@rangojs/router 0.0.0-experimental.20 → 0.0.0-experimental.204030a9
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 +4 -0
- package/README.md +242 -55
- package/dist/bin/rango.js +277 -99
- package/dist/vite/index.js +2929 -1132
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +68 -21
- package/skills/breadcrumbs/SKILL.md +252 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +243 -21
- package/skills/caching/SKILL.md +159 -10
- package/skills/composability/SKILL.md +27 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +262 -51
- package/skills/host-router/SKILL.md +243 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +46 -4
- package/skills/layout/SKILL.md +28 -7
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +291 -31
- package/skills/middleware/SKILL.md +49 -12
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +197 -6
- package/skills/prerender/SKILL.md +125 -102
- package/skills/rango/SKILL.md +242 -23
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +66 -9
- package/skills/route/SKILL.md +91 -8
- package/skills/router-setup/SKILL.md +98 -8
- package/skills/server-actions/SKILL.md +751 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/testing/SKILL.md +511 -188
- package/skills/typesafety/SKILL.md +354 -50
- package/skills/use-cache/SKILL.md +34 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +117 -0
- package/src/__internal.ts +92 -0
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +91 -70
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +183 -18
- package/src/browser/navigation-client.ts +187 -57
- package/src/browser/navigation-store.ts +75 -17
- package/src/browser/navigation-transaction.ts +21 -37
- package/src/browser/partial-update.ts +143 -40
- package/src/browser/prefetch/cache.ts +275 -28
- package/src/browser/prefetch/fetch.ts +191 -46
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +123 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +98 -14
- package/src/browser/react/NavigationProvider.tsx +110 -33
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +51 -7
- package/src/browser/react/index.ts +3 -0
- package/src/browser/react/location-state-shared.ts +175 -4
- package/src/browser/react/location-state.ts +39 -13
- package/src/browser/react/use-handle.ts +23 -64
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +20 -8
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +43 -10
- package/src/browser/react/use-segments.ts +11 -8
- package/src/browser/response-adapter.ts +25 -0
- package/src/browser/rsc-router.tsx +200 -75
- package/src/browser/scroll-restoration.ts +46 -39
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +31 -36
- package/src/browser/types.ts +81 -5
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/index.ts +2 -0
- package/src/build/route-trie.ts +69 -26
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +9 -2
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +278 -88
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +76 -49
- package/src/cache/cf/cf-cache-store.ts +501 -18
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.rsc.tsx +5 -1
- package/src/client.tsx +95 -284
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +36 -0
- package/src/errors.ts +30 -1
- package/src/handle.ts +65 -12
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/host/index.ts +2 -5
- package/src/host/router.ts +129 -57
- package/src/host/types.ts +31 -2
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +140 -20
- package/src/index.rsc.ts +15 -40
- package/src/index.ts +92 -76
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +2 -5
- package/src/loader.ts +3 -10
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +57 -15
- package/src/prerender.ts +141 -80
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -15
- package/src/route-content-wrapper.tsx +6 -28
- package/src/route-definition/dsl-helpers.ts +435 -260
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +110 -34
- package/src/route-definition/index.ts +3 -3
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +113 -1
- package/src/router/error-handling.ts +1 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +105 -39
- package/src/router/intercept-resolution.ts +15 -22
- package/src/router/lazy-includes.ts +12 -9
- package/src/router/loader-resolution.ts +175 -23
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +31 -16
- package/src/router/match-api.ts +129 -193
- package/src/router/match-handlers.ts +63 -20
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +136 -106
- package/src/router/match-middleware/cache-store.ts +54 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +124 -18
- package/src/router/metrics.ts +239 -14
- package/src/router/middleware-types.ts +61 -31
- package/src/router/middleware.ts +226 -124
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +118 -19
- package/src/router/prerender-match.ts +114 -10
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +286 -0
- package/src/router/revalidation.ts +85 -9
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +91 -29
- package/src/router/router-options.ts +89 -19
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +240 -23
- package/src/router/segment-resolution/helpers.ts +30 -25
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +483 -289
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry.ts +99 -0
- package/src/router/trie-matching.ts +38 -15
- package/src/router/types.ts +9 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +120 -32
- package/src/rsc/handler-context.ts +2 -2
- package/src/rsc/handler.ts +524 -370
- package/src/rsc/helpers.ts +91 -43
- package/src/rsc/index.ts +1 -21
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/origin-guard.ts +28 -10
- package/src/rsc/progressive-enhancement.ts +39 -10
- package/src/rsc/response-route-handler.ts +46 -53
- package/src/rsc/rsc-rendering.ts +69 -89
- package/src/rsc/runtime-warnings.ts +9 -10
- package/src/rsc/server-action.ts +39 -47
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/types.ts +19 -3
- package/src/search-params.ts +20 -17
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +219 -67
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +285 -63
- package/src/server/cookie-store.ts +28 -4
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +228 -65
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +9 -1
- package/src/static-handler.ts +19 -7
- package/src/testing/cache-status.ts +166 -0
- package/src/testing/collect-handle.ts +63 -0
- package/src/testing/dispatch.ts +440 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +154 -0
- package/src/testing/e2e/index.ts +149 -0
- package/src/testing/e2e/matchers.ts +51 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +306 -0
- package/src/testing/e2e/server.ts +183 -0
- package/src/testing/flight-matchers.ts +104 -0
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +22 -0
- package/src/testing/flight.ts +182 -0
- package/src/testing/generated-routes.ts +223 -0
- package/src/testing/index.ts +98 -0
- package/src/testing/internal/context.ts +151 -0
- package/src/testing/render-route.tsx +536 -0
- package/src/testing/run-loader.ts +296 -0
- package/src/testing/run-middleware.ts +170 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +112 -0
- package/src/theme/index.ts +4 -13
- package/src/types/cache-types.ts +4 -4
- package/src/types/global-namespace.ts +39 -26
- package/src/types/handler-context.ts +197 -79
- package/src/types/index.ts +1 -0
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-config.ts +17 -8
- package/src/types/route-entry.ts +19 -1
- package/src/types/segments.ts +37 -6
- package/src/urls/include-helper.ts +34 -67
- package/src/urls/index.ts +0 -3
- package/src/urls/path-helper-types.ts +50 -9
- package/src/urls/path-helper.ts +63 -63
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +26 -116
- package/src/urls/urls-function.ts +1 -5
- package/src/use-loader.tsx +487 -44
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +63 -91
- package/src/vite/discovery/discover-routers.ts +106 -53
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +222 -107
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +50 -13
- package/src/vite/discovery/virtual-module-codegen.ts +13 -23
- package/src/vite/index.ts +10 -3
- package/src/vite/plugin-types.ts +111 -72
- package/src/vite/plugins/cjs-to-esm.ts +8 -7
- package/src/vite/plugins/client-ref-dedup.ts +16 -0
- package/src/vite/plugins/client-ref-hashing.ts +28 -5
- 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/plugins/expose-action-id.ts +55 -33
- package/src/vite/plugins/expose-id-utils.ts +24 -8
- package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
- package/src/vite/plugins/expose-ids/handler-transform.ts +12 -35
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
- package/src/vite/plugins/expose-internal-ids.ts +544 -317
- package/src/vite/plugins/performance-tracks.ts +92 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +65 -50
- package/src/vite/plugins/version-injector.ts +39 -23
- package/src/vite/plugins/version-plugin.ts +72 -3
- package/src/vite/plugins/virtual-entries.ts +2 -2
- package/src/vite/rango.ts +265 -226
- package/src/vite/router-discovery.ts +924 -137
- package/src/vite/utils/ast-handler-extract.ts +15 -15
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +4 -2
- package/src/vite/utils/client-chunks.ts +190 -0
- package/src/vite/utils/forward-user-plugins.ts +193 -0
- package/src/vite/utils/manifest-utils.ts +21 -5
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +98 -5
- package/src/vite/utils/shared-utils.ts +109 -27
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/route-definition/route-function.ts +0 -119
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Snapshot
|
|
3
|
+
*
|
|
4
|
+
* Pure data type representing the fully-resolved state of a single route match.
|
|
5
|
+
* Consolidates the duplicated findMatch + loadManifest + collectRouteMiddleware +
|
|
6
|
+
* cacheScope derivation that previously lived separately in preview-match.ts
|
|
7
|
+
* and match-api.ts.
|
|
8
|
+
*
|
|
9
|
+
* resolveRoute() is the factory: given a pathname and dependencies, it returns
|
|
10
|
+
* a RouteSnapshot (or redirect/null). Consumers (createMatchContextForFull,
|
|
11
|
+
* createMatchContextForPartial, previewMatch) read snapshot fields instead of
|
|
12
|
+
* re-deriving them.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { CacheScope } from "../cache/cache-scope.js";
|
|
16
|
+
import { createCacheScope } from "../cache/cache-scope.js";
|
|
17
|
+
import type { EntryData, MetricsStore } from "../server/context.js";
|
|
18
|
+
import { loadManifest } from "./manifest.js";
|
|
19
|
+
import { collectRouteMiddleware } from "./middleware.js";
|
|
20
|
+
import type { CollectedMiddleware } from "./middleware-types.js";
|
|
21
|
+
import { traverseBack } from "./pattern-matching.js";
|
|
22
|
+
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Immutable snapshot of a resolved route match.
|
|
26
|
+
*
|
|
27
|
+
* Contains everything derivable from (pathname, findMatch, loadManifest)
|
|
28
|
+
* without request context, navigation state, or intercept logic.
|
|
29
|
+
*/
|
|
30
|
+
export interface RouteSnapshot<TEnv = any> {
|
|
31
|
+
/** Raw match result from the trie/pattern matcher */
|
|
32
|
+
matched: RouteMatchResult<TEnv>;
|
|
33
|
+
/** Resolved manifest entry (with loaded handler, loader, etc.) */
|
|
34
|
+
manifestEntry: EntryData;
|
|
35
|
+
/** All entries in the route chain (from traverseBack) */
|
|
36
|
+
entries: EntryData[];
|
|
37
|
+
/** Canonical route key (e.g. "blog.detail") */
|
|
38
|
+
routeKey: string;
|
|
39
|
+
/** Last segment of a dotted route key (e.g. "detail" from "blog.detail") */
|
|
40
|
+
localRouteName: string;
|
|
41
|
+
/** Extracted route params */
|
|
42
|
+
params: Record<string, string>;
|
|
43
|
+
/** Collected route-level middleware from the entry tree */
|
|
44
|
+
routeMiddleware: CollectedMiddleware[];
|
|
45
|
+
/** Merged cache scope from the entry chain */
|
|
46
|
+
cacheScope: CacheScope | null;
|
|
47
|
+
/** Whether the matched route is a passthrough route */
|
|
48
|
+
isPassthrough: boolean;
|
|
49
|
+
/** Response type for non-RSC routes (e.g. "application/json") */
|
|
50
|
+
responseType?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type ResolveRouteResult<TEnv = any> =
|
|
54
|
+
| { type: "match"; snapshot: RouteSnapshot<TEnv> }
|
|
55
|
+
| { type: "redirect"; redirectTo: string }
|
|
56
|
+
| null;
|
|
57
|
+
|
|
58
|
+
export interface ResolveRouteDeps<TEnv = any> {
|
|
59
|
+
findMatch: (pathname: string) => RouteMatchResult<TEnv> | null;
|
|
60
|
+
metricsStore?: MetricsStore;
|
|
61
|
+
isSSR?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* When true, skip entries array and cacheScope chain construction.
|
|
64
|
+
* Used by previewMatch which only needs matched, manifestEntry,
|
|
65
|
+
* routeMiddleware, and responseType — avoids an extra traverseBack
|
|
66
|
+
* allocation and cacheScope composition on the hot classification path.
|
|
67
|
+
*/
|
|
68
|
+
lite?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* When true, skip pushing the "route-matching" metric internally.
|
|
71
|
+
* Used by createMatchContextForPartial on the fresh path (no snapshot
|
|
72
|
+
* reuse) so it can measure current + prev + intercept-source findMatch
|
|
73
|
+
* calls under one combined "route-matching" metric. On the reuse path,
|
|
74
|
+
* the partial path emits "route-matching:nav" for the prev +
|
|
75
|
+
* intercept-source lookups only (current-route resolution was done
|
|
76
|
+
* during classification without metrics).
|
|
77
|
+
*/
|
|
78
|
+
skipRouteMatchMetric?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a pathname into a RouteSnapshot.
|
|
83
|
+
*
|
|
84
|
+
* This is the single source of truth for route derivation. It performs:
|
|
85
|
+
* 1. findMatch(pathname)
|
|
86
|
+
* 2. Redirect check
|
|
87
|
+
* 3. loadManifest
|
|
88
|
+
* 4. Passthrough detection
|
|
89
|
+
* 5. collectRouteMiddleware
|
|
90
|
+
* 6. Cache scope chain
|
|
91
|
+
* 7. responseType + localRouteName extraction
|
|
92
|
+
*
|
|
93
|
+
* Metrics timing is preserved identically to the previous inline code.
|
|
94
|
+
*/
|
|
95
|
+
export async function resolveRoute<TEnv = any>(
|
|
96
|
+
pathname: string,
|
|
97
|
+
deps: ResolveRouteDeps<TEnv>,
|
|
98
|
+
): Promise<ResolveRouteResult<TEnv>> {
|
|
99
|
+
const {
|
|
100
|
+
metricsStore,
|
|
101
|
+
isSSR = false,
|
|
102
|
+
lite = false,
|
|
103
|
+
skipRouteMatchMetric = false,
|
|
104
|
+
} = deps;
|
|
105
|
+
|
|
106
|
+
const routeMatchStart =
|
|
107
|
+
metricsStore && !skipRouteMatchMetric ? performance.now() : 0;
|
|
108
|
+
const matched = deps.findMatch(pathname);
|
|
109
|
+
if (metricsStore && !skipRouteMatchMetric) {
|
|
110
|
+
metricsStore.metrics.push({
|
|
111
|
+
label: "route-matching",
|
|
112
|
+
duration: performance.now() - routeMatchStart,
|
|
113
|
+
startTime: routeMatchStart - metricsStore.requestStart,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!matched) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (matched.redirectTo) {
|
|
122
|
+
return { type: "redirect", redirectTo: matched.redirectTo };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const manifestStart = metricsStore ? performance.now() : 0;
|
|
126
|
+
const manifestEntry = await loadManifest(
|
|
127
|
+
matched.entry,
|
|
128
|
+
matched.routeKey,
|
|
129
|
+
pathname,
|
|
130
|
+
metricsStore,
|
|
131
|
+
isSSR,
|
|
132
|
+
);
|
|
133
|
+
if (metricsStore) {
|
|
134
|
+
metricsStore.metrics.push({
|
|
135
|
+
label: "manifest-loading",
|
|
136
|
+
duration: performance.now() - manifestStart,
|
|
137
|
+
startTime: manifestStart - metricsStore.requestStart,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const isPassthrough =
|
|
142
|
+
manifestEntry.type === "route" && manifestEntry.isPassthrough === true;
|
|
143
|
+
|
|
144
|
+
let entries: EntryData[];
|
|
145
|
+
let cacheScope: CacheScope | null = null;
|
|
146
|
+
if (lite) {
|
|
147
|
+
entries = [];
|
|
148
|
+
} else {
|
|
149
|
+
({ entries, cacheScope } = buildEntriesAndCacheScope(manifestEntry));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const routeMiddleware = collectRouteMiddleware(
|
|
153
|
+
lite ? traverseBack(manifestEntry) : entries,
|
|
154
|
+
matched.params,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const responseType =
|
|
158
|
+
matched.responseType ||
|
|
159
|
+
(manifestEntry.type === "route" ? manifestEntry.responseType : undefined);
|
|
160
|
+
|
|
161
|
+
const localRouteName = matched.routeKey.includes(".")
|
|
162
|
+
? matched.routeKey.split(".").pop()!
|
|
163
|
+
: matched.routeKey;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
type: "match",
|
|
167
|
+
snapshot: {
|
|
168
|
+
matched,
|
|
169
|
+
manifestEntry,
|
|
170
|
+
entries,
|
|
171
|
+
routeKey: matched.routeKey,
|
|
172
|
+
localRouteName,
|
|
173
|
+
params: matched.params,
|
|
174
|
+
routeMiddleware,
|
|
175
|
+
cacheScope,
|
|
176
|
+
isPassthrough,
|
|
177
|
+
responseType,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Fill in the entries and cacheScope fields on a lite snapshot.
|
|
184
|
+
*
|
|
185
|
+
* When classifyRequest produces a lite snapshot (entries=[], cacheScope=null),
|
|
186
|
+
* this function computes the missing fields from manifestEntry without
|
|
187
|
+
* re-running findMatch, loadManifest, or collectRouteMiddleware.
|
|
188
|
+
*
|
|
189
|
+
* If the snapshot already has entries, returns it as-is.
|
|
190
|
+
*/
|
|
191
|
+
export function ensureFullRouteSnapshot<TEnv = any>(
|
|
192
|
+
snapshot: RouteSnapshot<TEnv>,
|
|
193
|
+
): RouteSnapshot<TEnv> {
|
|
194
|
+
if (snapshot.entries.length > 0) {
|
|
195
|
+
return snapshot;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const { entries, cacheScope } = buildEntriesAndCacheScope(
|
|
199
|
+
snapshot.manifestEntry,
|
|
200
|
+
);
|
|
201
|
+
return { ...snapshot, entries, cacheScope };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Materialize the entry chain and derive the merged cache scope.
|
|
206
|
+
* Shared by resolveRoute (non-lite) and ensureFullRouteSnapshot.
|
|
207
|
+
*/
|
|
208
|
+
function buildEntriesAndCacheScope(manifestEntry: EntryData): {
|
|
209
|
+
entries: EntryData[];
|
|
210
|
+
cacheScope: CacheScope | null;
|
|
211
|
+
} {
|
|
212
|
+
const entries = [...traverseBack(manifestEntry)];
|
|
213
|
+
let cacheScope: CacheScope | null = null;
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
if (entry.cache) {
|
|
216
|
+
cacheScope = createCacheScope(entry.cache, cacheScope);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return { entries, cacheScope };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Test helper: create a RouteSnapshot with sensible defaults and overrides.
|
|
224
|
+
*/
|
|
225
|
+
export function createRouteSnapshot<TEnv = any>(
|
|
226
|
+
overrides?: Partial<RouteSnapshot<TEnv>>,
|
|
227
|
+
): RouteSnapshot<TEnv> {
|
|
228
|
+
return {
|
|
229
|
+
matched: {
|
|
230
|
+
entry: {} as any,
|
|
231
|
+
routeKey: "test",
|
|
232
|
+
params: {},
|
|
233
|
+
optionalParams: new Set(),
|
|
234
|
+
} as RouteMatchResult<TEnv>,
|
|
235
|
+
manifestEntry: { type: "route", shortCode: "R0", parent: null } as any,
|
|
236
|
+
entries: [],
|
|
237
|
+
routeKey: "test",
|
|
238
|
+
localRouteName: "test",
|
|
239
|
+
params: {},
|
|
240
|
+
routeMiddleware: [],
|
|
241
|
+
cacheScope: null,
|
|
242
|
+
isPassthrough: false,
|
|
243
|
+
...overrides,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
@@ -138,6 +138,7 @@ export interface RouterContext<TEnv = any> {
|
|
|
138
138
|
interceptResult: InterceptResult | null,
|
|
139
139
|
localRouteName: string,
|
|
140
140
|
pathname: string,
|
|
141
|
+
stale?: boolean,
|
|
141
142
|
) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
|
|
142
143
|
|
|
143
144
|
// Generator-based segment resolution (for pipeline)
|
|
@@ -188,7 +189,10 @@ export interface RouterContext<TEnv = any> {
|
|
|
188
189
|
| "cache-hit"
|
|
189
190
|
| "loader"
|
|
190
191
|
| "parallel"
|
|
191
|
-
| "orphan-layout"
|
|
192
|
+
| "orphan-layout"
|
|
193
|
+
| "route-handler"
|
|
194
|
+
| "layout-handler"
|
|
195
|
+
| "intercept-loader";
|
|
192
196
|
}) => Promise<boolean>;
|
|
193
197
|
|
|
194
198
|
// Request context
|
|
@@ -206,6 +210,7 @@ export interface RouterContext<TEnv = any> {
|
|
|
206
210
|
params: Record<string, string>,
|
|
207
211
|
handlerContext: HandlerContext<any, TEnv>,
|
|
208
212
|
loaderPromises: Map<string, Promise<any>>,
|
|
213
|
+
options?: { skipLoaders?: boolean },
|
|
209
214
|
) => Promise<ResolvedSegment[]>;
|
|
210
215
|
|
|
211
216
|
// Generator-based simple resolution
|
|
@@ -2,6 +2,7 @@ import type { ComponentType, ReactNode } from "react";
|
|
|
2
2
|
import type { SerializedManifest } from "../debug.js";
|
|
3
3
|
import type { ReverseFunction } from "../reverse.js";
|
|
4
4
|
import type { UrlPatterns } from "../urls.js";
|
|
5
|
+
import type { UrlBuilder, EnvCompatible } from "../urls/pattern-types.js";
|
|
5
6
|
import type { EntryData } from "../server/context";
|
|
6
7
|
import type { ErrorInfo, MatchResult } from "../types";
|
|
7
8
|
import type { NonceProvider } from "../rsc/types.js";
|
|
@@ -12,7 +13,7 @@ import type {
|
|
|
12
13
|
} from "../cache/types.js";
|
|
13
14
|
import type { MiddlewareEntry, MiddlewareFn } from "./middleware.js";
|
|
14
15
|
import { RSC_ROUTER_BRAND } from "./router-registry.js";
|
|
15
|
-
import type {
|
|
16
|
+
import type { RangoOptions, RootLayoutProps } from "./router-options.js";
|
|
16
17
|
import type { DefaultVars } from "../types/global-namespace.js";
|
|
17
18
|
import type { ResolvedTimeouts, OnTimeoutCallback } from "./timeout.js";
|
|
18
19
|
|
|
@@ -48,16 +49,16 @@ type MergeRoutesWithResponses<
|
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
|
-
* Public
|
|
52
|
+
* Public Rango router interface — the user-facing API surface.
|
|
52
53
|
*
|
|
53
54
|
* Users interact with this type when building and using routers.
|
|
54
|
-
* Internal framework code uses
|
|
55
|
+
* Internal framework code uses RangoInternal (via toInternal()) to access
|
|
55
56
|
* matching, build-time, and configuration members that are not part of the
|
|
56
57
|
* public contract.
|
|
57
58
|
*
|
|
58
59
|
* TRoutes accumulates all registered route types through the builder chain.
|
|
59
60
|
*/
|
|
60
|
-
export interface
|
|
61
|
+
export interface Rango<
|
|
61
62
|
TEnv = any,
|
|
62
63
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
63
64
|
> {
|
|
@@ -68,23 +69,36 @@ export interface RSCRouter<
|
|
|
68
69
|
readonly id: string;
|
|
69
70
|
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
+
* URL prefix applied to all routes. Undefined when no basename is configured.
|
|
73
|
+
*/
|
|
74
|
+
readonly basename: string | undefined;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Register routes using URL patterns from urls() or a builder function
|
|
72
78
|
*
|
|
73
79
|
* @example
|
|
74
80
|
* ```typescript
|
|
75
|
-
*
|
|
76
|
-
*
|
|
81
|
+
* // With urls()
|
|
82
|
+
* createRouter({}).routes(urlpatterns)
|
|
83
|
+
*
|
|
84
|
+
* // With builder function (urls() is implicit)
|
|
85
|
+
* createRouter({}).routes(({ path, layout }) => [
|
|
86
|
+
* layout(RootLayout, () => [
|
|
87
|
+
* path("/", HomePage),
|
|
88
|
+
* ]),
|
|
89
|
+
* ])
|
|
77
90
|
* ```
|
|
78
91
|
*/
|
|
79
|
-
routes<T extends UrlPatterns<
|
|
80
|
-
patterns: T,
|
|
81
|
-
):
|
|
92
|
+
routes<T extends UrlPatterns<any, any, any>>(
|
|
93
|
+
patterns: T & EnvCompatible<T, TEnv>,
|
|
94
|
+
): Rango<
|
|
82
95
|
TEnv,
|
|
83
96
|
TRoutes &
|
|
84
97
|
(NonNullable<T["_routes"]> extends Record<string, unknown>
|
|
85
98
|
? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
|
|
86
99
|
: Record<string, string>)
|
|
87
100
|
>;
|
|
101
|
+
routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
|
|
88
102
|
|
|
89
103
|
/**
|
|
90
104
|
* Add global middleware that runs on all routes
|
|
@@ -100,7 +114,7 @@ export interface RSCRouter<
|
|
|
100
114
|
use(
|
|
101
115
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
102
116
|
middleware?: MiddlewareFn<TEnv>,
|
|
103
|
-
):
|
|
117
|
+
): Rango<TEnv, TRoutes>;
|
|
104
118
|
|
|
105
119
|
/**
|
|
106
120
|
* Type-safe URL builder for registered routes
|
|
@@ -127,7 +141,7 @@ export interface RSCRouter<
|
|
|
127
141
|
* type AppRoutes = typeof _router.routeMap;
|
|
128
142
|
*
|
|
129
143
|
* declare global {
|
|
130
|
-
* namespace
|
|
144
|
+
* namespace Rango {
|
|
131
145
|
* interface RegisteredRoutes extends AppRoutes {}
|
|
132
146
|
* }
|
|
133
147
|
* }
|
|
@@ -163,16 +177,16 @@ export interface RSCRouter<
|
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
/**
|
|
166
|
-
* Internal
|
|
180
|
+
* Internal Rango router interface — the full framework-facing API.
|
|
167
181
|
*
|
|
168
182
|
* This type includes all members used by the Vite plugin, RSC handler,
|
|
169
183
|
* pre-rendering pipeline, and other framework internals. It is NOT exported
|
|
170
184
|
* from the public package API.
|
|
171
185
|
*
|
|
172
|
-
* Use toInternal(router) to assert a public
|
|
186
|
+
* Use toInternal(router) to assert a public Rango into this type
|
|
173
187
|
* at the boundary where framework code receives a user-provided router.
|
|
174
188
|
*/
|
|
175
|
-
export interface
|
|
189
|
+
export interface RangoInternal<
|
|
176
190
|
TEnv = any,
|
|
177
191
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
178
192
|
> {
|
|
@@ -188,18 +202,28 @@ export interface RSCRouterInternal<
|
|
|
188
202
|
*/
|
|
189
203
|
readonly id: string;
|
|
190
204
|
|
|
205
|
+
/** URL prefix applied to all routes. */
|
|
206
|
+
readonly basename: string | undefined;
|
|
207
|
+
|
|
191
208
|
/**
|
|
192
|
-
* Register routes using URL patterns from urls()
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
209
|
+
* Register routes using URL patterns from urls() or a builder function.
|
|
210
|
+
*
|
|
211
|
+
* Env compatibility is checked by EnvCompatible: an env-agnostic urls() block
|
|
212
|
+
* (its env is `unknown` — e.g. a shared module, or an app that does not augment
|
|
213
|
+
* `Rango.Env`) attaches to any router, while a urls<TEnv>() block carrying a
|
|
214
|
+
* concrete env is accepted only when this router's `TEnv` satisfies it. So a
|
|
215
|
+
* `urls<{ DB }>()` cannot be mounted on a `createRouter<{}>()`.
|
|
216
|
+
*/
|
|
217
|
+
routes<T extends UrlPatterns<any, any, any>>(
|
|
218
|
+
patterns: T & EnvCompatible<T, TEnv>,
|
|
219
|
+
): Rango<
|
|
197
220
|
TEnv,
|
|
198
221
|
TRoutes &
|
|
199
222
|
(NonNullable<T["_routes"]> extends Record<string, unknown>
|
|
200
223
|
? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
|
|
201
224
|
: Record<string, string>)
|
|
202
225
|
>;
|
|
226
|
+
routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
|
|
203
227
|
|
|
204
228
|
/**
|
|
205
229
|
* Add global middleware that runs on all routes
|
|
@@ -207,7 +231,7 @@ export interface RSCRouterInternal<
|
|
|
207
231
|
use(
|
|
208
232
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
209
233
|
middleware?: MiddlewareFn<TEnv>,
|
|
210
|
-
):
|
|
234
|
+
): Rango<TEnv, TRoutes>;
|
|
211
235
|
|
|
212
236
|
/**
|
|
213
237
|
* Type-safe URL builder for registered routes
|
|
@@ -229,17 +253,17 @@ export interface RSCRouterInternal<
|
|
|
229
253
|
* Error callback for monitoring/alerting
|
|
230
254
|
* Called when errors occur in loaders, actions, or routes
|
|
231
255
|
*/
|
|
232
|
-
readonly onError?:
|
|
256
|
+
readonly onError?: RangoOptions<TEnv>["onError"];
|
|
233
257
|
|
|
234
258
|
/**
|
|
235
259
|
* Cache configuration
|
|
236
260
|
*/
|
|
237
|
-
readonly cache?:
|
|
261
|
+
readonly cache?: RangoOptions<TEnv>["cache"];
|
|
238
262
|
|
|
239
263
|
/**
|
|
240
264
|
* Not found component to render when no route matches
|
|
241
265
|
*/
|
|
242
|
-
readonly notFound?:
|
|
266
|
+
readonly notFound?: RangoOptions<TEnv>["notFound"];
|
|
243
267
|
|
|
244
268
|
/**
|
|
245
269
|
* Resolved theme configuration (null if theme not enabled)
|
|
@@ -258,10 +282,17 @@ export interface RSCRouterInternal<
|
|
|
258
282
|
|
|
259
283
|
/**
|
|
260
284
|
* Cache-Control header value for prefetch responses.
|
|
261
|
-
* False means no
|
|
285
|
+
* False means no caching of prefetch responses.
|
|
286
|
+
* Derived from prefetchCacheTTL.
|
|
262
287
|
*/
|
|
263
288
|
readonly prefetchCacheControl: string | false;
|
|
264
289
|
|
|
290
|
+
/**
|
|
291
|
+
* TTL in milliseconds for the client-side in-memory prefetch cache.
|
|
292
|
+
* 0 means caching is disabled.
|
|
293
|
+
*/
|
|
294
|
+
readonly prefetchCacheTTL: number;
|
|
295
|
+
|
|
265
296
|
/**
|
|
266
297
|
* Whether connection warmup is enabled.
|
|
267
298
|
* When true, the client sends HEAD /?_rsc_warmup after idle periods
|
|
@@ -269,6 +300,12 @@ export interface RSCRouterInternal<
|
|
|
269
300
|
*/
|
|
270
301
|
readonly warmupEnabled: boolean;
|
|
271
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Whether router-wide performance debugging is enabled.
|
|
305
|
+
* Used by the request handler to create metrics before middleware runs.
|
|
306
|
+
*/
|
|
307
|
+
readonly debugPerformance?: boolean;
|
|
308
|
+
|
|
272
309
|
/**
|
|
273
310
|
* Whether ?__debug_manifest is allowed in production.
|
|
274
311
|
* Always enabled in development.
|
|
@@ -325,6 +362,20 @@ export interface RSCRouterInternal<
|
|
|
325
362
|
*/
|
|
326
363
|
readonly __sourceFile?: string;
|
|
327
364
|
|
|
365
|
+
/** @internal basename for runtime manifest generation */
|
|
366
|
+
readonly __basename?: string;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @internal Router-level error/notFound fallbacks (`createRouter` options),
|
|
370
|
+
* exposed for the build-time clientChunks discovery so a `"use client"`
|
|
371
|
+
* default boundary is routed into the dedicated `app-fallback` chunk. Unlike
|
|
372
|
+
* the route-tree `errorBoundary()`/`notFoundBoundary()` helpers these never
|
|
373
|
+
* land in `EntryData`, so they are read directly off the router instance.
|
|
374
|
+
*/
|
|
375
|
+
readonly __defaultErrorBoundary?: RangoOptions<TEnv>["defaultErrorBoundary"];
|
|
376
|
+
readonly __defaultNotFoundBoundary?: RangoOptions<TEnv>["defaultNotFoundBoundary"];
|
|
377
|
+
readonly __notFound?: RangoOptions<TEnv>["notFound"];
|
|
378
|
+
|
|
328
379
|
match(
|
|
329
380
|
request: Request,
|
|
330
381
|
input?: RouterRequestInput<TEnv>,
|
|
@@ -340,6 +391,8 @@ export interface RSCRouterInternal<
|
|
|
340
391
|
params: Record<string, string>,
|
|
341
392
|
buildVars?: Record<string, any>,
|
|
342
393
|
isPassthroughRoute?: boolean,
|
|
394
|
+
buildEnv?: any,
|
|
395
|
+
devMode?: boolean,
|
|
343
396
|
): Promise<{
|
|
344
397
|
segments: SerializedSegmentData[];
|
|
345
398
|
handles: Record<string, SegmentHandleData>;
|
|
@@ -358,6 +411,8 @@ export interface RSCRouterInternal<
|
|
|
358
411
|
handler: Function,
|
|
359
412
|
handlerId: string,
|
|
360
413
|
routeName?: string,
|
|
414
|
+
buildEnv?: any,
|
|
415
|
+
devMode?: boolean,
|
|
361
416
|
): Promise<{ encoded: string; handles: Record<string, unknown[]> } | null>;
|
|
362
417
|
|
|
363
418
|
/**
|
|
@@ -411,6 +466,13 @@ export interface RSCRouterInternal<
|
|
|
411
466
|
segmentType?: ErrorInfo["segmentType"],
|
|
412
467
|
): Promise<MatchResult | null>;
|
|
413
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Low-level route matching function.
|
|
471
|
+
* Used by classifyRequest() for request classification without
|
|
472
|
+
* entering the full match pipeline.
|
|
473
|
+
*/
|
|
474
|
+
findMatch(pathname: string, metricsStore?: any): any;
|
|
475
|
+
|
|
414
476
|
/**
|
|
415
477
|
* Debug utility to serialize the manifest for inspection
|
|
416
478
|
* Returns a JSON-friendly representation of all routes and layouts
|
|
@@ -424,16 +486,16 @@ export interface RSCRouterInternal<
|
|
|
424
486
|
}
|
|
425
487
|
|
|
426
488
|
/**
|
|
427
|
-
* Assert a public
|
|
489
|
+
* Assert a public Rango into the internal type.
|
|
428
490
|
*
|
|
429
491
|
* Use this at the boundary where framework code receives a user-provided
|
|
430
492
|
* router and needs access to internal members (match, config, build-time).
|
|
431
493
|
* The cast is safe because createRouter() always produces an object that
|
|
432
|
-
* satisfies
|
|
494
|
+
* satisfies RangoInternal; the public type is just a narrower view.
|
|
433
495
|
*/
|
|
434
496
|
export function toInternal<
|
|
435
497
|
TEnv = any,
|
|
436
498
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
437
|
-
>(router:
|
|
438
|
-
return router as
|
|
499
|
+
>(router: Rango<TEnv, TRoutes>): RangoInternal<TEnv, TRoutes> {
|
|
500
|
+
return router as RangoInternal<TEnv, TRoutes>;
|
|
439
501
|
}
|