@rangojs/router 0.0.0-experimental.13 → 0.0.0-experimental.13221847
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1531 -212
- package/dist/vite/index.js +3995 -2489
- package/package.json +57 -52
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +85 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +6 -4
- package/skills/hooks/SKILL.md +328 -70
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +62 -15
- package/skills/loader/SKILL.md +368 -42
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +14 -10
- package/skills/parallel/SKILL.md +137 -1
- package/skills/prerender/SKILL.md +366 -28
- package/skills/rango/SKILL.md +85 -21
- package/skills/response-routes/SKILL.md +136 -83
- package/skills/route/SKILL.md +195 -21
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +240 -102
- package/skills/use-cache/SKILL.md +324 -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/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +266 -558
- package/src/browser/navigation-client.ts +132 -75
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +303 -309
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +144 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +190 -70
- package/src/browser/react/NavigationProvider.tsx +78 -11
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +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 +29 -70
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +188 -57
- package/src/browser/scroll-restoration.ts +117 -44
- package/src/browser/segment-reconciler.ts +221 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +488 -606
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +116 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +63 -21
- package/src/build/generate-route-types.ts +36 -1038
- package/src/build/index.ts +2 -5
- package/src/build/route-trie.ts +38 -12
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +479 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +122 -303
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +84 -126
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +77 -7
- package/src/handle.ts +12 -7
- 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 +104 -40
- package/src/index.ts +122 -67
- package/src/internal-debug.ts +9 -3
- package/src/loader.rsc.ts +18 -93
- package/src/loader.ts +26 -9
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +121 -17
- package/src/prerender.ts +325 -20
- package/src/reverse.ts +144 -124
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +959 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -1450
- package/src/route-map-builder.ts +87 -133
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +41 -6
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +324 -116
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +179 -133
- package/src/router/logging.ts +112 -6
- package/src/router/manifest.ts +58 -19
- package/src/router/match-api.ts +89 -88
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +86 -89
- package/src/router/match-middleware/cache-lookup.ts +295 -49
- package/src/router/match-middleware/cache-store.ts +56 -13
- package/src/router/match-middleware/intercept-resolution.ts +45 -22
- package/src/router/match-middleware/segment-resolution.ts +20 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +44 -21
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +327 -369
- package/src/router/pattern-matching.ts +169 -31
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +105 -14
- package/src/router/router-context.ts +40 -21
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +677 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1296 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1354
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +96 -29
- package/src/router/types.ts +15 -9
- package/src/router.ts +642 -2366
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +639 -1027
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +38 -11
- package/src/search-params.ts +66 -54
- package/src/segment-system.tsx +165 -17
- package/src/server/context.ts +237 -54
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +438 -71
- package/src/server.ts +26 -164
- package/src/ssr/index.tsx +101 -31
- package/src/static-handler.ts +22 -4
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +773 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +109 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -1323
- package/src/use-loader.tsx +85 -77
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -2259
- package/src/vite/plugin-types.ts +48 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -47
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +8 -43
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +181 -9
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- 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/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/reverse.ts
CHANGED
|
@@ -10,92 +10,38 @@ export type SanitizePrefix<T extends string> = T extends `/${infer P}` ? P : T;
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Helper type to merge multiple route definitions into a single accumulated type.
|
|
13
|
-
* Note: When using createRouter, types accumulate automatically through the
|
|
14
|
-
* builder chain, so this type is typically not needed.
|
|
15
13
|
*
|
|
16
14
|
* @example
|
|
17
15
|
* ```typescript
|
|
18
|
-
*
|
|
19
|
-
* type AppRoutes = MergeRoutes<[
|
|
20
|
-
* typeof homeRoutes,
|
|
21
|
-
* PrefixRoutePatterns<typeof blogRoutes, "/blog">,
|
|
22
|
-
* ]>;
|
|
23
|
-
*
|
|
24
|
-
* // Preferred: Let router accumulate types automatically
|
|
25
|
-
* const router = createRouter<AppEnv>()
|
|
26
|
-
* .routes(homeRoutes).map(...)
|
|
27
|
-
* .routes("/blog", blogRoutes).map(...);
|
|
28
|
-
* type AppRoutes = typeof router.routeMap;
|
|
16
|
+
* type AppRoutes = MergeRoutes<[typeof siteRoutes, typeof apiRoutes]>;
|
|
29
17
|
* ```
|
|
30
18
|
*/
|
|
31
19
|
export type MergeRoutes<T extends unknown[]> = T extends [
|
|
32
20
|
infer First,
|
|
33
|
-
...infer Rest
|
|
21
|
+
...infer Rest,
|
|
34
22
|
]
|
|
35
23
|
? First & MergeRoutes<Rest>
|
|
36
24
|
: {};
|
|
37
25
|
|
|
38
|
-
/**
|
|
39
|
-
* Add key prefix to all entries in a route map
|
|
40
|
-
* { "cart": "/cart" } with prefix "shop" -> { "shop.cart": "/shop/cart" }
|
|
41
|
-
*/
|
|
42
|
-
export type PrefixRouteKeys<
|
|
43
|
-
T,
|
|
44
|
-
Prefix extends string
|
|
45
|
-
> = Prefix extends ""
|
|
46
|
-
? T
|
|
47
|
-
: { [K in keyof T as `${Prefix}.${K & string}`]: T[K] };
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Add path prefix to all patterns in a route map
|
|
51
|
-
* { "cart": "/cart" } with prefix "/shop" -> { "cart": "/shop/cart" }
|
|
52
|
-
*/
|
|
53
|
-
export type PrefixRoutePatterns<
|
|
54
|
-
T,
|
|
55
|
-
PathPrefix extends string
|
|
56
|
-
> = {
|
|
57
|
-
[K in keyof T]: PathPrefix extends "" | "/"
|
|
58
|
-
? T[K]
|
|
59
|
-
: T[K] extends "/"
|
|
60
|
-
? PathPrefix
|
|
61
|
-
: T[K] extends string
|
|
62
|
-
? `${PathPrefix}${T[K]}`
|
|
63
|
-
: T[K];
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Combined: prefix both keys and patterns
|
|
68
|
-
* Used for module augmentation registration
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```typescript
|
|
72
|
-
* // Given shopRoutes = { "index": "/", "cart": "/cart", "products.detail": "/product/:slug" }
|
|
73
|
-
* // PrefixedRoutes<typeof shopRoutes, "shop"> produces:
|
|
74
|
-
* // { "shop.index": "/shop", "shop.cart": "/shop/cart", "shop.products.detail": "/shop/product/:slug" }
|
|
75
|
-
* ```
|
|
76
|
-
*/
|
|
77
|
-
export type PrefixedRoutes<
|
|
78
|
-
T,
|
|
79
|
-
KeyPrefix extends string,
|
|
80
|
-
PathPrefix extends string = KeyPrefix extends "" ? "" : `/${KeyPrefix}`
|
|
81
|
-
> = PrefixRouteKeys<PrefixRoutePatterns<T, PathPrefix>, KeyPrefix>;
|
|
82
|
-
|
|
83
26
|
/**
|
|
84
27
|
* Helper to safely extract route patterns from a routes object
|
|
85
28
|
* Handles string values, { path, response } objects, and interface types (like RegisteredRoutes)
|
|
86
29
|
*/
|
|
87
|
-
type RoutePatternFor<
|
|
88
|
-
TRoutes
|
|
89
|
-
|
|
90
|
-
|
|
30
|
+
type RoutePatternFor<
|
|
31
|
+
TRoutes,
|
|
32
|
+
TName extends keyof TRoutes,
|
|
33
|
+
> = TRoutes[TName] extends string
|
|
34
|
+
? TRoutes[TName]
|
|
35
|
+
: TRoutes[TName] extends { readonly path: infer P extends string }
|
|
36
|
+
? P
|
|
37
|
+
: string;
|
|
91
38
|
|
|
92
39
|
/**
|
|
93
40
|
* Extract params type for a route
|
|
94
41
|
*/
|
|
95
|
-
export type ParamsFor<
|
|
96
|
-
TRoutes,
|
|
97
|
-
|
|
98
|
-
> = ExtractParams<RoutePatternFor<TRoutes, TName>>;
|
|
42
|
+
export type ParamsFor<TRoutes, TName extends keyof TRoutes> = ExtractParams<
|
|
43
|
+
RoutePatternFor<TRoutes, TName>
|
|
44
|
+
>;
|
|
99
45
|
|
|
100
46
|
/**
|
|
101
47
|
* Check if an object type has any keys
|
|
@@ -106,10 +52,12 @@ type IsEmptyObject<T> = keyof T extends never ? true : false;
|
|
|
106
52
|
* Extract search schema from a route entry.
|
|
107
53
|
* Returns {} if no search schema is defined.
|
|
108
54
|
*/
|
|
109
|
-
type ExtractSearchSchema<
|
|
110
|
-
TRoutes
|
|
111
|
-
|
|
112
|
-
|
|
55
|
+
type ExtractSearchSchema<
|
|
56
|
+
TRoutes,
|
|
57
|
+
TName extends keyof TRoutes,
|
|
58
|
+
> = TRoutes[TName] extends { readonly search: infer S extends SearchSchema }
|
|
59
|
+
? S
|
|
60
|
+
: {};
|
|
113
61
|
|
|
114
62
|
/**
|
|
115
63
|
* Type-safe reverse function signature (Django-style URL reversal)
|
|
@@ -128,7 +76,11 @@ export type ReverseFunction<TRoutes> = {
|
|
|
128
76
|
* Route without params - validates route name exists
|
|
129
77
|
*/
|
|
130
78
|
<TName extends keyof TRoutes & string>(
|
|
131
|
-
name: IsEmptyObject<
|
|
79
|
+
name: IsEmptyObject<
|
|
80
|
+
ExtractParams<RoutePatternFor<TRoutes, TName>>
|
|
81
|
+
> extends true
|
|
82
|
+
? TName
|
|
83
|
+
: never,
|
|
132
84
|
): string;
|
|
133
85
|
|
|
134
86
|
/**
|
|
@@ -136,7 +88,7 @@ export type ReverseFunction<TRoutes> = {
|
|
|
136
88
|
*/
|
|
137
89
|
<TName extends keyof TRoutes & string>(
|
|
138
90
|
name: TName,
|
|
139
|
-
params: ExtractParams<RoutePatternFor<TRoutes, TName
|
|
91
|
+
params: ExtractParams<RoutePatternFor<TRoutes, TName>>,
|
|
140
92
|
): string;
|
|
141
93
|
|
|
142
94
|
/**
|
|
@@ -145,48 +97,112 @@ export type ReverseFunction<TRoutes> = {
|
|
|
145
97
|
<TName extends keyof TRoutes & string>(
|
|
146
98
|
name: TName,
|
|
147
99
|
params: ExtractParams<RoutePatternFor<TRoutes, TName>>,
|
|
148
|
-
search: ResolveSearchSchema<ExtractSearchSchema<TRoutes, TName
|
|
100
|
+
search: ResolveSearchSchema<ExtractSearchSchema<TRoutes, TName>>,
|
|
101
|
+
): string;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Dot-prefixed route without params - strictly local resolution
|
|
105
|
+
*/
|
|
106
|
+
<TName extends keyof TRoutes & string>(
|
|
107
|
+
name: IsEmptyObject<
|
|
108
|
+
ExtractParams<RoutePatternFor<TRoutes, TName>>
|
|
109
|
+
> extends true
|
|
110
|
+
? `.${TName}`
|
|
111
|
+
: never,
|
|
112
|
+
): string;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Dot-prefixed route with params - strictly local resolution
|
|
116
|
+
*/
|
|
117
|
+
<TName extends keyof TRoutes & string>(
|
|
118
|
+
name: `.${TName}`,
|
|
119
|
+
params: ExtractParams<RoutePatternFor<TRoutes, TName>>,
|
|
120
|
+
): string;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Dot-prefixed route with params and search - strictly local resolution
|
|
124
|
+
*/
|
|
125
|
+
<TName extends keyof TRoutes & string>(
|
|
126
|
+
name: `.${TName}`,
|
|
127
|
+
params: ExtractParams<RoutePatternFor<TRoutes, TName>>,
|
|
128
|
+
search: ResolveSearchSchema<ExtractSearchSchema<TRoutes, TName>>,
|
|
149
129
|
): string;
|
|
150
130
|
};
|
|
151
131
|
|
|
152
132
|
/**
|
|
153
|
-
* Type-safe scoped reverse function
|
|
133
|
+
* Type-safe scoped reverse function with separate local and global namespaces.
|
|
154
134
|
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
135
|
+
* - `.name` — local resolution within the current include() scope
|
|
136
|
+
* - `name` — global resolution against the named-routes definition
|
|
157
137
|
*
|
|
158
138
|
* @example
|
|
159
139
|
* ```typescript
|
|
160
|
-
* reverse("
|
|
161
|
-
* reverse("
|
|
162
|
-
* reverse("
|
|
140
|
+
* reverse(".article", { slug: "hello" }) // ✓ Local route (resolves with mount prefix)
|
|
141
|
+
* reverse(".index") // ✓ Local route (no params)
|
|
142
|
+
* reverse("magazine.index") // ✓ Global route (fully qualified)
|
|
143
|
+
* reverse("blog.post", { slug: "hello" }) // ✓ Global route + params
|
|
144
|
+
* reverse(".typo") // ✗ Compile error (not in local routes)
|
|
145
|
+
* reverse("typo") // ✗ Compile error (not in global routes)
|
|
163
146
|
* ```
|
|
164
147
|
*/
|
|
165
|
-
export type ScopedReverseFunction<
|
|
148
|
+
export type ScopedReverseFunction<
|
|
149
|
+
TLocalRoutes,
|
|
150
|
+
TGlobalRoutes = TLocalRoutes,
|
|
151
|
+
> = {
|
|
166
152
|
/**
|
|
167
|
-
*
|
|
168
|
-
|
|
153
|
+
* Global route without params
|
|
154
|
+
*/
|
|
155
|
+
<TName extends keyof TGlobalRoutes & string>(
|
|
156
|
+
name: IsEmptyObject<
|
|
157
|
+
ExtractParams<RoutePatternFor<TGlobalRoutes, TName>>
|
|
158
|
+
> extends true
|
|
159
|
+
? TName
|
|
160
|
+
: never,
|
|
161
|
+
): string;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Global route with params
|
|
165
|
+
*/
|
|
166
|
+
<TName extends keyof TGlobalRoutes & string>(
|
|
167
|
+
name: TName,
|
|
168
|
+
params: ExtractParams<RoutePatternFor<TGlobalRoutes, TName>>,
|
|
169
|
+
): string;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Global route with params and search
|
|
173
|
+
*/
|
|
174
|
+
<TName extends keyof TGlobalRoutes & string>(
|
|
175
|
+
name: TName,
|
|
176
|
+
params: ExtractParams<RoutePatternFor<TGlobalRoutes, TName>>,
|
|
177
|
+
search: ResolveSearchSchema<ExtractSearchSchema<TGlobalRoutes, TName>>,
|
|
178
|
+
): string;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Dot-prefixed local route without params
|
|
169
182
|
*/
|
|
170
183
|
<TName extends keyof TLocalRoutes & string>(
|
|
171
|
-
name: IsEmptyObject<
|
|
184
|
+
name: IsEmptyObject<
|
|
185
|
+
ExtractParams<RoutePatternFor<TLocalRoutes, TName>>
|
|
186
|
+
> extends true
|
|
187
|
+
? `.${TName}`
|
|
188
|
+
: never,
|
|
172
189
|
): string;
|
|
173
190
|
|
|
174
191
|
/**
|
|
175
|
-
*
|
|
176
|
-
* @recommended Use this for type-safe URL generation with parameters
|
|
192
|
+
* Dot-prefixed local route with params
|
|
177
193
|
*/
|
|
178
194
|
<TName extends keyof TLocalRoutes & string>(
|
|
179
|
-
name: TName
|
|
180
|
-
params: ExtractParams<RoutePatternFor<TLocalRoutes, TName
|
|
195
|
+
name: `.${TName}`,
|
|
196
|
+
params: ExtractParams<RoutePatternFor<TLocalRoutes, TName>>,
|
|
181
197
|
): string;
|
|
182
198
|
|
|
183
199
|
/**
|
|
184
|
-
*
|
|
200
|
+
* Dot-prefixed local route with params and search
|
|
185
201
|
*/
|
|
186
202
|
<TName extends keyof TLocalRoutes & string>(
|
|
187
|
-
name: TName
|
|
203
|
+
name: `.${TName}`,
|
|
188
204
|
params: ExtractParams<RoutePatternFor<TLocalRoutes, TName>>,
|
|
189
|
-
search: ResolveSearchSchema<ExtractSearchSchema<TLocalRoutes, TName
|
|
205
|
+
search: ResolveSearchSchema<ExtractSearchSchema<TLocalRoutes, TName>>,
|
|
190
206
|
): string;
|
|
191
207
|
};
|
|
192
208
|
|
|
@@ -194,12 +210,13 @@ export type ScopedReverseFunction<TLocalRoutes> = {
|
|
|
194
210
|
* Extract local routes type from UrlPatterns
|
|
195
211
|
* Used with scopedReverse() to get the routes type from patterns
|
|
196
212
|
*/
|
|
197
|
-
export type ExtractLocalRoutes<TPatterns> =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
export type ExtractLocalRoutes<TPatterns> = TPatterns extends {
|
|
214
|
+
readonly _routes?: infer TRoutes;
|
|
215
|
+
}
|
|
216
|
+
? TRoutes
|
|
217
|
+
: TPatterns extends Record<string, string>
|
|
218
|
+
? TPatterns
|
|
219
|
+
: Record<string, string>;
|
|
203
220
|
|
|
204
221
|
/**
|
|
205
222
|
* Extract the response data type for a named route from a UrlPatterns instance.
|
|
@@ -210,24 +227,23 @@ export type { RouteResponse } from "./urls.js";
|
|
|
210
227
|
/**
|
|
211
228
|
* Get a locally-typed reverse function from ctx.reverse for composable modules.
|
|
212
229
|
*
|
|
213
|
-
* This is a type-only cast - ctx.reverse already resolves
|
|
214
|
-
*
|
|
215
|
-
*
|
|
230
|
+
* This is a type-only cast - ctx.reverse already resolves names at runtime.
|
|
231
|
+
* Provides type safety: `.name` validates against local routes,
|
|
232
|
+
* `name` validates against global named-routes.
|
|
216
233
|
*
|
|
217
234
|
* @param reverse - The ctx.reverse function from HandlerContext
|
|
218
|
-
* @returns The same reverse function,
|
|
235
|
+
* @returns The same reverse function, typed with local + global routes
|
|
219
236
|
*
|
|
220
237
|
* @example
|
|
221
238
|
* ```typescript
|
|
222
239
|
* // urls/blog.tsx
|
|
223
240
|
* export const blogPatterns = urls(({ path }) => [
|
|
224
241
|
* path("/", (ctx) => {
|
|
225
|
-
* // Get locally-typed reverse for this module's routes
|
|
226
242
|
* const reverse = scopedReverse<typeof blogPatterns>(ctx.reverse);
|
|
227
243
|
*
|
|
228
|
-
* reverse("index"); // ✓
|
|
229
|
-
* reverse("post", { slug: "x" }); // ✓
|
|
230
|
-
* reverse("shop.cart");
|
|
244
|
+
* reverse(".index"); // ✓ Local route
|
|
245
|
+
* reverse(".post", { slug: "x" }); // ✓ Local with params
|
|
246
|
+
* reverse("shop.cart"); // ✓ Global route
|
|
231
247
|
*
|
|
232
248
|
* return <BlogIndex />;
|
|
233
249
|
* }, { name: "index" }),
|
|
@@ -237,7 +253,7 @@ export type { RouteResponse } from "./urls.js";
|
|
|
237
253
|
* ```
|
|
238
254
|
*/
|
|
239
255
|
export function scopedReverse<TPatterns>(
|
|
240
|
-
reverse: (
|
|
256
|
+
reverse: (...args: any[]) => string,
|
|
241
257
|
): ScopedReverseFunction<ExtractLocalRoutes<TPatterns>> {
|
|
242
258
|
return reverse as ScopedReverseFunction<ExtractLocalRoutes<TPatterns>>;
|
|
243
259
|
}
|
|
@@ -258,24 +274,24 @@ export function scopedReverse<TPatterns>(
|
|
|
258
274
|
*/
|
|
259
275
|
type RouteMapEntry = string | { path: string; search?: Record<string, string> };
|
|
260
276
|
|
|
261
|
-
function resolveRoutePattern(
|
|
277
|
+
function resolveRoutePattern(
|
|
278
|
+
entry: RouteMapEntry | undefined,
|
|
279
|
+
): string | undefined {
|
|
262
280
|
if (!entry) return undefined;
|
|
263
281
|
return typeof entry === "string" ? entry : entry.path;
|
|
264
282
|
}
|
|
265
283
|
|
|
266
284
|
export function createReverse<TRoutes extends Record<string, string>>(
|
|
267
285
|
routeMap: TRoutes,
|
|
268
|
-
getFallbackMap?: () => Record<string, RouteMapEntry> | undefined,
|
|
269
286
|
): ReverseFunction<TRoutes & Record<string, string>> {
|
|
270
|
-
return ((
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
287
|
+
return ((
|
|
288
|
+
name: string,
|
|
289
|
+
params?: Record<string, string>,
|
|
290
|
+
search?: Record<string, unknown>,
|
|
291
|
+
) => {
|
|
292
|
+
const pattern = resolveRoutePattern(
|
|
293
|
+
routeMap[name] as unknown as RouteMapEntry,
|
|
294
|
+
);
|
|
279
295
|
if (!pattern) {
|
|
280
296
|
// During build-time discovery, lazy includes haven't resolved yet.
|
|
281
297
|
// Return a placeholder instead of crashing the build.
|
|
@@ -288,13 +304,17 @@ export function createReverse<TRoutes extends Record<string, string>>(
|
|
|
288
304
|
let result = pattern;
|
|
289
305
|
if (params) {
|
|
290
306
|
// Replace :param placeholders with actual values
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
307
|
+
// Strip constraint syntax: :param(a|b) -> use "param" as key
|
|
308
|
+
result = result.replace(
|
|
309
|
+
/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\??/g,
|
|
310
|
+
(_, key) => {
|
|
311
|
+
const value = params[key];
|
|
312
|
+
if (value === undefined) {
|
|
313
|
+
throw new Error(`Missing param "${key}" for route "${name}"`);
|
|
314
|
+
}
|
|
315
|
+
return encodeURIComponent(value);
|
|
316
|
+
},
|
|
317
|
+
);
|
|
298
318
|
}
|
|
299
319
|
|
|
300
320
|
// Append search params as query string
|
|
@@ -60,7 +60,8 @@ function NetworkErrorFallback({
|
|
|
60
60
|
marginBottom: "1.5rem",
|
|
61
61
|
}}
|
|
62
62
|
>
|
|
63
|
-
{error.message ||
|
|
63
|
+
{error.message ||
|
|
64
|
+
"Unable to connect to the server. Please check your internet connection."}
|
|
64
65
|
</p>
|
|
65
66
|
<div style={{ display: "flex", gap: "1rem", justifyContent: "center" }}>
|
|
66
67
|
<button
|
|
@@ -104,7 +105,12 @@ function NetworkErrorFallback({
|
|
|
104
105
|
* Default fallback UI for root error boundary
|
|
105
106
|
* This is shown when an unhandled error bubbles up to the root
|
|
106
107
|
*/
|
|
107
|
-
function RootErrorFallback({
|
|
108
|
+
function RootErrorFallback({
|
|
109
|
+
error,
|
|
110
|
+
reset,
|
|
111
|
+
}: ClientErrorBoundaryFallbackProps): ReactNode {
|
|
112
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
113
|
+
|
|
108
114
|
return (
|
|
109
115
|
<div
|
|
110
116
|
style={{
|
|
@@ -131,38 +137,40 @@ function RootErrorFallback({ error, reset }: ClientErrorBoundaryFallbackProps):
|
|
|
131
137
|
>
|
|
132
138
|
An unexpected error occurred while processing your request.
|
|
133
139
|
</p>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
background: "#fef2f2",
|
|
137
|
-
border: "1px solid #fecaca",
|
|
138
|
-
borderRadius: "0.5rem",
|
|
139
|
-
padding: "1rem",
|
|
140
|
-
marginBottom: "1rem",
|
|
141
|
-
}}
|
|
142
|
-
>
|
|
143
|
-
<p
|
|
140
|
+
{isDev && (
|
|
141
|
+
<div
|
|
144
142
|
style={{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
background: "#fef2f2",
|
|
144
|
+
border: "1px solid #fecaca",
|
|
145
|
+
borderRadius: "0.5rem",
|
|
146
|
+
padding: "1rem",
|
|
147
|
+
marginBottom: "1rem",
|
|
148
148
|
}}
|
|
149
149
|
>
|
|
150
|
-
|
|
151
|
-
</p>
|
|
152
|
-
{error.stack && (
|
|
153
|
-
<pre
|
|
150
|
+
<p
|
|
154
151
|
style={{
|
|
155
|
-
|
|
156
|
-
color: "#
|
|
157
|
-
|
|
158
|
-
whiteSpace: "pre-wrap",
|
|
159
|
-
wordBreak: "break-word",
|
|
152
|
+
fontWeight: 600,
|
|
153
|
+
color: "#991b1b",
|
|
154
|
+
marginBottom: "0.5rem",
|
|
160
155
|
}}
|
|
161
156
|
>
|
|
162
|
-
{error.
|
|
163
|
-
</
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
{error.name}: {error.message}
|
|
158
|
+
</p>
|
|
159
|
+
{error.stack && (
|
|
160
|
+
<pre
|
|
161
|
+
style={{
|
|
162
|
+
fontSize: "0.75rem",
|
|
163
|
+
color: "#6b7280",
|
|
164
|
+
overflow: "auto",
|
|
165
|
+
whiteSpace: "pre-wrap",
|
|
166
|
+
wordBreak: "break-word",
|
|
167
|
+
}}
|
|
168
|
+
>
|
|
169
|
+
{error.stack}
|
|
170
|
+
</pre>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
166
174
|
<div style={{ display: "flex", gap: "1rem" }}>
|
|
167
175
|
<button
|
|
168
176
|
type="button"
|
|
@@ -231,7 +239,11 @@ export class RootErrorBoundary extends Component<
|
|
|
231
239
|
}
|
|
232
240
|
|
|
233
241
|
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
|
|
234
|
-
console.error(
|
|
242
|
+
console.error(
|
|
243
|
+
"[RootErrorBoundary] Unhandled error caught:",
|
|
244
|
+
error,
|
|
245
|
+
errorInfo,
|
|
246
|
+
);
|
|
235
247
|
}
|
|
236
248
|
|
|
237
249
|
componentDidUpdate(prevProps: { children: ReactNode }): void {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import { Suspense, use, useId } from "react";
|
|
4
4
|
import { invariant } from "./errors";
|
|
5
|
-
import { OutletProvider } from "./
|
|
5
|
+
import { OutletProvider } from "./outlet-provider.js";
|
|
6
6
|
import type { ResolvedSegment } from "./types.js";
|
|
7
7
|
import { isLoaderDataResult } from "./types.js";
|
|
8
8
|
|
|
@@ -31,7 +31,10 @@ export function RouteContentWrapper({
|
|
|
31
31
|
return content as ReactNode;
|
|
32
32
|
}
|
|
33
33
|
return (
|
|
34
|
-
<Suspense
|
|
34
|
+
<Suspense
|
|
35
|
+
fallback={fallback ?? null}
|
|
36
|
+
key={segmentId ? "route-content-suspense-" + segmentId : undefined}
|
|
37
|
+
>
|
|
35
38
|
<Suspender content={content} key={segmentId} />
|
|
36
39
|
</Suspense>
|
|
37
40
|
);
|
|
@@ -50,11 +53,11 @@ export function RouteContentWrapperCallback<T>({
|
|
|
50
53
|
invariant(children, "RouteContentWrapperCallback requires children");
|
|
51
54
|
invariant(
|
|
52
55
|
typeof children === "function",
|
|
53
|
-
"RouteContentWrapperCallback requires children to be a function"
|
|
56
|
+
"RouteContentWrapperCallback requires children to be a function",
|
|
54
57
|
);
|
|
55
58
|
invariant(
|
|
56
59
|
resolve !== undefined,
|
|
57
|
-
"RouteContentWrapperCallback requires resolve"
|
|
60
|
+
"RouteContentWrapperCallback requires resolve",
|
|
58
61
|
);
|
|
59
62
|
return (
|
|
60
63
|
<Suspense
|