@rangojs/router 0.0.0-experimental.7 → 0.0.0-experimental.8a4d0430
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 +5 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +4474 -863
- package/package.json +60 -51
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +50 -21
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +334 -72
- 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 +89 -30
- package/skills/loader/SKILL.md +388 -38
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +78 -1
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +85 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +226 -14
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +318 -89
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +87 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +285 -553
- package/src/browser/navigation-client.ts +124 -71
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +258 -308
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +185 -73
- package/src/browser/react/NavigationProvider.tsx +51 -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 +32 -79
- package/src/browser/react/use-href.tsx +2 -2
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +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 +107 -26
- package/src/browser/scroll-restoration.ts +92 -16
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +504 -599
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +109 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +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 +469 -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 +338 -0
- package/src/cache/cache-scope.ts +120 -303
- package/src/cache/cf/cf-cache-store.ts +119 -7
- package/src/cache/cf/index.ts +8 -2
- package/src/cache/document-cache.ts +101 -72
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +0 -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 +106 -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 +17 -7
- package/src/errors.ts +108 -2
- package/src/handle.ts +15 -29
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +153 -19
- package/src/index.ts +211 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -157
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +934 -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 -1428
- package/src/route-map-builder.ts +211 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +59 -8
- 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 +158 -0
- package/src/router/handler-context.ts +374 -81
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +215 -122
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +148 -35
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +80 -93
- package/src/router/match-middleware/cache-lookup.ts +382 -9
- package/src/router/match-middleware/cache-store.ts +51 -22
- package/src/router/match-middleware/intercept-resolution.ts +55 -17
- package/src/router/match-middleware/segment-resolution.ts +24 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +34 -28
- package/src/router/metrics.ts +235 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +324 -367
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/router-context.ts +36 -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 +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1241 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +77 -3
- package/src/router.ts +692 -4257
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +764 -754
- 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 +235 -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 +230 -0
- package/src/segment-system.tsx +25 -13
- package/src/server/context.ts +182 -51
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +430 -70
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +100 -31
- package/src/static-handler.ts +114 -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 +687 -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 +102 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -1623
- 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 -802
- 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 +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -1129
- package/src/vite/plugin-types.ts +131 -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 -51
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- 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 +254 -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 +510 -0
- package/src/vite/router-discovery.ts +785 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/href.ts +0 -255
- package/src/server/route-manifest-cache.ts +0 -173
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search parameter schema types and runtime utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides a lightweight schema system for typed query parameters.
|
|
5
|
+
* When a route defines a `search` schema, ctx.search provides a typed
|
|
6
|
+
* object with parsed values. ctx.searchParams always remains a standard
|
|
7
|
+
* URLSearchParams instance.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Schema Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/** Supported scalar types for search params (append ? for optional). */
|
|
15
|
+
export type SearchSchemaValue =
|
|
16
|
+
| "string"
|
|
17
|
+
| "number"
|
|
18
|
+
| "boolean"
|
|
19
|
+
| "string?"
|
|
20
|
+
| "number?"
|
|
21
|
+
| "boolean?";
|
|
22
|
+
|
|
23
|
+
/** A search schema maps param names to their type descriptors. */
|
|
24
|
+
export type SearchSchema = Record<string, SearchSchemaValue>;
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Type-Level Schema Resolution
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
/** Strip trailing `?` from a schema value to get the base type. */
|
|
31
|
+
type BaseType<T extends string> = T extends `${infer B}?` ? B : T;
|
|
32
|
+
|
|
33
|
+
/** Map a base type string to its TypeScript type. */
|
|
34
|
+
type ResolveBaseType<T extends string> = T extends "string"
|
|
35
|
+
? string
|
|
36
|
+
: T extends "number"
|
|
37
|
+
? number
|
|
38
|
+
: T extends "boolean"
|
|
39
|
+
? boolean
|
|
40
|
+
: never;
|
|
41
|
+
|
|
42
|
+
/** Keys whose schema value does NOT end with `?`. */
|
|
43
|
+
type RequiredKeys<T extends SearchSchema> = {
|
|
44
|
+
[K in keyof T]: T[K] extends `${string}?` ? never : K;
|
|
45
|
+
}[keyof T];
|
|
46
|
+
|
|
47
|
+
/** Keys whose schema value ends with `?`. */
|
|
48
|
+
type OptionalKeys<T extends SearchSchema> = {
|
|
49
|
+
[K in keyof T]: T[K] extends `${string}?` ? K : never;
|
|
50
|
+
}[keyof T];
|
|
51
|
+
|
|
52
|
+
/** Flatten an intersection type into a single object type. */
|
|
53
|
+
type Simplify<T> = { [K in keyof T]: T[K] };
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a SearchSchema to its typed object.
|
|
57
|
+
*
|
|
58
|
+
* Both required and optional params resolve to `T | undefined` at the handler
|
|
59
|
+
* level. The required/optional distinction is a consumer-facing contract
|
|
60
|
+
* (e.g., for href() and reverse() autocomplete) — it tells callers which
|
|
61
|
+
* params the route expects, but the handler must still check for undefined
|
|
62
|
+
* since the framework cannot trust the client to send all required params.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* type S = { q: "string"; page: "number?"; sort: "string?" };
|
|
66
|
+
* type R = ResolveSearchSchema<S>;
|
|
67
|
+
* // { q: string | undefined; page?: number; sort?: string }
|
|
68
|
+
*/
|
|
69
|
+
export type ResolveSearchSchema<T extends SearchSchema> = Simplify<
|
|
70
|
+
{
|
|
71
|
+
[K in RequiredKeys<T> & string]:
|
|
72
|
+
| ResolveBaseType<BaseType<T[K]>>
|
|
73
|
+
| undefined;
|
|
74
|
+
} & {
|
|
75
|
+
[K in OptionalKeys<T> & string]?: ResolveBaseType<BaseType<T[K]>>;
|
|
76
|
+
}
|
|
77
|
+
>;
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Route-Level Type Extraction
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
/** Resolve the global route map from RegisteredRoutes or GeneratedRouteMap. */
|
|
84
|
+
type GlobalRouteMap = keyof RSCRouter.RegisteredRoutes extends never
|
|
85
|
+
? keyof RSCRouter.GeneratedRouteMap extends never
|
|
86
|
+
? Record<string, string>
|
|
87
|
+
: RSCRouter.GeneratedRouteMap
|
|
88
|
+
: RSCRouter.RegisteredRoutes;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Extract the resolved search params type for a named route.
|
|
92
|
+
* Looks up the search schema from the route map and resolves it.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* // Given: path("/search", handler, { name: "search", search: { q: "string", page: "number?" } })
|
|
97
|
+
* type Params = RouteSearchParams<"search">;
|
|
98
|
+
* // { q: string; page?: number }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export type RouteSearchParams<TName extends string, TRouteMap = never> = [
|
|
102
|
+
TRouteMap,
|
|
103
|
+
] extends [never]
|
|
104
|
+
? ExtractAndResolveSearch<GlobalRouteMap, TName>
|
|
105
|
+
: ExtractAndResolveSearch<TRouteMap, TName>;
|
|
106
|
+
|
|
107
|
+
type ExtractAndResolveSearch<TRouteMap, TName> = TName extends keyof TRouteMap
|
|
108
|
+
? TRouteMap[TName] extends { readonly search: infer S extends SearchSchema }
|
|
109
|
+
? ResolveSearchSchema<S>
|
|
110
|
+
: {}
|
|
111
|
+
: {};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Extract the route params type for a named route.
|
|
115
|
+
* Looks up the path pattern from the route map and extracts params.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* // Given: path("/blog/:slug", handler, { name: "blogPost" })
|
|
120
|
+
* type Params = RouteParams<"blogPost">;
|
|
121
|
+
* // { slug: string }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export type RouteParams<TName extends string, TRouteMap = never> = [
|
|
125
|
+
TRouteMap,
|
|
126
|
+
] extends [never]
|
|
127
|
+
? ExtractRouteParamsFromMap<GlobalRouteMap, TName>
|
|
128
|
+
: ExtractRouteParamsFromMap<TRouteMap, TName>;
|
|
129
|
+
|
|
130
|
+
type ExtractRouteParamsFromMap<TRouteMap, TName> = TName extends keyof TRouteMap
|
|
131
|
+
? TRouteMap[TName] extends string
|
|
132
|
+
? ExtractParamsFromPattern<TRouteMap[TName]>
|
|
133
|
+
: TRouteMap[TName] extends { readonly path: infer P extends string }
|
|
134
|
+
? ExtractParamsFromPattern<P>
|
|
135
|
+
: {}
|
|
136
|
+
: {};
|
|
137
|
+
|
|
138
|
+
/** Parse "a|b|c" into "a" | "b" | "c" */
|
|
139
|
+
type ParseConstraint<T extends string> =
|
|
140
|
+
T extends `${infer First}|${infer Rest}` ? First | ParseConstraint<Rest> : T;
|
|
141
|
+
|
|
142
|
+
/** Minimal inline param extraction (avoids importing from types.ts to prevent circular deps). */
|
|
143
|
+
type ExtractParamsFromPattern<T extends string> =
|
|
144
|
+
T extends `${string}:${infer Param}/${infer Rest}`
|
|
145
|
+
? Param extends `${infer Name}(${infer C})?`
|
|
146
|
+
? {
|
|
147
|
+
[K in Name]?: ParseConstraint<C>;
|
|
148
|
+
} & ExtractParamsFromPattern<`/${Rest}`>
|
|
149
|
+
: Param extends `${infer Name}(${infer C})`
|
|
150
|
+
? {
|
|
151
|
+
[K in Name]: ParseConstraint<C>;
|
|
152
|
+
} & ExtractParamsFromPattern<`/${Rest}`>
|
|
153
|
+
: Param extends `${infer Name}?`
|
|
154
|
+
? { [K in Name]?: string } & ExtractParamsFromPattern<`/${Rest}`>
|
|
155
|
+
: { [K in Param]: string } & ExtractParamsFromPattern<`/${Rest}`>
|
|
156
|
+
: T extends `${string}:${infer Param}`
|
|
157
|
+
? Param extends `${infer Name}(${infer C})?`
|
|
158
|
+
? { [K in Name]?: ParseConstraint<C> }
|
|
159
|
+
: Param extends `${infer Name}(${infer C})`
|
|
160
|
+
? { [K in Name]: ParseConstraint<C> }
|
|
161
|
+
: Param extends `${infer Name}?`
|
|
162
|
+
? { [K in Name]?: string }
|
|
163
|
+
: { [K in Param]: string }
|
|
164
|
+
: {};
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Runtime Parser
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Parse URLSearchParams into a typed object using the given schema.
|
|
172
|
+
*
|
|
173
|
+
* - `"string"` / `"string?"` - kept as-is
|
|
174
|
+
* - `"number"` / `"number?"` - coerced via `Number()`; NaN treated as missing
|
|
175
|
+
* - `"boolean"` / `"boolean?"` - `"true"` / `"1"` -> true, `"false"` / `"0"` / `""` -> false
|
|
176
|
+
*
|
|
177
|
+
* Missing params (both required and optional) are omitted from the result
|
|
178
|
+
* (undefined). The required/optional distinction is a consumer-facing contract
|
|
179
|
+
* only — the handler must check for undefined.
|
|
180
|
+
*/
|
|
181
|
+
export function parseSearchParams<T extends SearchSchema>(
|
|
182
|
+
searchParams: URLSearchParams,
|
|
183
|
+
schema: T,
|
|
184
|
+
): ResolveSearchSchema<T> {
|
|
185
|
+
const result: Record<string, unknown> = {};
|
|
186
|
+
|
|
187
|
+
for (const [key, descriptor] of Object.entries(schema)) {
|
|
188
|
+
const isOptional = descriptor.endsWith("?");
|
|
189
|
+
const baseType = isOptional ? descriptor.slice(0, -1) : descriptor;
|
|
190
|
+
const raw = searchParams.get(key);
|
|
191
|
+
|
|
192
|
+
if (raw === null) {
|
|
193
|
+
// Missing params are omitted (undefined) regardless of required/optional
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (baseType === "string") {
|
|
198
|
+
result[key] = raw;
|
|
199
|
+
} else if (baseType === "number") {
|
|
200
|
+
const num = Number(raw);
|
|
201
|
+
if (!Number.isNaN(num)) {
|
|
202
|
+
result[key] = num;
|
|
203
|
+
}
|
|
204
|
+
// NaN treated as missing (undefined)
|
|
205
|
+
} else if (baseType === "boolean") {
|
|
206
|
+
result[key] = raw === "true" || raw === "1";
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return result as ResolveSearchSchema<T>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// Runtime Serializer
|
|
215
|
+
// ============================================================================
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Serialize a typed search params object to a query string (without leading `?`).
|
|
219
|
+
* Skips `undefined` and `null` values.
|
|
220
|
+
*/
|
|
221
|
+
export function serializeSearchParams(params: Record<string, unknown>): string {
|
|
222
|
+
const parts: string[] = [];
|
|
223
|
+
for (const [key, value] of Object.entries(params)) {
|
|
224
|
+
if (value === undefined || value === null) continue;
|
|
225
|
+
parts.push(
|
|
226
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return parts.join("&");
|
|
230
|
+
}
|
package/src/segment-system.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
import { createElement, type ReactNode, type ComponentType } from "react";
|
|
2
3
|
import { OutletProvider } from "./client.js";
|
|
3
4
|
import { MountContextProvider } from "./browser/react/mount-context.js";
|
|
@@ -14,6 +15,11 @@ import {
|
|
|
14
15
|
} from "./route-content-wrapper.js";
|
|
15
16
|
import { RootErrorBoundary } from "./root-error-boundary.js";
|
|
16
17
|
|
|
18
|
+
// ViewTransition is only available in React experimental.
|
|
19
|
+
// Access via namespace import to avoid compile-time errors on stable React.
|
|
20
|
+
const ReactViewTransition: any =
|
|
21
|
+
"ViewTransition" in React ? (React as any).ViewTransition : null;
|
|
22
|
+
|
|
17
23
|
/**
|
|
18
24
|
* Resolve loader data from raw results, unwrapping LoaderDataResult wrappers
|
|
19
25
|
*/
|
|
@@ -210,7 +216,7 @@ export async function renderSegments(
|
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
let nodeContent: ReactNode =
|
|
213
|
-
loading !== null && loading
|
|
219
|
+
loading !== null && loading !== undefined && loading !== false
|
|
214
220
|
? createElement(RouteContentWrapper, {
|
|
215
221
|
key: `suspense-loading-${id}`,
|
|
216
222
|
content:
|
|
@@ -221,6 +227,19 @@ export async function renderSegments(
|
|
|
221
227
|
segmentId: id,
|
|
222
228
|
})
|
|
223
229
|
: registerLazyRef(resolvedComponent);
|
|
230
|
+
|
|
231
|
+
// Wrap with <ViewTransition> if transition config exists (React experimental only).
|
|
232
|
+
// An empty config ({}) creates a bare <ViewTransition> boundary that participates
|
|
233
|
+
// in transitions without adding custom animation classes. Named element-level
|
|
234
|
+
// <ViewTransition> components inside (with name/share props) morph independently
|
|
235
|
+
// from the parent's default cross-fade.
|
|
236
|
+
if (ReactViewTransition && node.segment.transition) {
|
|
237
|
+
nodeContent = createElement(ReactViewTransition, {
|
|
238
|
+
...node.segment.transition,
|
|
239
|
+
children: nodeContent,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
224
243
|
// Common props for OutletProvider
|
|
225
244
|
const outletContent: ReactNode =
|
|
226
245
|
node.segment.type === "layout" ? content : null;
|
|
@@ -407,20 +426,13 @@ function* segmentTreeWalk(
|
|
|
407
426
|
}
|
|
408
427
|
}
|
|
409
428
|
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
//
|
|
414
|
-
nonParallels.sort((a, b) => {
|
|
415
|
-
if (a.id.length !== b.id.length) {
|
|
416
|
-
return a.id.length - b.id.length;
|
|
417
|
-
}
|
|
418
|
-
return a.id.localeCompare(b.id);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// Iterate bottom-to-top using reverse() to process leaf segments first
|
|
429
|
+
// Segments arrive in root-to-leaf order from the server (resolveSegment
|
|
430
|
+
// and resolveSegmentWithRevalidation push segments in this order).
|
|
431
|
+
// All consumers (reconcileSegments, cache) preserve this order.
|
|
432
|
+
// No sorting needed — iterate bottom-to-top to process leaf segments first.
|
|
422
433
|
// This processes route/leaf layouts first, then parent layouts
|
|
423
434
|
// Note: We reverse the array to iterate from end to start (bottom-to-top)
|
|
435
|
+
|
|
424
436
|
for (let i = nonParallels.length - 1; i >= 0; i--) {
|
|
425
437
|
const segment = nonParallels[i];
|
|
426
438
|
|