@rangojs/router 0.0.0-experimental.fa8a383a → 0.0.0-experimental.fb4fdc18
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/README.md +188 -35
- package/dist/bin/rango.js +130 -47
- package/dist/vite/index.js +1884 -537
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +7 -5
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +8 -0
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +33 -20
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +20 -0
- package/skills/layout/SKILL.md +22 -0
- package/skills/links/SKILL.md +93 -17
- package/skills/loader/SKILL.md +123 -46
- package/skills/middleware/SKILL.md +36 -3
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/parallel/SKILL.md +133 -0
- package/skills/prerender/SKILL.md +110 -68
- package/skills/rango/SKILL.md +26 -22
- package/skills/response-routes/SKILL.md +8 -0
- package/skills/route/SKILL.md +75 -0
- package/skills/router-setup/SKILL.md +87 -2
- package/skills/server-actions/SKILL.md +739 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +19 -1
- package/src/__internal.ts +1 -1
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +44 -4
- package/src/browser/navigation-bridge.ts +95 -7
- package/src/browser/navigation-client.ts +128 -53
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/partial-update.ts +93 -12
- package/src/browser/prefetch/cache.ts +129 -21
- package/src/browser/prefetch/fetch.ts +156 -18
- package/src/browser/prefetch/queue.ts +92 -29
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +72 -8
- package/src/browser/react/NavigationProvider.tsx +82 -21
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +51 -7
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +17 -4
- package/src/browser/react/use-router.ts +29 -9
- package/src/browser/react/use-segments.ts +11 -8
- package/src/browser/rsc-router.tsx +60 -9
- package/src/browser/scroll-restoration.ts +10 -8
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/browser/server-action-bridge.ts +8 -6
- package/src/browser/types.ts +46 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/route-trie.ts +52 -25
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +211 -72
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +46 -5
- package/src/cache/cf/cf-cache-store.ts +5 -7
- package/src/cache/taint.ts +55 -0
- package/src/client.tsx +84 -230
- package/src/context-var.ts +72 -2
- package/src/handle.ts +40 -0
- package/src/index.rsc.ts +6 -1
- package/src/index.ts +49 -6
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +138 -77
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +28 -2
- package/src/route-definition/dsl-helpers.ts +210 -35
- package/src/route-definition/helpers-types.ts +73 -20
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +9 -1
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/handler-context.ts +102 -25
- package/src/router/intercept-resolution.ts +9 -4
- package/src/router/lazy-includes.ts +6 -6
- package/src/router/loader-resolution.ts +159 -21
- package/src/router/manifest.ts +22 -13
- package/src/router/match-api.ts +128 -192
- package/src/router/match-handlers.ts +1 -0
- package/src/router/match-middleware/background-revalidation.ts +12 -1
- package/src/router/match-middleware/cache-lookup.ts +74 -14
- package/src/router/match-middleware/cache-store.ts +21 -4
- package/src/router/match-middleware/segment-resolution.ts +53 -0
- package/src/router/match-result.ts +112 -9
- package/src/router/metrics.ts +6 -1
- package/src/router/middleware-types.ts +20 -33
- package/src/router/middleware.ts +56 -12
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +101 -17
- package/src/router/prerender-match.ts +110 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +15 -1
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +114 -18
- package/src/router/segment-resolution/helpers.ts +29 -24
- package/src/router/segment-resolution/revalidation.ts +257 -127
- package/src/router/trie-matching.ts +18 -13
- package/src/router/types.ts +1 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +55 -7
- package/src/rsc/handler.ts +478 -383
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +18 -2
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +20 -1
- package/src/rsc/server-action.ts +12 -0
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +15 -1
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +22 -62
- package/src/server/context.ts +76 -4
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +185 -57
- package/src/ssr/index.tsx +8 -1
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +145 -68
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +12 -1
- package/src/types/segments.ts +18 -1
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +47 -12
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +18 -16
- package/src/use-loader.tsx +77 -5
- package/src/vite/debug.ts +184 -0
- package/src/vite/discovery/bundle-postprocess.ts +30 -33
- package/src/vite/discovery/discover-routers.ts +36 -4
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +175 -74
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +13 -4
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +60 -5
- package/src/vite/plugins/cjs-to-esm.ts +5 -0
- package/src/vite/plugins/client-ref-dedup.ts +16 -0
- package/src/vite/plugins/client-ref-hashing.ts +16 -4
- 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 +52 -28
- package/src/vite/plugins/expose-id-utils.ts +12 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +30 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
- package/src/vite/plugins/expose-internal-ids.ts +563 -316
- package/src/vite/plugins/performance-tracks.ts +96 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/use-cache-transform.ts +56 -43
- package/src/vite/plugins/version-injector.ts +37 -11
- package/src/vite/rango.ts +63 -11
- package/src/vite/router-discovery.ts +732 -86
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +38 -5
- package/src/vite/utils/shared-utils.ts +3 -2
package/src/router/types.ts
CHANGED
|
@@ -96,6 +96,7 @@ export interface SegmentResolutionDeps<TEnv = any> {
|
|
|
96
96
|
findNearestNotFoundBoundary: (
|
|
97
97
|
entry: EntryData | null,
|
|
98
98
|
) => ReactNode | NotFoundBoundaryHandler | null;
|
|
99
|
+
notFoundComponent?: ReactNode | ((props: { pathname: string }) => ReactNode);
|
|
99
100
|
callOnError: (error: unknown, phase: ErrorPhase, context: any) => void;
|
|
100
101
|
}
|
|
101
102
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL param encode/decode at the route boundary.
|
|
3
|
+
*
|
|
4
|
+
* Extraction (decode): regex/trie matchers keep param values URL-encoded;
|
|
5
|
+
* `safeDecodeURIComponent` turns them back into raw strings so `ctx.params`
|
|
6
|
+
* matches the contract apps expect (Express/React Router/Fastify/Koa) and
|
|
7
|
+
* round-trips through reverse stay stable. Malformed %-encoding is
|
|
8
|
+
* preserved as-is so a broken URL doesn't crash matching.
|
|
9
|
+
*
|
|
10
|
+
* Reversal (encode): `encodePathSegment` escapes only what RFC 3986
|
|
11
|
+
* requires for a path segment — `/`, `?`, `#`, space, control chars,
|
|
12
|
+
* non-ASCII — and leaves pchar sub-delims (`@ : $ & + , ; =` and friends)
|
|
13
|
+
* readable. `encodeURIComponent` over-encodes for path segments, which
|
|
14
|
+
* makes generated URLs harder for humans to read in the address bar
|
|
15
|
+
* (e.g. mailbox IDs like `ivo@example.com` would become
|
|
16
|
+
* `ivo%40example.com` even though `@` is path-legal).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export function safeDecodeURIComponent(raw: string): string {
|
|
20
|
+
if (raw === "" || raw.indexOf("%") === -1) return raw;
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return raw;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// encodeURIComponent over-encodes for path segments. After running it,
|
|
29
|
+
// un-encode the pchar sub-delims + (`:` / `@`) so the resulting URL
|
|
30
|
+
// keeps human-readable characters that are legal in a path segment.
|
|
31
|
+
// Everything dangerous — `/ ? # %` and space/control/non-ASCII — stays
|
|
32
|
+
// encoded.
|
|
33
|
+
const PATH_SAFE_ESCAPES: Record<string, string> = {
|
|
34
|
+
"%3A": ":",
|
|
35
|
+
"%40": "@",
|
|
36
|
+
"%24": "$",
|
|
37
|
+
"%26": "&",
|
|
38
|
+
"%2B": "+",
|
|
39
|
+
"%2C": ",",
|
|
40
|
+
"%3B": ";",
|
|
41
|
+
"%3D": "=",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function encodePathSegment(value: string): string {
|
|
45
|
+
return encodeURIComponent(value).replace(
|
|
46
|
+
/%(?:3A|40|24|26|2B|2C|3B|3D)/gi,
|
|
47
|
+
(match) => PATH_SAFE_ESCAPES[match.toUpperCase()] ?? match,
|
|
48
|
+
);
|
|
49
|
+
}
|
package/src/router.ts
CHANGED
|
@@ -19,9 +19,10 @@ import {
|
|
|
19
19
|
import MapRootLayout from "./server/root-layout.js";
|
|
20
20
|
import type { AllUseItems } from "./route-types.js";
|
|
21
21
|
import type { UrlPatterns } from "./urls.js";
|
|
22
|
+
import type { UrlBuilder } from "./urls/pattern-types.js";
|
|
23
|
+
import { urls } from "./urls.js";
|
|
22
24
|
import {
|
|
23
|
-
EntryData,
|
|
24
|
-
InterceptSelectorContext,
|
|
25
|
+
type EntryData,
|
|
25
26
|
getContext,
|
|
26
27
|
RSCRouterContext,
|
|
27
28
|
type MetricsStore,
|
|
@@ -133,6 +134,7 @@ export function createRouter<TEnv = any>(
|
|
|
133
134
|
const {
|
|
134
135
|
id: userProvidedId,
|
|
135
136
|
$$id: injectedId,
|
|
137
|
+
basename: basenameOption,
|
|
136
138
|
debugPerformance = false,
|
|
137
139
|
document: documentOption,
|
|
138
140
|
defaultErrorBoundary,
|
|
@@ -158,6 +160,13 @@ export function createRouter<TEnv = any>(
|
|
|
158
160
|
originCheck: originCheckOption,
|
|
159
161
|
} = options;
|
|
160
162
|
|
|
163
|
+
// Normalize basename: ensure leading slash, strip trailing slash.
|
|
164
|
+
// A bare "/" is equivalent to no basename.
|
|
165
|
+
const basename =
|
|
166
|
+
basenameOption && basenameOption.replace(/^\/+|\/+$/g, "")
|
|
167
|
+
? "/" + basenameOption.replace(/^\/+|\/+$/g, "")
|
|
168
|
+
: undefined;
|
|
169
|
+
|
|
161
170
|
// Resolve telemetry sink (no-op when not configured)
|
|
162
171
|
const telemetry = resolveSink(telemetrySink);
|
|
163
172
|
|
|
@@ -526,6 +535,7 @@ export function createRouter<TEnv = any>(
|
|
|
526
535
|
trackHandler,
|
|
527
536
|
findNearestErrorBoundary,
|
|
528
537
|
findNearestNotFoundBoundary,
|
|
538
|
+
notFoundComponent: notFound,
|
|
529
539
|
callOnError,
|
|
530
540
|
};
|
|
531
541
|
|
|
@@ -614,6 +624,8 @@ export function createRouter<TEnv = any>(
|
|
|
614
624
|
params: Record<string, string>,
|
|
615
625
|
buildVars?: Record<string, any>,
|
|
616
626
|
isPassthroughRoute?: boolean,
|
|
627
|
+
buildEnv?: TEnv,
|
|
628
|
+
devMode?: boolean,
|
|
617
629
|
) {
|
|
618
630
|
return _matchForPrerender(
|
|
619
631
|
pathname,
|
|
@@ -621,6 +633,8 @@ export function createRouter<TEnv = any>(
|
|
|
621
633
|
prerenderDeps,
|
|
622
634
|
buildVars,
|
|
623
635
|
isPassthroughRoute,
|
|
636
|
+
buildEnv,
|
|
637
|
+
devMode,
|
|
624
638
|
);
|
|
625
639
|
}
|
|
626
640
|
|
|
@@ -628,12 +642,16 @@ export function createRouter<TEnv = any>(
|
|
|
628
642
|
handler: Function,
|
|
629
643
|
handlerId: string,
|
|
630
644
|
routeName?: string,
|
|
645
|
+
buildEnv?: TEnv,
|
|
646
|
+
devMode?: boolean,
|
|
631
647
|
) {
|
|
632
648
|
return _renderStaticSegment<TEnv>(
|
|
633
649
|
handler,
|
|
634
650
|
handlerId,
|
|
635
651
|
mergedRouteMap,
|
|
636
652
|
routeName,
|
|
653
|
+
buildEnv,
|
|
654
|
+
devMode,
|
|
637
655
|
);
|
|
638
656
|
}
|
|
639
657
|
|
|
@@ -658,8 +676,15 @@ export function createRouter<TEnv = any>(
|
|
|
658
676
|
const router: RSCRouterInternal<TEnv, {}> = {
|
|
659
677
|
__brand: RSC_ROUTER_BRAND,
|
|
660
678
|
id: routerId,
|
|
679
|
+
basename,
|
|
680
|
+
|
|
681
|
+
routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
|
|
682
|
+
// Wrap builder functions in urls() automatically
|
|
683
|
+
const urlPatterns: UrlPatterns<TEnv> =
|
|
684
|
+
typeof patternsOrBuilder === "function"
|
|
685
|
+
? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
|
|
686
|
+
: patternsOrBuilder;
|
|
661
687
|
|
|
662
|
-
routes(urlPatterns: UrlPatterns<TEnv>): any {
|
|
663
688
|
// Store reference for runtime manifest generation
|
|
664
689
|
storedUrlPatterns = urlPatterns;
|
|
665
690
|
const currentMountIndex = mountIndex++;
|
|
@@ -707,6 +732,10 @@ export function createRouter<TEnv = any>(
|
|
|
707
732
|
counters: {},
|
|
708
733
|
mountIndex: currentMountIndex,
|
|
709
734
|
cacheProfiles: resolvedCacheProfiles,
|
|
735
|
+
// basename sets the initial URL prefix so all path() patterns
|
|
736
|
+
// are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
|
|
737
|
+
// No namePrefix — route names stay unprefixed.
|
|
738
|
+
...(basename ? { urlPrefix: basename } : {}),
|
|
710
739
|
},
|
|
711
740
|
() => {
|
|
712
741
|
handlerResult = urlPatterns.handler() as AllUseItems[];
|
|
@@ -726,7 +755,7 @@ export function createRouter<TEnv = any>(
|
|
|
726
755
|
if (entry.type === "route" && entry.isPrerender) {
|
|
727
756
|
if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
|
|
728
757
|
prerenderRouteKeys.add(name);
|
|
729
|
-
if (entry.
|
|
758
|
+
if (entry.isPassthrough === true) {
|
|
730
759
|
if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
|
|
731
760
|
passthroughRouteKeys.add(name);
|
|
732
761
|
}
|
|
@@ -855,8 +884,18 @@ export function createRouter<TEnv = any>(
|
|
|
855
884
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
856
885
|
middleware?: MiddlewareFn<TEnv>,
|
|
857
886
|
): any {
|
|
858
|
-
//
|
|
859
|
-
|
|
887
|
+
// Auto-prefix pattern with basename so router-level middleware
|
|
888
|
+
// patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
|
|
889
|
+
if (basename && typeof patternOrMiddleware === "string") {
|
|
890
|
+
const pattern = patternOrMiddleware;
|
|
891
|
+
const prefixed =
|
|
892
|
+
pattern === "/*" || pattern === "*"
|
|
893
|
+
? `${basename}/*`
|
|
894
|
+
: `${basename}${pattern}`;
|
|
895
|
+
addMiddleware(prefixed, middleware, null);
|
|
896
|
+
} else {
|
|
897
|
+
addMiddleware(patternOrMiddleware, middleware, null);
|
|
898
|
+
}
|
|
860
899
|
return router;
|
|
861
900
|
},
|
|
862
901
|
|
|
@@ -957,6 +996,9 @@ export function createRouter<TEnv = any>(
|
|
|
957
996
|
// Expose source file for per-router type generation
|
|
958
997
|
__sourceFile,
|
|
959
998
|
|
|
999
|
+
// Expose basename for runtime manifest generation
|
|
1000
|
+
__basename: basename,
|
|
1001
|
+
|
|
960
1002
|
// RSC request handler (lazily created on first call)
|
|
961
1003
|
fetch: (() => {
|
|
962
1004
|
// Handler is created on first call and reused
|
|
@@ -990,6 +1032,10 @@ export function createRouter<TEnv = any>(
|
|
|
990
1032
|
};
|
|
991
1033
|
})(),
|
|
992
1034
|
|
|
1035
|
+
// Low-level route matching for request classification
|
|
1036
|
+
findMatch: (pathname: string, metricsStore?: any) =>
|
|
1037
|
+
findMatch(pathname, metricsStore),
|
|
1038
|
+
|
|
993
1039
|
// Debug utility for manifest inspection
|
|
994
1040
|
debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
|
|
995
1041
|
};
|
|
@@ -998,7 +1044,9 @@ export function createRouter<TEnv = any>(
|
|
|
998
1044
|
RouterRegistry.set(routerId, router);
|
|
999
1045
|
|
|
1000
1046
|
// If urls option was provided, auto-register them
|
|
1001
|
-
if (urlsOption) {
|
|
1047
|
+
if (typeof urlsOption === "function") {
|
|
1048
|
+
return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
|
|
1049
|
+
} else if (urlsOption) {
|
|
1002
1050
|
return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
|
|
1003
1051
|
}
|
|
1004
1052
|
|