@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650
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 +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +71 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -25
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +42 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +316 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -10
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -41
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +5 -112
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +62 -67
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -48
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -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 +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -34
- package/src/vite/utils/shared-utils.ts +95 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -11,122 +11,40 @@ import {
|
|
|
11
11
|
when,
|
|
12
12
|
errorBoundary,
|
|
13
13
|
notFoundBoundary,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
route,
|
|
15
|
+
loader,
|
|
16
|
+
loading,
|
|
17
|
+
transition,
|
|
18
18
|
} from "./dsl-helpers.js";
|
|
19
19
|
import RootLayout from "../server/root-layout";
|
|
20
20
|
import { invariant } from "../errors";
|
|
21
21
|
|
|
22
|
-
/*
|
|
23
|
-
* Create revalidate helper
|
|
24
|
-
*/
|
|
25
|
-
const createRevalidateHelper = <TEnv>(): RouteHelpers<
|
|
26
|
-
any,
|
|
27
|
-
TEnv
|
|
28
|
-
>["revalidate"] => {
|
|
29
|
-
return revalidate as RouteHelpers<any, TEnv>["revalidate"];
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Create errorBoundary helper
|
|
34
|
-
*/
|
|
35
|
-
const createErrorBoundaryHelper = <TEnv>(): RouteHelpers<
|
|
36
|
-
any,
|
|
37
|
-
TEnv
|
|
38
|
-
>["errorBoundary"] => {
|
|
39
|
-
return errorBoundary as RouteHelpers<any, TEnv>["errorBoundary"];
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Create notFoundBoundary helper
|
|
44
|
-
*/
|
|
45
|
-
const createNotFoundBoundaryHelper = <TEnv>(): RouteHelpers<
|
|
46
|
-
any,
|
|
47
|
-
TEnv
|
|
48
|
-
>["notFoundBoundary"] => {
|
|
49
|
-
return notFoundBoundary as RouteHelpers<any, TEnv>["notFoundBoundary"];
|
|
50
|
-
};
|
|
51
|
-
|
|
52
22
|
/**
|
|
53
|
-
*
|
|
23
|
+
* Assemble the RouteHelpers object. The helpers are the DSL functions
|
|
24
|
+
* themselves; the single cast erases the phantom generics (and the extra
|
|
25
|
+
* `route` key) that the per-router RouteHelpers<T, TEnv> type carries but the
|
|
26
|
+
* runtime functions do not.
|
|
54
27
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
28
|
+
function buildRouteHelpers<T extends RouteDefinition, TEnv>(): RouteHelpers<
|
|
29
|
+
T,
|
|
57
30
|
TEnv
|
|
58
|
-
>
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
>(): RouteHelpers<T, TEnv>["intercept"] => {
|
|
76
|
-
return intercept as RouteHelpers<T, TEnv>["intercept"];
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Create loader helper
|
|
81
|
-
*/
|
|
82
|
-
const createLoaderHelper = <TEnv>(): RouteHelpers<any, TEnv>["loader"] => {
|
|
83
|
-
return loaderFn as RouteHelpers<any, TEnv>["loader"];
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Create loading helper
|
|
88
|
-
*/
|
|
89
|
-
const createLoadingHelper = (): RouteHelpers<any, any>["loading"] => {
|
|
90
|
-
return loadingFn;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Create route helper
|
|
95
|
-
*/
|
|
96
|
-
const createRouteHelper = <
|
|
97
|
-
const T extends RouteDefinition,
|
|
98
|
-
TEnv,
|
|
99
|
-
>(): RouteHelpers<T, TEnv>["route"] => {
|
|
100
|
-
return routeFn as unknown as RouteHelpers<T, TEnv>["route"];
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Create layout helper
|
|
105
|
-
*/
|
|
106
|
-
const createLayoutHelper = <TEnv>(): RouteHelpers<any, TEnv>["layout"] => {
|
|
107
|
-
return layout as RouteHelpers<any, TEnv>["layout"];
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Create when helper for intercept conditions
|
|
112
|
-
*/
|
|
113
|
-
const createWhenHelper = (): RouteHelpers<any, any>["when"] => {
|
|
114
|
-
return when;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create cache helper for cache configuration
|
|
119
|
-
*/
|
|
120
|
-
const createCacheHelper = (): RouteHelpers<any, any>["cache"] => {
|
|
121
|
-
return cache;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Create transition helper
|
|
126
|
-
*/
|
|
127
|
-
const createTransitionHelper = (): RouteHelpers<any, any>["transition"] => {
|
|
128
|
-
return transitionFn as RouteHelpers<any, any>["transition"];
|
|
129
|
-
};
|
|
31
|
+
> {
|
|
32
|
+
return {
|
|
33
|
+
route,
|
|
34
|
+
layout,
|
|
35
|
+
parallel,
|
|
36
|
+
intercept,
|
|
37
|
+
middleware,
|
|
38
|
+
revalidate,
|
|
39
|
+
loader,
|
|
40
|
+
loading,
|
|
41
|
+
errorBoundary,
|
|
42
|
+
notFoundBoundary,
|
|
43
|
+
when,
|
|
44
|
+
cache,
|
|
45
|
+
transition,
|
|
46
|
+
} as unknown as RouteHelpers<T, TEnv>;
|
|
47
|
+
}
|
|
130
48
|
|
|
131
49
|
/**
|
|
132
50
|
* Branded type for route handlers that carries the route type info.
|
|
@@ -152,21 +70,7 @@ export function map<const T extends RouteDefinition, TEnv = DefaultEnv>(
|
|
|
152
70
|
"map() expects a builder function as its argument",
|
|
153
71
|
);
|
|
154
72
|
// Create helpers
|
|
155
|
-
const helpers
|
|
156
|
-
route: createRouteHelper<T, TEnv>(),
|
|
157
|
-
layout: createLayoutHelper<TEnv>(),
|
|
158
|
-
parallel: createParallelHelper<TEnv>(),
|
|
159
|
-
intercept: createInterceptHelper<T, TEnv>(),
|
|
160
|
-
middleware: createMiddlewareHelper<TEnv>(),
|
|
161
|
-
revalidate: createRevalidateHelper<TEnv>(),
|
|
162
|
-
loader: createLoaderHelper<TEnv>(),
|
|
163
|
-
loading: createLoadingHelper(),
|
|
164
|
-
errorBoundary: createErrorBoundaryHelper<TEnv>(),
|
|
165
|
-
notFoundBoundary: createNotFoundBoundaryHelper<TEnv>(),
|
|
166
|
-
when: createWhenHelper(),
|
|
167
|
-
cache: createCacheHelper(),
|
|
168
|
-
transition: createTransitionHelper(),
|
|
169
|
-
};
|
|
73
|
+
const helpers = buildRouteHelpers<T, TEnv>();
|
|
170
74
|
|
|
171
75
|
return [layout(RootLayout, () => builder(helpers))].flat(3);
|
|
172
76
|
};
|
|
@@ -182,19 +86,5 @@ export function createRouteHelpers<
|
|
|
182
86
|
T extends RouteDefinition,
|
|
183
87
|
TEnv,
|
|
184
88
|
>(): RouteHelpers<T, TEnv> {
|
|
185
|
-
return
|
|
186
|
-
route: createRouteHelper<T, TEnv>(),
|
|
187
|
-
layout: createLayoutHelper<TEnv>(),
|
|
188
|
-
parallel: createParallelHelper<TEnv>(),
|
|
189
|
-
intercept: createInterceptHelper<T, TEnv>(),
|
|
190
|
-
middleware: createMiddlewareHelper<TEnv>(),
|
|
191
|
-
revalidate: createRevalidateHelper<TEnv>(),
|
|
192
|
-
loader: createLoaderHelper<TEnv>(),
|
|
193
|
-
loading: createLoadingHelper(),
|
|
194
|
-
errorBoundary: createErrorBoundaryHelper<TEnv>(),
|
|
195
|
-
notFoundBoundary: createNotFoundBoundaryHelper<TEnv>(),
|
|
196
|
-
when: createWhenHelper(),
|
|
197
|
-
cache: createCacheHelper(),
|
|
198
|
-
transition: createTransitionHelper(),
|
|
199
|
-
};
|
|
89
|
+
return buildRouteHelpers<T, TEnv>();
|
|
200
90
|
}
|
|
@@ -198,10 +198,10 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
198
198
|
use?: () => UseItems<InterceptUseItem>,
|
|
199
199
|
): InterceptItem;
|
|
200
200
|
// Global: unprefixed, params inferred from global route map
|
|
201
|
-
<K extends keyof
|
|
201
|
+
<K extends keyof Rango.GeneratedRouteMap & string>(
|
|
202
202
|
slotName: `@${string}`,
|
|
203
203
|
routeName: K,
|
|
204
|
-
handler: ReactNode | Handler<K,
|
|
204
|
+
handler: ReactNode | Handler<K, Rango.GeneratedRouteMap, TEnv>,
|
|
205
205
|
use?: () => UseItems<InterceptUseItem>,
|
|
206
206
|
): InterceptItem;
|
|
207
207
|
};
|
|
@@ -250,8 +250,10 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
250
250
|
* )
|
|
251
251
|
*
|
|
252
252
|
* // Revalidate after specific actions (actionId format: "path/to/file.ts#exportName")
|
|
253
|
+
* // Use `|| undefined` (defer), not `?? false` (hard short-circuit), so the
|
|
254
|
+
* // chain and the segment default still apply when there is no match.
|
|
253
255
|
* revalidate(({ actionId }) =>
|
|
254
|
-
* actionId?.includes("Cart")
|
|
256
|
+
* actionId?.includes("Cart") || undefined
|
|
255
257
|
* )
|
|
256
258
|
*
|
|
257
259
|
* // Soft decision (suggest but allow override)
|
|
@@ -274,7 +276,7 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
274
276
|
*
|
|
275
277
|
* // With loader-specific revalidation (match by file or export name)
|
|
276
278
|
* loader(CartLoader, () => [
|
|
277
|
-
* revalidate(({ actionId }) => actionId?.includes("Cart")
|
|
279
|
+
* revalidate(({ actionId }) => actionId?.includes("Cart") || undefined),
|
|
278
280
|
* ])
|
|
279
281
|
*
|
|
280
282
|
* // Consume in client components with useLoader()
|
|
@@ -439,18 +441,36 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
439
441
|
cache: {
|
|
440
442
|
(): CacheItem;
|
|
441
443
|
(children: () => UseItems<AllUseItems>): CacheItem;
|
|
442
|
-
(profileName: string): CacheItem;
|
|
443
|
-
(profileName: string, use: () => UseItems<AllUseItems>): CacheItem;
|
|
444
444
|
(
|
|
445
|
-
options: PartialCacheOptions | false,
|
|
445
|
+
options: PartialCacheOptions<TEnv> | false,
|
|
446
446
|
use?: () => UseItems<AllUseItems>,
|
|
447
447
|
): CacheItem;
|
|
448
448
|
};
|
|
449
449
|
/**
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
450
|
+
* Opt a route (or group of routes) into transition-driven navigation.
|
|
451
|
+
*
|
|
452
|
+
* `transition()` does two independent things, and you choose how far to go:
|
|
453
|
+
* 1. startTransition (ALL React versions): the navigation commit is driven
|
|
454
|
+
* through React's startTransition, so a same-route nav (same route,
|
|
455
|
+
* different params, e.g. /product/1 -> /product/2) holds the previous
|
|
456
|
+
* content while the new loader resolves instead of flashing the route's
|
|
457
|
+
* loading() skeleton (see segment-system.tsx inTransitionScope). This is
|
|
458
|
+
* also the precondition for any view-transition animation.
|
|
459
|
+
* 2. <ViewTransition> (experimental React only): the segment content is also
|
|
460
|
+
* wrapped in React's <ViewTransition>, so the held swap cross-fades/morphs.
|
|
461
|
+
* Layered on by default; pass { viewTransition: false } to keep #1 without
|
|
462
|
+
* the router boundary (and place your own <ViewTransition> instead).
|
|
463
|
+
*
|
|
464
|
+
* A view transition cannot fire without a startTransition, so the meaningful
|
|
465
|
+
* choices are (see skills/view-transitions for the full matrix):
|
|
466
|
+
* - no transition() -> neither (remount + skeleton)
|
|
467
|
+
* - transition({ viewTransition: false }) -> startTransition only (hold)
|
|
468
|
+
* - transition({}) / transition({ enter… }) -> startTransition + ViewTransition
|
|
469
|
+
*
|
|
470
|
+
* Precedence: a bare transition({}) inherits createRouter({ viewTransition })
|
|
471
|
+
* (default "auto"); an explicit per-route `viewTransition` always wins. So
|
|
472
|
+
* transition({}) is startTransition + ViewTransition under the default and
|
|
473
|
+
* startTransition only when the router sets viewTransition: false.
|
|
454
474
|
*
|
|
455
475
|
* ```typescript
|
|
456
476
|
* // Attach to a single route
|
|
@@ -464,16 +484,19 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
464
484
|
* path("/about", AboutPage),
|
|
465
485
|
* ])
|
|
466
486
|
*
|
|
467
|
-
* //
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
* })
|
|
487
|
+
* // Hold content + drive view transitions, but place no router boundary:
|
|
488
|
+
* path("/product/:id", ProductPage, { name: "product" }, () => [
|
|
489
|
+
* transition({ viewTransition: false }),
|
|
490
|
+
* ])
|
|
472
491
|
* ```
|
|
473
|
-
* @param config - ViewTransition configuration (enter, exit, update, share,
|
|
492
|
+
* @param config - ViewTransition configuration (enter, exit, update, share,
|
|
493
|
+
* default, name) plus `viewTransition: "auto" | false` to toggle the router
|
|
494
|
+
* boundary (createRouter({ viewTransition }) sets the app-wide default)
|
|
474
495
|
* @param children - Optional callback returning child routes to wrap
|
|
475
496
|
*/
|
|
476
497
|
transition: {
|
|
498
|
+
(): TransitionItem;
|
|
499
|
+
(children: () => UseItems<AllUseItems>): TransitionItem;
|
|
477
500
|
(config: TransitionConfig): TransitionItem;
|
|
478
501
|
(
|
|
479
502
|
config: TransitionConfig,
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getRequestContext,
|
|
5
5
|
_getRequestContext,
|
|
6
6
|
} from "../server/request-context.js";
|
|
7
|
+
import { markExternalRedirect } from "../redirect-origin.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Create a soft redirect Response for middleware short-circuit
|
|
@@ -39,6 +40,11 @@ import {
|
|
|
39
40
|
* status: 303,
|
|
40
41
|
* state: [Flash({ text: "Session expired" })],
|
|
41
42
|
* });
|
|
43
|
+
*
|
|
44
|
+
* // Off-host redirect (opt out of the same-origin guard). Without
|
|
45
|
+
* // `external: true`, a cross-origin target is blocked and replaced with the
|
|
46
|
+
* // app root, matching the client's open-redirect protection.
|
|
47
|
+
* return redirect('https://accounts.example.com/oauth', { external: true });
|
|
42
48
|
* ```
|
|
43
49
|
*/
|
|
44
50
|
export function redirect(url: string, status?: number): Response;
|
|
@@ -47,13 +53,18 @@ export function redirect(
|
|
|
47
53
|
options: {
|
|
48
54
|
status?: number;
|
|
49
55
|
state?: LocationStateEntry | LocationStateEntry[];
|
|
56
|
+
external?: boolean;
|
|
50
57
|
},
|
|
51
58
|
): Response;
|
|
52
59
|
export function redirect(
|
|
53
60
|
url: string,
|
|
54
61
|
statusOrOptions?:
|
|
55
62
|
| number
|
|
56
|
-
| {
|
|
63
|
+
| {
|
|
64
|
+
status?: number;
|
|
65
|
+
state?: LocationStateEntry | LocationStateEntry[];
|
|
66
|
+
external?: boolean;
|
|
67
|
+
},
|
|
57
68
|
): Response {
|
|
58
69
|
const status =
|
|
59
70
|
typeof statusOrOptions === "number"
|
|
@@ -61,6 +72,8 @@ export function redirect(
|
|
|
61
72
|
: (statusOrOptions?.status ?? 302);
|
|
62
73
|
const state =
|
|
63
74
|
typeof statusOrOptions === "object" ? statusOrOptions?.state : undefined;
|
|
75
|
+
const external =
|
|
76
|
+
typeof statusOrOptions === "object" ? statusOrOptions?.external : undefined;
|
|
64
77
|
|
|
65
78
|
if (state) {
|
|
66
79
|
const ctx = requireRequestContext();
|
|
@@ -85,17 +98,38 @@ export function redirect(
|
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
// Auto-prefix root-relative URLs with basename for app-local redirects.
|
|
101
|
+
// Treat the URL as already-prefixed when the basename is followed by a path
|
|
102
|
+
// separator, a query, a fragment, or end-of-string, so "/admin?tab=x" and
|
|
103
|
+
// "/admin#frag" are not double-prefixed into "/admin/admin?tab=x".
|
|
88
104
|
const bn = _getRequestContext()?._basename;
|
|
89
105
|
let resolvedUrl = url;
|
|
90
|
-
if (
|
|
106
|
+
if (
|
|
107
|
+
bn &&
|
|
108
|
+
url.startsWith("/") &&
|
|
109
|
+
url !== bn &&
|
|
110
|
+
!url.startsWith(bn + "/") &&
|
|
111
|
+
!url.startsWith(bn + "?") &&
|
|
112
|
+
!url.startsWith(bn + "#")
|
|
113
|
+
) {
|
|
91
114
|
resolvedUrl = url === "/" ? bn : bn + url;
|
|
92
115
|
}
|
|
93
116
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
const headers: Record<string, string> = {
|
|
118
|
+
Location: resolvedUrl,
|
|
119
|
+
"X-RSC-Redirect": "soft",
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const response = new Response(null, { status, headers });
|
|
123
|
+
|
|
124
|
+
// Mark an explicit off-host redirect with an out-of-band brand so the
|
|
125
|
+
// same-origin guard (rsc/redirect-guard.ts) lets it through. The brand is a
|
|
126
|
+
// WeakSet membership on this Response object -- NOT a wire header -- so the
|
|
127
|
+
// opt-in cannot be forged by an attacker-controlled upstream response a
|
|
128
|
+
// proxy-style response route might copy. The internal redirect-rebuild paths
|
|
129
|
+
// transfer the brand; the guard reads and clears it (see markExternalRedirect).
|
|
130
|
+
if (external) {
|
|
131
|
+
markExternalRedirect(response);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return response;
|
|
101
135
|
}
|
|
@@ -139,6 +139,12 @@ export function mergeHandlerUse(
|
|
|
139
139
|
mountSite: string,
|
|
140
140
|
): (() => any[]) | undefined {
|
|
141
141
|
if (!handlerUse && !explicitUse) return undefined;
|
|
142
|
+
// Validation asymmetry (intentional, pre-1.0): only handler.use() items are
|
|
143
|
+
// checked against the mount-site allow-list (validateHandlerUseItems below).
|
|
144
|
+
// Explicit use() items pass through unvalidated on both the explicit-only
|
|
145
|
+
// branch here and the merged branch, so a structurally-valid-but-prohibited
|
|
146
|
+
// item (e.g. middleware() inside a parallel slot) is not rejected at this seam.
|
|
147
|
+
// Documented rather than enforced for now; revisit before 1.0 (#569).
|
|
142
148
|
if (!handlerUse) return explicitUse;
|
|
143
149
|
if (!explicitUse) {
|
|
144
150
|
return () => {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AllUseItems, WhenItem } from "../route-types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The set of valid use-item `type` discriminants — the single runtime source of
|
|
5
|
+
* truth for "is this a well-formed use item?" shape validation.
|
|
6
|
+
*
|
|
7
|
+
* Declared via a `Record<...>` so that adding a member to the union without
|
|
8
|
+
* updating this map is a compile error. `when` is included because when() items
|
|
9
|
+
* are valid inside intercept() even though WhenItem is not part of AllUseItems
|
|
10
|
+
* (it lives only in InterceptUseItem). This is shape validation only; per-mount-
|
|
11
|
+
* site rules remain the narrower hand-written tables in resolve-handler-use.ts.
|
|
12
|
+
*/
|
|
13
|
+
const USE_ITEM_TYPES: Record<AllUseItems["type"] | WhenItem["type"], true> = {
|
|
14
|
+
layout: true,
|
|
15
|
+
route: true,
|
|
16
|
+
middleware: true,
|
|
17
|
+
revalidate: true,
|
|
18
|
+
parallel: true,
|
|
19
|
+
intercept: true,
|
|
20
|
+
loader: true,
|
|
21
|
+
loading: true,
|
|
22
|
+
errorBoundary: true,
|
|
23
|
+
notFoundBoundary: true,
|
|
24
|
+
when: true,
|
|
25
|
+
cache: true,
|
|
26
|
+
transition: true,
|
|
27
|
+
include: true,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ALL_USE_ITEM_TYPES: ReadonlySet<string> = new Set(
|
|
31
|
+
Object.keys(USE_ITEM_TYPES),
|
|
32
|
+
);
|
package/src/route-map-builder.ts
CHANGED
|
@@ -8,15 +8,10 @@
|
|
|
8
8
|
* See docs/manifests.md for the full data flow.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
// Singleton route map instance - populated incrementally as routes are encountered
|
|
12
11
|
let globalRouteMap: Record<string, string> = {};
|
|
13
12
|
|
|
14
|
-
// Cached complete manifest - includes all routes (including lazy includes)
|
|
15
|
-
// Set from runtime cache or build-time import
|
|
16
13
|
let cachedManifest: Record<string, string> | null = null;
|
|
17
14
|
|
|
18
|
-
// Pre-computed route entries from build-time prefix tree leaf nodes.
|
|
19
|
-
// Used by evaluateLazyEntry() to skip running the handler for route matching.
|
|
20
15
|
let cachedPrecomputedEntries: Array<{
|
|
21
16
|
staticPrefix: string;
|
|
22
17
|
routes: Record<string, string>;
|
|
@@ -43,7 +38,6 @@ export function registerRouteMap(map: Record<string, string>): void {
|
|
|
43
38
|
* @internal
|
|
44
39
|
*/
|
|
45
40
|
export function getGlobalRouteMap(): Record<string, string> {
|
|
46
|
-
// Cached manifest is complete (includes lazy routes), so prefer it
|
|
47
41
|
if (cachedManifest) {
|
|
48
42
|
return cachedManifest;
|
|
49
43
|
}
|
|
@@ -231,10 +225,6 @@ export function waitForManifestReady(): Promise<void> | null {
|
|
|
231
225
|
return manifestReadyPromise;
|
|
232
226
|
}
|
|
233
227
|
|
|
234
|
-
// ============================================================================
|
|
235
|
-
// Route Scope Registry
|
|
236
|
-
// ============================================================================
|
|
237
|
-
|
|
238
228
|
// Tracks whether each route is at root scope (no named include boundary above).
|
|
239
229
|
// Used by dot-local reverse resolution to decide whether bare-name fallback
|
|
240
230
|
// is allowed after scoped lookups are exhausted.
|
|
@@ -259,14 +249,8 @@ export function isRouteRootScoped(routeName: string): boolean | undefined {
|
|
|
259
249
|
return rootScopeRoutes.get(routeName);
|
|
260
250
|
}
|
|
261
251
|
|
|
262
|
-
// ============================================================================
|
|
263
|
-
// Search Schema Registry
|
|
264
|
-
// ============================================================================
|
|
265
|
-
|
|
266
252
|
import type { SearchSchema } from "./search-params.js";
|
|
267
253
|
|
|
268
|
-
// Global search schema map: route name -> search schema descriptor.
|
|
269
|
-
// Populated by path() when a search option is provided.
|
|
270
254
|
const globalSearchSchemas: Map<string, SearchSchema> = new Map();
|
|
271
255
|
|
|
272
256
|
export function registerSearchSchema(
|
package/src/route-types.ts
CHANGED
|
@@ -5,47 +5,43 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Brand for UrlPatterns nominal typing (see pattern-types.ts). The route-item
|
|
9
|
+
* types below are discriminated by their `type` literal, so they carry no brand.
|
|
9
10
|
*/
|
|
10
|
-
export declare const LayoutBrand: unique symbol;
|
|
11
|
-
export declare const RouteBrand: unique symbol;
|
|
12
|
-
export declare const ParallelBrand: unique symbol;
|
|
13
|
-
export declare const InterceptBrand: unique symbol;
|
|
14
|
-
export declare const MiddlewareBrand: unique symbol;
|
|
15
|
-
export declare const RevalidateBrand: unique symbol;
|
|
16
|
-
export declare const LoaderBrand: unique symbol;
|
|
17
|
-
export declare const LoadingBrand: unique symbol;
|
|
18
|
-
export declare const ErrorBoundaryBrand: unique symbol;
|
|
19
|
-
export declare const NotFoundBoundaryBrand: unique symbol;
|
|
20
|
-
export declare const WhenBrand: unique symbol;
|
|
21
|
-
export declare const CacheBrand: unique symbol;
|
|
22
|
-
export declare const TransitionBrand: unique symbol;
|
|
23
|
-
export declare const IncludeBrand: unique symbol;
|
|
24
11
|
export declare const UrlPatternsBrand: unique symbol;
|
|
25
12
|
|
|
26
13
|
export type LayoutItem = {
|
|
27
14
|
name: string;
|
|
28
15
|
type: "layout";
|
|
29
16
|
uses?: AllUseItems[];
|
|
30
|
-
[LayoutBrand]: void;
|
|
31
17
|
};
|
|
32
18
|
|
|
33
19
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
20
|
+
* Phantom inference fields attached to wrapper items (layout/cache/transition)
|
|
21
|
+
* so the urls() type extractor can read their child routes/responses. The fields
|
|
22
|
+
* never exist at runtime.
|
|
36
23
|
*/
|
|
37
|
-
|
|
24
|
+
type WithChildren<
|
|
25
|
+
TBase,
|
|
38
26
|
TChildRoutes extends Record<string, any> = Record<string, string>,
|
|
39
27
|
TChildResponses extends Record<string, unknown> = Record<string, unknown>,
|
|
40
|
-
> =
|
|
28
|
+
> = TBase & {
|
|
41
29
|
readonly __childRoutes?: TChildRoutes;
|
|
42
30
|
readonly __childResponses?: TChildResponses;
|
|
43
31
|
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Typed layout item that carries child routes as phantom type
|
|
35
|
+
* Used for type inference in urls() API
|
|
36
|
+
*/
|
|
37
|
+
export type TypedLayoutItem<
|
|
38
|
+
TChildRoutes extends Record<string, any> = Record<string, string>,
|
|
39
|
+
TChildResponses extends Record<string, unknown> = Record<string, unknown>,
|
|
40
|
+
> = WithChildren<LayoutItem, TChildRoutes, TChildResponses>;
|
|
44
41
|
export type RouteItem = {
|
|
45
42
|
name: string;
|
|
46
43
|
type: "route";
|
|
47
44
|
uses?: AllUseItems[];
|
|
48
|
-
[RouteBrand]: void;
|
|
49
45
|
};
|
|
50
46
|
|
|
51
47
|
/**
|
|
@@ -67,64 +63,53 @@ export type ParallelItem = {
|
|
|
67
63
|
name: string;
|
|
68
64
|
type: "parallel";
|
|
69
65
|
uses?: ParallelUseItem[];
|
|
70
|
-
[ParallelBrand]: void;
|
|
71
66
|
};
|
|
72
67
|
export type InterceptItem = {
|
|
73
68
|
name: string;
|
|
74
69
|
type: "intercept";
|
|
75
70
|
uses?: InterceptUseItem[];
|
|
76
|
-
[InterceptBrand]: void;
|
|
77
71
|
};
|
|
78
72
|
export type LoaderItem = {
|
|
79
73
|
name: string;
|
|
80
74
|
type: "loader";
|
|
81
75
|
uses?: LoaderUseItem[];
|
|
82
|
-
[LoaderBrand]: void;
|
|
83
76
|
};
|
|
84
77
|
export type MiddlewareItem = {
|
|
85
78
|
name: string;
|
|
86
79
|
type: "middleware";
|
|
87
80
|
uses?: AllUseItems[];
|
|
88
|
-
[MiddlewareBrand]: void;
|
|
89
81
|
};
|
|
90
82
|
export type RevalidateItem = {
|
|
91
83
|
name: string;
|
|
92
84
|
type: "revalidate";
|
|
93
85
|
uses?: AllUseItems[];
|
|
94
|
-
[RevalidateBrand]: void;
|
|
95
86
|
};
|
|
96
87
|
export type LoadingItem = {
|
|
97
88
|
name: string;
|
|
98
89
|
type: "loading";
|
|
99
|
-
[LoadingBrand]: void;
|
|
100
90
|
};
|
|
101
91
|
export type ErrorBoundaryItem = {
|
|
102
92
|
name: string;
|
|
103
93
|
type: "errorBoundary";
|
|
104
94
|
uses?: AllUseItems[];
|
|
105
|
-
[ErrorBoundaryBrand]: void;
|
|
106
95
|
};
|
|
107
96
|
export type NotFoundBoundaryItem = {
|
|
108
97
|
name: string;
|
|
109
98
|
type: "notFoundBoundary";
|
|
110
99
|
uses?: AllUseItems[];
|
|
111
|
-
[NotFoundBoundaryBrand]: void;
|
|
112
100
|
};
|
|
113
101
|
export type WhenItem = {
|
|
114
102
|
name: string;
|
|
115
103
|
type: "when";
|
|
116
|
-
[WhenBrand]: void;
|
|
117
104
|
};
|
|
118
105
|
export type CacheItem = {
|
|
119
106
|
name: string;
|
|
120
107
|
type: "cache";
|
|
121
108
|
uses?: AllUseItems[];
|
|
122
|
-
[CacheBrand]: void;
|
|
123
109
|
};
|
|
124
110
|
export type TransitionItem = {
|
|
125
111
|
name: string;
|
|
126
112
|
type: "transition";
|
|
127
|
-
[TransitionBrand]: void;
|
|
128
113
|
};
|
|
129
114
|
|
|
130
115
|
/**
|
|
@@ -134,10 +119,7 @@ export type TransitionItem = {
|
|
|
134
119
|
export type TypedTransitionItem<
|
|
135
120
|
TChildRoutes extends Record<string, any> = Record<string, string>,
|
|
136
121
|
TChildResponses extends Record<string, unknown> = Record<string, unknown>,
|
|
137
|
-
> = TransitionItem
|
|
138
|
-
readonly __childRoutes?: TChildRoutes;
|
|
139
|
-
readonly __childResponses?: TChildResponses;
|
|
140
|
-
};
|
|
122
|
+
> = WithChildren<TransitionItem, TChildRoutes, TChildResponses>;
|
|
141
123
|
|
|
142
124
|
/**
|
|
143
125
|
* Typed cache item that carries child routes as phantom type
|
|
@@ -146,10 +128,7 @@ export type TypedTransitionItem<
|
|
|
146
128
|
export type TypedCacheItem<
|
|
147
129
|
TChildRoutes extends Record<string, any> = Record<string, string>,
|
|
148
130
|
TChildResponses extends Record<string, unknown> = Record<string, unknown>,
|
|
149
|
-
> = CacheItem
|
|
150
|
-
readonly __childRoutes?: TChildRoutes;
|
|
151
|
-
readonly __childResponses?: TChildResponses;
|
|
152
|
-
};
|
|
131
|
+
> = WithChildren<CacheItem, TChildRoutes, TChildResponses>;
|
|
153
132
|
|
|
154
133
|
/**
|
|
155
134
|
* Include item for URL pattern composition (used by urls() API)
|
|
@@ -184,7 +163,6 @@ export type IncludeItem = {
|
|
|
184
163
|
*/
|
|
185
164
|
includeScope?: string;
|
|
186
165
|
};
|
|
187
|
-
[IncludeBrand]: void;
|
|
188
166
|
};
|
|
189
167
|
|
|
190
168
|
/**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a router basename to its canonical form: a single leading slash,
|
|
3
|
+
* no trailing slash, and `undefined` for an empty or bare-"/" value.
|
|
4
|
+
*
|
|
5
|
+
* This is the single source of truth used by both createRouter() (so the RSC
|
|
6
|
+
* handler stores a canonical basename on the request context) and the testing
|
|
7
|
+
* primitives (so a consumer can pass the same un-normalized string their
|
|
8
|
+
* createRouter() accepts and observe the same redirect() prefixing).
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeBasename(basename?: string): string | undefined {
|
|
11
|
+
if (!basename) return undefined;
|
|
12
|
+
const trimmed = basename.replace(/^\/+|\/+$/g, "");
|
|
13
|
+
return trimmed ? "/" + trimmed : undefined;
|
|
14
|
+
}
|