@rangojs/router 0.0.0-experimental.98 → 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 +60 -11
- 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/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 -26
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +22 -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 +310 -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 +3 -6
- 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 -11
- 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 -41
- 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 -42
- 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 +0 -116
- 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 +20 -58
- 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 -47
- 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 -35
- 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
|
@@ -2,18 +2,16 @@ import type { ComponentType, ReactNode } from "react";
|
|
|
2
2
|
import type { SerializedManifest } from "../debug.js";
|
|
3
3
|
import type { ReverseFunction } from "../reverse.js";
|
|
4
4
|
import type { UrlPatterns } from "../urls.js";
|
|
5
|
-
import type { UrlBuilder } from "../urls/pattern-types.js";
|
|
5
|
+
import type { UrlBuilder, EnvCompatible } from "../urls/pattern-types.js";
|
|
6
6
|
import type { EntryData } from "../server/context";
|
|
7
7
|
import type { ErrorInfo, MatchResult } from "../types";
|
|
8
8
|
import type { NonceProvider } from "../rsc/types.js";
|
|
9
9
|
import type { ExecutionContext } from "../server/request-context.js";
|
|
10
|
-
import type {
|
|
11
|
-
SerializedSegmentData,
|
|
12
|
-
SegmentHandleData,
|
|
13
|
-
} from "../cache/types.js";
|
|
10
|
+
import type { SerializedSegmentData } from "../cache/types.js";
|
|
14
11
|
import type { MiddlewareEntry, MiddlewareFn } from "./middleware.js";
|
|
12
|
+
import type { ExtractParams } from "../types/route-config.js";
|
|
15
13
|
import { RSC_ROUTER_BRAND } from "./router-registry.js";
|
|
16
|
-
import type {
|
|
14
|
+
import type { RangoOptions, RootLayoutProps } from "./router-options.js";
|
|
17
15
|
import type { DefaultVars } from "../types/global-namespace.js";
|
|
18
16
|
import type { ResolvedTimeouts, OnTimeoutCallback } from "./timeout.js";
|
|
19
17
|
|
|
@@ -49,16 +47,16 @@ type MergeRoutesWithResponses<
|
|
|
49
47
|
};
|
|
50
48
|
|
|
51
49
|
/**
|
|
52
|
-
* Public
|
|
50
|
+
* Public Rango router interface — the user-facing API surface.
|
|
53
51
|
*
|
|
54
52
|
* Users interact with this type when building and using routers.
|
|
55
|
-
* Internal framework code uses
|
|
53
|
+
* Internal framework code uses RangoInternal (via toInternal()) to access
|
|
56
54
|
* matching, build-time, and configuration members that are not part of the
|
|
57
55
|
* public contract.
|
|
58
56
|
*
|
|
59
57
|
* TRoutes accumulates all registered route types through the builder chain.
|
|
60
58
|
*/
|
|
61
|
-
export interface
|
|
59
|
+
export interface Rango<
|
|
62
60
|
TEnv = any,
|
|
63
61
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
64
62
|
> {
|
|
@@ -89,16 +87,16 @@ export interface RSCRouter<
|
|
|
89
87
|
* ])
|
|
90
88
|
* ```
|
|
91
89
|
*/
|
|
92
|
-
routes<T extends UrlPatterns<
|
|
93
|
-
patterns: T,
|
|
94
|
-
):
|
|
90
|
+
routes<T extends UrlPatterns<any, any, any>>(
|
|
91
|
+
patterns: T & EnvCompatible<T, TEnv>,
|
|
92
|
+
): Rango<
|
|
95
93
|
TEnv,
|
|
96
94
|
TRoutes &
|
|
97
95
|
(NonNullable<T["_routes"]> extends Record<string, unknown>
|
|
98
96
|
? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
|
|
99
97
|
: Record<string, string>)
|
|
100
98
|
>;
|
|
101
|
-
routes(builder: UrlBuilder<TEnv>):
|
|
99
|
+
routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
|
|
102
100
|
|
|
103
101
|
/**
|
|
104
102
|
* Add global middleware that runs on all routes
|
|
@@ -108,13 +106,18 @@ export interface RSCRouter<
|
|
|
108
106
|
* createRouter({ document: RootLayout })
|
|
109
107
|
* .use(loggerMiddleware) // All routes
|
|
110
108
|
* .use("/api/*", rateLimiter) // Pattern match
|
|
109
|
+
* .use("/users/:id", (ctx) => {}) // ctx.params.id is typed
|
|
111
110
|
* .routes(urlpatterns)
|
|
112
111
|
* ```
|
|
113
112
|
*/
|
|
113
|
+
use<Pattern extends string>(
|
|
114
|
+
pattern: Pattern,
|
|
115
|
+
middleware: MiddlewareFn<TEnv, ExtractParams<Pattern>>,
|
|
116
|
+
): Rango<TEnv, TRoutes>;
|
|
114
117
|
use(
|
|
115
118
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
116
119
|
middleware?: MiddlewareFn<TEnv>,
|
|
117
|
-
):
|
|
120
|
+
): Rango<TEnv, TRoutes>;
|
|
118
121
|
|
|
119
122
|
/**
|
|
120
123
|
* Type-safe URL builder for registered routes
|
|
@@ -141,7 +144,7 @@ export interface RSCRouter<
|
|
|
141
144
|
* type AppRoutes = typeof _router.routeMap;
|
|
142
145
|
*
|
|
143
146
|
* declare global {
|
|
144
|
-
* namespace
|
|
147
|
+
* namespace Rango {
|
|
145
148
|
* interface RegisteredRoutes extends AppRoutes {}
|
|
146
149
|
* }
|
|
147
150
|
* }
|
|
@@ -177,16 +180,16 @@ export interface RSCRouter<
|
|
|
177
180
|
}
|
|
178
181
|
|
|
179
182
|
/**
|
|
180
|
-
* Internal
|
|
183
|
+
* Internal Rango router interface — the full framework-facing API.
|
|
181
184
|
*
|
|
182
185
|
* This type includes all members used by the Vite plugin, RSC handler,
|
|
183
186
|
* pre-rendering pipeline, and other framework internals. It is NOT exported
|
|
184
187
|
* from the public package API.
|
|
185
188
|
*
|
|
186
|
-
* Use toInternal(router) to assert a public
|
|
189
|
+
* Use toInternal(router) to assert a public Rango into this type
|
|
187
190
|
* at the boundary where framework code receives a user-provided router.
|
|
188
191
|
*/
|
|
189
|
-
export interface
|
|
192
|
+
export interface RangoInternal<
|
|
190
193
|
TEnv = any,
|
|
191
194
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
192
195
|
> {
|
|
@@ -206,26 +209,36 @@ export interface RSCRouterInternal<
|
|
|
206
209
|
readonly basename: string | undefined;
|
|
207
210
|
|
|
208
211
|
/**
|
|
209
|
-
* Register routes using URL patterns from urls() or a builder function
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
* Register routes using URL patterns from urls() or a builder function.
|
|
213
|
+
*
|
|
214
|
+
* Env compatibility is checked by EnvCompatible: an env-agnostic urls() block
|
|
215
|
+
* (its env is `unknown` — e.g. a shared module, or an app that does not augment
|
|
216
|
+
* `Rango.Env`) attaches to any router, while a urls<TEnv>() block carrying a
|
|
217
|
+
* concrete env is accepted only when this router's `TEnv` satisfies it. So a
|
|
218
|
+
* `urls<{ DB }>()` cannot be mounted on a `createRouter<{}>()`.
|
|
219
|
+
*/
|
|
220
|
+
routes<T extends UrlPatterns<any, any, any>>(
|
|
221
|
+
patterns: T & EnvCompatible<T, TEnv>,
|
|
222
|
+
): Rango<
|
|
214
223
|
TEnv,
|
|
215
224
|
TRoutes &
|
|
216
225
|
(NonNullable<T["_routes"]> extends Record<string, unknown>
|
|
217
226
|
? MergeRoutesWithResponses<NonNullable<T["_routes"]>, T["_responses"]>
|
|
218
227
|
: Record<string, string>)
|
|
219
228
|
>;
|
|
220
|
-
routes(builder: UrlBuilder<TEnv>):
|
|
229
|
+
routes(builder: UrlBuilder<TEnv>): Rango<TEnv, TRoutes>;
|
|
221
230
|
|
|
222
231
|
/**
|
|
223
232
|
* Add global middleware that runs on all routes
|
|
224
233
|
*/
|
|
234
|
+
use<Pattern extends string>(
|
|
235
|
+
pattern: Pattern,
|
|
236
|
+
middleware: MiddlewareFn<TEnv, ExtractParams<Pattern>>,
|
|
237
|
+
): Rango<TEnv, TRoutes>;
|
|
225
238
|
use(
|
|
226
239
|
patternOrMiddleware: string | MiddlewareFn<TEnv>,
|
|
227
240
|
middleware?: MiddlewareFn<TEnv>,
|
|
228
|
-
):
|
|
241
|
+
): Rango<TEnv, TRoutes>;
|
|
229
242
|
|
|
230
243
|
/**
|
|
231
244
|
* Type-safe URL builder for registered routes
|
|
@@ -247,17 +260,17 @@ export interface RSCRouterInternal<
|
|
|
247
260
|
* Error callback for monitoring/alerting
|
|
248
261
|
* Called when errors occur in loaders, actions, or routes
|
|
249
262
|
*/
|
|
250
|
-
readonly onError?:
|
|
263
|
+
readonly onError?: RangoOptions<TEnv>["onError"];
|
|
251
264
|
|
|
252
265
|
/**
|
|
253
266
|
* Cache configuration
|
|
254
267
|
*/
|
|
255
|
-
readonly cache?:
|
|
268
|
+
readonly cache?: RangoOptions<TEnv>["cache"];
|
|
256
269
|
|
|
257
270
|
/**
|
|
258
271
|
* Not found component to render when no route matches
|
|
259
272
|
*/
|
|
260
|
-
readonly notFound?:
|
|
273
|
+
readonly notFound?: RangoOptions<TEnv>["notFound"];
|
|
261
274
|
|
|
262
275
|
/**
|
|
263
276
|
* Resolved theme configuration (null if theme not enabled)
|
|
@@ -287,6 +300,13 @@ export interface RSCRouterInternal<
|
|
|
287
300
|
*/
|
|
288
301
|
readonly prefetchCacheTTL: number;
|
|
289
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Resolved rango state cookie name (`{prefix}_{routerId}`), composed once at
|
|
305
|
+
* router init and shipped to the client in payload metadata. The server-side
|
|
306
|
+
* cookie writer reads it from here; the client reads it from metadata.
|
|
307
|
+
*/
|
|
308
|
+
readonly resolvedStateCookieName: string;
|
|
309
|
+
|
|
290
310
|
/**
|
|
291
311
|
* Whether connection warmup is enabled.
|
|
292
312
|
* When true, the client sends HEAD /?_rsc_warmup after idle periods
|
|
@@ -359,6 +379,17 @@ export interface RSCRouterInternal<
|
|
|
359
379
|
/** @internal basename for runtime manifest generation */
|
|
360
380
|
readonly __basename?: string;
|
|
361
381
|
|
|
382
|
+
/**
|
|
383
|
+
* @internal Router-level error/notFound fallbacks (`createRouter` options),
|
|
384
|
+
* exposed for the build-time clientChunks discovery so a `"use client"`
|
|
385
|
+
* default boundary is routed into the dedicated `app-fallback` chunk. Unlike
|
|
386
|
+
* the route-tree `errorBoundary()`/`notFoundBoundary()` helpers these never
|
|
387
|
+
* land in `EntryData`, so they are read directly off the router instance.
|
|
388
|
+
*/
|
|
389
|
+
readonly __defaultErrorBoundary?: RangoOptions<TEnv>["defaultErrorBoundary"];
|
|
390
|
+
readonly __defaultNotFoundBoundary?: RangoOptions<TEnv>["defaultNotFoundBoundary"];
|
|
391
|
+
readonly __notFound?: RangoOptions<TEnv>["notFound"];
|
|
392
|
+
|
|
362
393
|
match(
|
|
363
394
|
request: Request,
|
|
364
395
|
input?: RouterRequestInput<TEnv>,
|
|
@@ -378,11 +409,13 @@ export interface RSCRouterInternal<
|
|
|
378
409
|
devMode?: boolean,
|
|
379
410
|
): Promise<{
|
|
380
411
|
segments: SerializedSegmentData[];
|
|
381
|
-
|
|
412
|
+
/** RSC-encoded handle map ("" when none) — see handle-snapshot.ts. */
|
|
413
|
+
handles: string;
|
|
382
414
|
routeName: string;
|
|
383
415
|
params: Record<string, string>;
|
|
384
416
|
interceptSegments?: SerializedSegmentData[];
|
|
385
|
-
|
|
417
|
+
/** RSC-encoded MERGED (main + intercept) handle map for the intercept artifact. */
|
|
418
|
+
interceptHandles?: string;
|
|
386
419
|
passthrough?: true;
|
|
387
420
|
} | null>;
|
|
388
421
|
|
|
@@ -396,7 +429,7 @@ export interface RSCRouterInternal<
|
|
|
396
429
|
routeName?: string,
|
|
397
430
|
buildEnv?: any,
|
|
398
431
|
devMode?: boolean,
|
|
399
|
-
): Promise<{ encoded: string; handles:
|
|
432
|
+
): Promise<{ encoded: string; handles: string } | null>;
|
|
400
433
|
|
|
401
434
|
/**
|
|
402
435
|
* Preview match - returns route middleware without segment resolution.
|
|
@@ -469,16 +502,16 @@ export interface RSCRouterInternal<
|
|
|
469
502
|
}
|
|
470
503
|
|
|
471
504
|
/**
|
|
472
|
-
* Assert a public
|
|
505
|
+
* Assert a public Rango into the internal type.
|
|
473
506
|
*
|
|
474
507
|
* Use this at the boundary where framework code receives a user-provided
|
|
475
508
|
* router and needs access to internal members (match, config, build-time).
|
|
476
509
|
* The cast is safe because createRouter() always produces an object that
|
|
477
|
-
* satisfies
|
|
510
|
+
* satisfies RangoInternal; the public type is just a narrower view.
|
|
478
511
|
*/
|
|
479
512
|
export function toInternal<
|
|
480
513
|
TEnv = any,
|
|
481
514
|
TRoutes extends Record<string, unknown> = Record<string, string>,
|
|
482
|
-
>(router:
|
|
483
|
-
return router as
|
|
515
|
+
>(router: Rango<TEnv, TRoutes>): RangoInternal<TEnv, TRoutes> {
|
|
516
|
+
return router as RangoInternal<TEnv, TRoutes>;
|
|
484
517
|
}
|
|
@@ -73,7 +73,7 @@ export interface RootLayoutProps {
|
|
|
73
73
|
/**
|
|
74
74
|
* Router configuration options
|
|
75
75
|
*/
|
|
76
|
-
export interface
|
|
76
|
+
export interface RangoOptions<TEnv = any> {
|
|
77
77
|
/**
|
|
78
78
|
* Unique identifier for this router instance.
|
|
79
79
|
* Used to namespace static output files and route maps.
|
|
@@ -132,6 +132,21 @@ export interface RSCRouterOptions<TEnv = any> {
|
|
|
132
132
|
*/
|
|
133
133
|
allowDebugManifest?: boolean;
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* DEVELOPMENT/TEST ONLY. Emit an `X-Rango-Cache` response header describing
|
|
137
|
+
* the cache status of the matched route, for use by testing primitives such
|
|
138
|
+
* as `assertCacheStatus`.
|
|
139
|
+
*
|
|
140
|
+
* Defaults to `false`. When neither this option nor the
|
|
141
|
+
* `RANGO_TEST_SIGNALS=1` environment flag is set, NO header is emitted and
|
|
142
|
+
* router output is byte-identical to the default.
|
|
143
|
+
*
|
|
144
|
+
* The header encodes per-segment (v1: coarse route-level) status keyed by the
|
|
145
|
+
* route NAME, e.g. `X-Rango-Cache: product.detail=hit`. Do NOT enable in
|
|
146
|
+
* production — it exposes internal cache decisions.
|
|
147
|
+
*/
|
|
148
|
+
debugCacheSignal?: boolean;
|
|
149
|
+
|
|
135
150
|
/**
|
|
136
151
|
* Document component that wraps the entire application.
|
|
137
152
|
*
|
|
@@ -357,6 +372,30 @@ export interface RSCRouterOptions<TEnv = any> {
|
|
|
357
372
|
*/
|
|
358
373
|
theme?: import("../theme/types.js").ThemeConfig | true;
|
|
359
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Default for whether the router wraps `transition()` segments in its own
|
|
377
|
+
* React `<ViewTransition>` boundary (experimental React only).
|
|
378
|
+
*
|
|
379
|
+
* - "auto" (default): every route/layout that opts in via `transition()`
|
|
380
|
+
* gets a router-owned cross-fade.
|
|
381
|
+
* - false: the router never places its own boundary. Routes that use
|
|
382
|
+
* `transition()` still drive navigation through startTransition (so loaders
|
|
383
|
+
* hold instead of flashing a skeleton) and still let consumer-placed
|
|
384
|
+
* `<ViewTransition>` elements animate — the router just contributes no
|
|
385
|
+
* cross-fade of its own. This is the "router triggers, you place the
|
|
386
|
+
* transitions" model.
|
|
387
|
+
*
|
|
388
|
+
* A per-segment `transition({ viewTransition })` overrides this default.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```typescript
|
|
392
|
+
* // App-wide: drive + hold, but never auto-wrap. Place <ViewTransition>
|
|
393
|
+
* // yourself in components where you want a morph.
|
|
394
|
+
* const router = createRouter<AppEnv>({ viewTransition: false });
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
viewTransition?: "auto" | false;
|
|
398
|
+
|
|
360
399
|
/**
|
|
361
400
|
* URL patterns to register with the router.
|
|
362
401
|
*
|
|
@@ -457,6 +496,21 @@ export interface RSCRouterOptions<TEnv = any> {
|
|
|
457
496
|
*/
|
|
458
497
|
prefetchCacheTTL?: number | false;
|
|
459
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Prefix for the rango state cookie name. The resolved name is
|
|
501
|
+
* `{prefix}_{routerId}`; the prefix is sanitized to cookie-name-safe
|
|
502
|
+
* characters (`[A-Za-z0-9-]`) and an empty result falls back to the default.
|
|
503
|
+
*
|
|
504
|
+
* The rango state cookie keys the client's prefetch / HTTP caches. Overriding
|
|
505
|
+
* the prefix lets you align it with cookie-naming policies or consent-manager
|
|
506
|
+
* classification lists, or avoid colliding with an existing `rango-state`
|
|
507
|
+
* cookie. It is not a full-name override: the `_{routerId}` suffix is what
|
|
508
|
+
* keeps sibling apps on one origin from clobbering each other's state.
|
|
509
|
+
*
|
|
510
|
+
* @default "rango-state"
|
|
511
|
+
*/
|
|
512
|
+
stateCookiePrefix?: string;
|
|
513
|
+
|
|
460
514
|
/**
|
|
461
515
|
* Enable connection warmup to keep TCP+TLS alive after idle periods.
|
|
462
516
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RangoInternal } from "./router-interfaces.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Brand marker for identifying router instances at build time.
|
|
@@ -12,10 +12,7 @@ export const RSC_ROUTER_BRAND = "__rsc_router__" as const;
|
|
|
12
12
|
* Used by the Vite plugin at build time to discover routers and extract
|
|
13
13
|
* manifests, prefix trees, and pre-render candidates.
|
|
14
14
|
*/
|
|
15
|
-
export const RouterRegistry: Map<
|
|
16
|
-
string,
|
|
17
|
-
RSCRouterInternal<any, any>
|
|
18
|
-
> = new Map();
|
|
15
|
+
export const RouterRegistry: Map<string, RangoInternal<any, any>> = new Map();
|
|
19
16
|
|
|
20
17
|
export let routerAutoId = 0;
|
|
21
18
|
|
|
@@ -27,58 +27,17 @@ import {
|
|
|
27
27
|
tryStaticSlot,
|
|
28
28
|
resolveLayoutComponent,
|
|
29
29
|
resolveWithErrorBoundary,
|
|
30
|
+
warnOnStreamedResponse,
|
|
30
31
|
} from "./helpers.js";
|
|
32
|
+
import { applyViewTransitionDefault } from "./view-transition-default.js";
|
|
31
33
|
import { getRouterContext } from "../router-context.js";
|
|
32
|
-
import {
|
|
34
|
+
import { observeStreamedHandler } from "./streamed-handler-telemetry.js";
|
|
33
35
|
import {
|
|
34
36
|
track,
|
|
35
|
-
|
|
37
|
+
RangoContext,
|
|
36
38
|
runInsideLoaderScope,
|
|
37
39
|
} from "../../server/context.js";
|
|
38
40
|
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// Streamed handler telemetry
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Attach a fire-and-forget rejection observer to a streamed handler promise.
|
|
45
|
-
* React catches the actual error via its error boundary; this only emits
|
|
46
|
-
* the handler.error telemetry event.
|
|
47
|
-
*/
|
|
48
|
-
function observeStreamedHandler(
|
|
49
|
-
promise: Promise<ReactNode>,
|
|
50
|
-
segmentId: string,
|
|
51
|
-
segmentType: string,
|
|
52
|
-
pathname?: string,
|
|
53
|
-
routeKey?: string,
|
|
54
|
-
params?: Record<string, string>,
|
|
55
|
-
): void {
|
|
56
|
-
let routerCtx;
|
|
57
|
-
try {
|
|
58
|
-
routerCtx = getRouterContext();
|
|
59
|
-
} catch {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (!routerCtx?.telemetry) return;
|
|
63
|
-
const sink = resolveSink(routerCtx.telemetry);
|
|
64
|
-
const reqId = routerCtx.requestId;
|
|
65
|
-
promise.catch((err: unknown) => {
|
|
66
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
67
|
-
safeEmit(sink, {
|
|
68
|
-
type: "handler.error",
|
|
69
|
-
timestamp: performance.now(),
|
|
70
|
-
requestId: reqId,
|
|
71
|
-
segmentId,
|
|
72
|
-
segmentType,
|
|
73
|
-
error: errorObj,
|
|
74
|
-
handledByBoundary: true,
|
|
75
|
-
pathname,
|
|
76
|
-
routeKey,
|
|
77
|
-
params,
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
41
|
// ---------------------------------------------------------------------------
|
|
83
42
|
// Fresh path (full match, no revalidation)
|
|
84
43
|
// ---------------------------------------------------------------------------
|
|
@@ -132,18 +91,32 @@ export async function resolveLoaders<TEnv>(
|
|
|
132
91
|
|
|
133
92
|
// Loading disabled: still start all loaders in parallel, but only emit
|
|
134
93
|
// settled promises so handlers don't stream loading placeholders.
|
|
135
|
-
|
|
94
|
+
//
|
|
95
|
+
// Wrap each loader promise with wrapLoaderPromise BEFORE awaiting. The wrapped
|
|
96
|
+
// promise resolves to a LoaderDataResult and never rejects, routing a failed
|
|
97
|
+
// loader to its own per-loader error boundary. Awaiting the RAW promises here
|
|
98
|
+
// instead would (1) propagate a rejection to the segment-level boundary,
|
|
99
|
+
// collapsing the whole entry and discarding successful sibling data, and
|
|
100
|
+
// (2) leave the other in-flight raw promises without a .catch, producing
|
|
101
|
+
// unhandled rejections. Mirrors the loading path and intercept-resolution.
|
|
102
|
+
const pendingLoaderData = loaderEntries.map((loaderEntry, i) => {
|
|
103
|
+
const { loader } = loaderEntry;
|
|
104
|
+
const segmentId = `${shortCode}D${i}.${loader.$$id}`;
|
|
136
105
|
const start = performance.now();
|
|
137
|
-
const
|
|
138
|
-
|
|
106
|
+
const wrapped = deps.wrapLoaderPromise(
|
|
107
|
+
runInsideLoaderScope(() =>
|
|
108
|
+
resolveLoaderData(loaderEntry, ctx, ctx.pathname),
|
|
109
|
+
),
|
|
110
|
+
entry,
|
|
111
|
+
segmentId,
|
|
112
|
+
ctx.pathname,
|
|
139
113
|
);
|
|
140
|
-
return {
|
|
114
|
+
return { wrapped, start, segmentId, loaderId: loader.$$id };
|
|
141
115
|
});
|
|
142
|
-
await Promise.all(pendingLoaderData.map((p) => p.
|
|
116
|
+
await Promise.all(pendingLoaderData.map((p) => p.wrapped));
|
|
143
117
|
|
|
144
118
|
return loaderEntries.map((loaderEntry, i) => {
|
|
145
119
|
const { loader } = loaderEntry;
|
|
146
|
-
const segmentId = `${shortCode}D${i}.${loader.$$id}`;
|
|
147
120
|
const pending = pendingLoaderData[i]!;
|
|
148
121
|
if (ms && !ms.metrics.some((m) => m.label === `loader:${loader.$$id}`)) {
|
|
149
122
|
// All loaders ran in parallel via Promise.all — each span covers
|
|
@@ -159,19 +132,14 @@ export async function resolveLoaders<TEnv>(
|
|
|
159
132
|
);
|
|
160
133
|
}
|
|
161
134
|
return {
|
|
162
|
-
id: segmentId,
|
|
135
|
+
id: pending.segmentId,
|
|
163
136
|
namespace: entry.id,
|
|
164
137
|
type: "loader" as const,
|
|
165
138
|
index: i,
|
|
166
139
|
component: null,
|
|
167
140
|
params: ctx.params,
|
|
168
141
|
loaderId: loader.$$id,
|
|
169
|
-
loaderData:
|
|
170
|
-
pending.promise,
|
|
171
|
-
entry,
|
|
172
|
-
segmentId,
|
|
173
|
-
ctx.pathname,
|
|
174
|
-
),
|
|
142
|
+
loaderData: pending.wrapped,
|
|
175
143
|
belongsToRoute,
|
|
176
144
|
};
|
|
177
145
|
});
|
|
@@ -224,7 +192,10 @@ export async function resolveSegment<TEnv>(
|
|
|
224
192
|
index: 0,
|
|
225
193
|
component,
|
|
226
194
|
loading: entry.loading === false ? null : entry.loading,
|
|
227
|
-
transition:
|
|
195
|
+
transition: applyViewTransitionDefault(
|
|
196
|
+
entry.transition,
|
|
197
|
+
deps.viewTransitionDefault,
|
|
198
|
+
),
|
|
228
199
|
params,
|
|
229
200
|
belongsToRoute: false,
|
|
230
201
|
layoutName: entry.id,
|
|
@@ -293,6 +264,7 @@ export async function resolveSegment<TEnv>(
|
|
|
293
264
|
if (entry.loading) {
|
|
294
265
|
const result = handleHandlerResult(handler(context));
|
|
295
266
|
if (result instanceof Promise) {
|
|
267
|
+
warnOnStreamedResponse(result, entry.id);
|
|
296
268
|
result.finally(doneRouteHandler).catch(() => {});
|
|
297
269
|
const tracked = deps.trackHandler(result, {
|
|
298
270
|
segmentId: entry.shortCode,
|
|
@@ -359,7 +331,10 @@ export async function resolveSegment<TEnv>(
|
|
|
359
331
|
index: 0,
|
|
360
332
|
component: component ?? null,
|
|
361
333
|
loading: entry.loading === false ? null : entry.loading,
|
|
362
|
-
transition:
|
|
334
|
+
transition: applyViewTransitionDefault(
|
|
335
|
+
entry.transition,
|
|
336
|
+
deps.viewTransitionDefault,
|
|
337
|
+
),
|
|
363
338
|
params,
|
|
364
339
|
belongsToRoute: true,
|
|
365
340
|
...(entry.mountPath ? { mountPath: entry.mountPath } : {}),
|
|
@@ -443,7 +418,10 @@ export async function resolveOrphanLayout<TEnv>(
|
|
|
443
418
|
belongsToRoute,
|
|
444
419
|
layoutName: orphan.id,
|
|
445
420
|
loading: orphan.loading === false ? null : orphan.loading,
|
|
446
|
-
transition:
|
|
421
|
+
transition: applyViewTransitionDefault(
|
|
422
|
+
orphan.transition,
|
|
423
|
+
deps.viewTransitionDefault,
|
|
424
|
+
),
|
|
447
425
|
...(orphan.mountPath ? { mountPath: orphan.mountPath } : {}),
|
|
448
426
|
});
|
|
449
427
|
|
|
@@ -565,7 +543,10 @@ export async function resolveParallelEntry<TEnv>(
|
|
|
565
543
|
index: 0,
|
|
566
544
|
component,
|
|
567
545
|
loading: parallelEntry.loading === false ? null : parallelEntry.loading,
|
|
568
|
-
transition:
|
|
546
|
+
transition: applyViewTransitionDefault(
|
|
547
|
+
parallelEntry.transition,
|
|
548
|
+
deps.viewTransitionDefault,
|
|
549
|
+
),
|
|
569
550
|
params,
|
|
570
551
|
slot,
|
|
571
552
|
belongsToRoute,
|
|
@@ -632,7 +613,7 @@ export async function resolveAllSegments<TEnv>(
|
|
|
632
613
|
// can guard non-cacheable variable reads. Also guards response-level
|
|
633
614
|
// side effects (headers.set). Persists for all descendant entries.
|
|
634
615
|
if (entry.type === "cache") {
|
|
635
|
-
const store =
|
|
616
|
+
const store = RangoContext.getStore();
|
|
636
617
|
if (store) store.insideCacheScope = true;
|
|
637
618
|
}
|
|
638
619
|
const doneEntry = track(`segment:${entry.id}`, 1);
|
|
@@ -52,6 +52,40 @@ export function handleHandlerResult(
|
|
|
52
52
|
return result;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Dev-only: warn when a handler on a route that declares loading() resolves or
|
|
57
|
+
* rejects with a Response (e.g. redirect()).
|
|
58
|
+
*
|
|
59
|
+
* On a non-loading route a returned/thrown Response short-circuits to an HTTP
|
|
60
|
+
* redirect. But when the route declares loading(), the handler result is
|
|
61
|
+
* streamed (not awaited at the resolution boundary), so the Response surfaces
|
|
62
|
+
* only during RSC serialization and is rendered into the stream instead of
|
|
63
|
+
* becoming a 302/308 — a silent failure mode. Issue redirects from middleware,
|
|
64
|
+
* a loader, or a synchronous handler return instead. Compiled out in production.
|
|
65
|
+
*/
|
|
66
|
+
export function warnOnStreamedResponse(
|
|
67
|
+
result: Promise<unknown>,
|
|
68
|
+
entryId: string,
|
|
69
|
+
): void {
|
|
70
|
+
if (process.env.NODE_ENV === "production") return;
|
|
71
|
+
// A Response can surface either as a rejection (handleHandlerResult rethrows a
|
|
72
|
+
// resolved Response) or as a resolved value (the raw parallel-slot handler is
|
|
73
|
+
// not run through handleHandlerResult). Check both so every streamed path is
|
|
74
|
+
// covered. Each handler is an independent observer; it does not consume the
|
|
75
|
+
// rejection for the trackHandler/observeStreamedHandler chains.
|
|
76
|
+
const check = (value: unknown) => {
|
|
77
|
+
if (value instanceof Response) {
|
|
78
|
+
console.warn(
|
|
79
|
+
`[rango] Handler for "${entryId}" returned a Response (e.g. ` +
|
|
80
|
+
`redirect()), but it declares loading(): the Response is rendered ` +
|
|
81
|
+
`into the RSC stream, NOT sent as an HTTP redirect. Issue redirects ` +
|
|
82
|
+
`from middleware, a loader, or a synchronous handler return.`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
result.then(check, check);
|
|
87
|
+
}
|
|
88
|
+
|
|
55
89
|
// ---------------------------------------------------------------------------
|
|
56
90
|
// Static handler interception
|
|
57
91
|
// ---------------------------------------------------------------------------
|