@rangojs/router 0.0.0-experimental.002d056c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -0
- package/README.md +899 -0
- package/dist/bin/rango.js +1606 -0
- package/dist/vite/index.js +5153 -0
- package/package.json +177 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +253 -0
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +182 -0
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +704 -0
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +313 -0
- package/skills/layout/SKILL.md +310 -0
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +596 -0
- package/skills/middleware/SKILL.md +339 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +305 -0
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +118 -0
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +385 -0
- package/skills/router-setup/SKILL.md +439 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +79 -0
- package/skills/typesafety/SKILL.md +623 -0
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +273 -0
- 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 +899 -0
- package/src/browser/history-state.ts +80 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +141 -0
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +134 -0
- package/src/browser/navigation-bridge.ts +638 -0
- package/src/browser/navigation-client.ts +261 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +582 -0
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +145 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +368 -0
- package/src/browser/react/NavigationProvider.tsx +413 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +59 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +162 -0
- package/src/browser/react/location-state.ts +107 -0
- package/src/browser/react/mount-context.ts +37 -0
- 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 +218 -0
- package/src/browser/react/use-client-cache.ts +58 -0
- package/src/browser/react/use-handle.ts +162 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +135 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +99 -0
- 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 +171 -0
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +464 -0
- package/src/browser/scroll-restoration.ts +397 -0
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +667 -0
- package/src/browser/shallow.ts +40 -0
- package/src/browser/types.ts +547 -0
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -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 +479 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +382 -0
- package/src/cache/cf/cf-cache-store.ts +982 -0
- package/src/cache/cf/index.ts +29 -0
- package/src/cache/document-cache.ts +369 -0
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +44 -0
- package/src/cache/memory-segment-store.ts +328 -0
- 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 +342 -0
- package/src/client.rsc.tsx +85 -0
- package/src/client.tsx +601 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +27 -0
- package/src/context-var.ts +86 -0
- package/src/debug.ts +243 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +365 -0
- package/src/handle.ts +135 -0
- package/src/handles/MetaTags.tsx +246 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +7 -0
- package/src/handles/meta.ts +264 -0
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +222 -0
- package/src/index.rsc.ts +233 -0
- package/src/index.ts +277 -0
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +89 -0
- package/src/loader.ts +64 -0
- package/src/network-error-thrower.tsx +23 -0
- package/src/outlet-context.ts +15 -0
- 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 +289 -0
- package/src/route-content-wrapper.tsx +196 -0
- 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 -0
- package/src/route-map-builder.ts +281 -0
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +259 -0
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +397 -0
- package/src/router/lazy-includes.ts +236 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +269 -0
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +266 -0
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +223 -0
- package/src/router/match-middleware/cache-lookup.ts +634 -0
- package/src/router/match-middleware/cache-store.ts +295 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +306 -0
- package/src/router/match-middleware/segment-resolution.ts +193 -0
- package/src/router/match-pipelines.ts +179 -0
- package/src/router/match-result.ts +219 -0
- package/src/router/metrics.ts +282 -0
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +749 -0
- package/src/router/pattern-matching.ts +563 -0
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +289 -0
- package/src/router/router-context.ts +320 -0
- 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 +1242 -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 +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +170 -0
- package/src/router.ts +1006 -0
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +1089 -0
- package/src/rsc/helpers.ts +198 -0
- package/src/rsc/index.ts +36 -0
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +32 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +263 -0
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +454 -0
- package/src/server/context.ts +591 -0
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +308 -0
- package/src/server/loader-registry.ts +133 -0
- package/src/server/request-context.ts +920 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +51 -0
- package/src/ssr/index.tsx +365 -0
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +297 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +62 -0
- package/src/theme/index.ts +48 -0
- package/src/theme/theme-context.ts +44 -0
- package/src/theme/theme-script.ts +155 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- 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 +109 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -0
- 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 -0
- package/src/use-loader.tsx +354 -0
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +16 -0
- package/src/vite/plugin-types.ts +48 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/plugins/expose-action-id.ts +363 -0
- 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 +266 -0
- package/src/vite/plugins/version.d.ts +12 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/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/utils/package-resolution.ts +121 -0
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NavigationClient,
|
|
3
|
+
FetchPartialOptions,
|
|
4
|
+
FetchPartialResult,
|
|
5
|
+
RscPayload,
|
|
6
|
+
RscBrowserDependencies,
|
|
7
|
+
} from "./types.js";
|
|
8
|
+
import { NetworkError, ServerRedirect, isNetworkError } from "../errors.js";
|
|
9
|
+
import {
|
|
10
|
+
browserDebugLog,
|
|
11
|
+
isBrowserDebugEnabled,
|
|
12
|
+
startBrowserTransaction,
|
|
13
|
+
} from "./logging.js";
|
|
14
|
+
import { getRangoState } from "./rango-state.js";
|
|
15
|
+
import {
|
|
16
|
+
extractRscHeaderUrl,
|
|
17
|
+
emptyResponse,
|
|
18
|
+
teeWithCompletion,
|
|
19
|
+
} from "./response-adapter.js";
|
|
20
|
+
import {
|
|
21
|
+
buildPrefetchKey,
|
|
22
|
+
consumePrefetch,
|
|
23
|
+
consumeInflightPrefetch,
|
|
24
|
+
} from "./prefetch/cache.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a navigation client for fetching RSC payloads
|
|
28
|
+
*
|
|
29
|
+
* The client handles building URLs with RSC parameters and
|
|
30
|
+
* deserializing the response using the RSC runtime.
|
|
31
|
+
*
|
|
32
|
+
* Checks the in-memory prefetch cache before making a network request.
|
|
33
|
+
* The cache key is source-dependent (includes the previous URL) so
|
|
34
|
+
* prefetch responses match the exact diff the server would produce.
|
|
35
|
+
*
|
|
36
|
+
* @param deps - RSC browser dependencies (createFromFetch)
|
|
37
|
+
* @returns NavigationClient instance
|
|
38
|
+
*/
|
|
39
|
+
export function createNavigationClient(
|
|
40
|
+
deps: Pick<RscBrowserDependencies, "createFromFetch">,
|
|
41
|
+
): NavigationClient {
|
|
42
|
+
return {
|
|
43
|
+
/**
|
|
44
|
+
* Fetch a partial RSC payload for navigation
|
|
45
|
+
*
|
|
46
|
+
* First checks the in-memory prefetch cache for a matching entry.
|
|
47
|
+
* If found, uses the cached response instantly. Otherwise sends
|
|
48
|
+
* current segment IDs to the server for diff-based rendering.
|
|
49
|
+
*
|
|
50
|
+
* @param options - Fetch options
|
|
51
|
+
* @returns RSC payload with segments and metadata, plus stream completion promise
|
|
52
|
+
*/
|
|
53
|
+
async fetchPartial(
|
|
54
|
+
options: FetchPartialOptions,
|
|
55
|
+
): Promise<FetchPartialResult> {
|
|
56
|
+
const {
|
|
57
|
+
targetUrl,
|
|
58
|
+
segmentIds,
|
|
59
|
+
previousUrl,
|
|
60
|
+
signal,
|
|
61
|
+
staleRevalidation,
|
|
62
|
+
interceptSourceUrl,
|
|
63
|
+
version,
|
|
64
|
+
hmr,
|
|
65
|
+
} = options;
|
|
66
|
+
|
|
67
|
+
const debugEnabled = isBrowserDebugEnabled();
|
|
68
|
+
const tx = debugEnabled
|
|
69
|
+
? startBrowserTransaction(staleRevalidation ? "revalidate" : "navigate")
|
|
70
|
+
: null;
|
|
71
|
+
if (tx) {
|
|
72
|
+
browserDebugLog(tx, "request start", {
|
|
73
|
+
from: previousUrl,
|
|
74
|
+
to: targetUrl,
|
|
75
|
+
segments: segmentIds,
|
|
76
|
+
staleRevalidation: !!staleRevalidation,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Build fetch URL with partial rendering params (used for both
|
|
81
|
+
// cache key lookup and actual fetch if cache misses)
|
|
82
|
+
const fetchUrl = new URL(targetUrl, window.location.origin);
|
|
83
|
+
fetchUrl.searchParams.set("_rsc_partial", "true");
|
|
84
|
+
fetchUrl.searchParams.set("_rsc_segments", segmentIds.join(","));
|
|
85
|
+
if (staleRevalidation) {
|
|
86
|
+
fetchUrl.searchParams.set("_rsc_stale", "true");
|
|
87
|
+
}
|
|
88
|
+
if (version) {
|
|
89
|
+
fetchUrl.searchParams.set("_rsc_v", version);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check in-memory prefetch cache before making a network request.
|
|
93
|
+
// The cache key includes the source URL (previousUrl) because the
|
|
94
|
+
// server's diff response depends on the source page context.
|
|
95
|
+
// Skip cache for stale revalidation (needs fresh data), HMR (needs
|
|
96
|
+
// fresh modules), and intercept contexts (source-dependent responses).
|
|
97
|
+
const canUsePrefetch = !staleRevalidation && !hmr && !interceptSourceUrl;
|
|
98
|
+
const cacheKey = buildPrefetchKey(previousUrl, fetchUrl);
|
|
99
|
+
const cachedResponse = canUsePrefetch ? consumePrefetch(cacheKey) : null;
|
|
100
|
+
// If no completed cache entry, check for in-flight prefetch.
|
|
101
|
+
// This reuses a prefetch that is still downloading rather than
|
|
102
|
+
// starting a duplicate request from scratch.
|
|
103
|
+
const inflightPrefetch =
|
|
104
|
+
!cachedResponse && canUsePrefetch
|
|
105
|
+
? consumeInflightPrefetch(cacheKey)
|
|
106
|
+
: null;
|
|
107
|
+
|
|
108
|
+
// Track when the stream completes
|
|
109
|
+
let resolveStreamComplete: () => void;
|
|
110
|
+
const streamComplete = new Promise<void>((resolve) => {
|
|
111
|
+
resolveStreamComplete = resolve;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/** Start a fresh navigation fetch (no cache / inflight hit). */
|
|
115
|
+
const doFreshFetch = (): Promise<Response> => {
|
|
116
|
+
if (tx) {
|
|
117
|
+
browserDebugLog(tx, "fetching", {
|
|
118
|
+
path: `${fetchUrl.pathname}${fetchUrl.search}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return fetch(fetchUrl, {
|
|
123
|
+
headers: {
|
|
124
|
+
"X-RSC-Router-Client-Path": previousUrl,
|
|
125
|
+
"X-Rango-State": getRangoState(),
|
|
126
|
+
...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
|
|
127
|
+
...(interceptSourceUrl && {
|
|
128
|
+
"X-RSC-Router-Intercept-Source": interceptSourceUrl,
|
|
129
|
+
}),
|
|
130
|
+
...(hmr && { "X-RSC-HMR": "1" }),
|
|
131
|
+
},
|
|
132
|
+
signal,
|
|
133
|
+
}).then((response) => {
|
|
134
|
+
// Check for version mismatch - server wants us to reload
|
|
135
|
+
const reload = extractRscHeaderUrl(response, "X-RSC-Reload");
|
|
136
|
+
if (reload === "blocked") {
|
|
137
|
+
resolveStreamComplete();
|
|
138
|
+
return emptyResponse();
|
|
139
|
+
}
|
|
140
|
+
if (reload) {
|
|
141
|
+
if (tx) {
|
|
142
|
+
browserDebugLog(tx, "version mismatch, reloading", {
|
|
143
|
+
reloadUrl: reload.url,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
window.location.href = reload.url;
|
|
147
|
+
return new Promise<Response>(() => {});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Server-side redirect without state: the server returned 204 with
|
|
151
|
+
// X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
|
|
152
|
+
// to a URL rendering full HTML). Throw ServerRedirect so the
|
|
153
|
+
// navigation bridge catches it and re-navigates with _skipCache.
|
|
154
|
+
const redirect = extractRscHeaderUrl(response, "X-RSC-Redirect");
|
|
155
|
+
if (redirect === "blocked") {
|
|
156
|
+
resolveStreamComplete();
|
|
157
|
+
return emptyResponse();
|
|
158
|
+
}
|
|
159
|
+
if (redirect) {
|
|
160
|
+
if (tx) {
|
|
161
|
+
browserDebugLog(tx, "server redirect", {
|
|
162
|
+
redirectUrl: redirect.url,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
resolveStreamComplete();
|
|
166
|
+
throw new ServerRedirect(redirect.url, undefined);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return teeWithCompletion(
|
|
170
|
+
response,
|
|
171
|
+
() => {
|
|
172
|
+
if (tx) browserDebugLog(tx, "stream complete");
|
|
173
|
+
resolveStreamComplete();
|
|
174
|
+
},
|
|
175
|
+
signal,
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
let responsePromise: Promise<Response>;
|
|
181
|
+
|
|
182
|
+
if (cachedResponse) {
|
|
183
|
+
if (tx) {
|
|
184
|
+
browserDebugLog(tx, "prefetch cache hit", { key: cacheKey });
|
|
185
|
+
}
|
|
186
|
+
// Cached response body is already fully buffered (arrayBuffer),
|
|
187
|
+
// so stream completion is immediate.
|
|
188
|
+
responsePromise = Promise.resolve(cachedResponse).then((response) => {
|
|
189
|
+
return teeWithCompletion(
|
|
190
|
+
response,
|
|
191
|
+
() => {
|
|
192
|
+
if (tx) browserDebugLog(tx, "stream complete (from cache)");
|
|
193
|
+
resolveStreamComplete();
|
|
194
|
+
},
|
|
195
|
+
signal,
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
} else if (inflightPrefetch) {
|
|
199
|
+
if (tx) {
|
|
200
|
+
browserDebugLog(tx, "reusing inflight prefetch", { key: cacheKey });
|
|
201
|
+
}
|
|
202
|
+
// Await the in-flight prefetch. If it resolves with a Response,
|
|
203
|
+
// use it like a cache hit. If it fails (null), fall back to
|
|
204
|
+
// a fresh navigation fetch.
|
|
205
|
+
responsePromise = inflightPrefetch.then((prefetchResponse) => {
|
|
206
|
+
if (!prefetchResponse) {
|
|
207
|
+
if (tx) {
|
|
208
|
+
browserDebugLog(
|
|
209
|
+
tx,
|
|
210
|
+
"inflight prefetch failed, falling back to fetch",
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
return doFreshFetch();
|
|
214
|
+
}
|
|
215
|
+
if (tx) {
|
|
216
|
+
browserDebugLog(tx, "inflight prefetch resolved", {
|
|
217
|
+
key: cacheKey,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return teeWithCompletion(
|
|
221
|
+
prefetchResponse,
|
|
222
|
+
() => {
|
|
223
|
+
if (tx)
|
|
224
|
+
browserDebugLog(tx, "stream complete (from inflight prefetch)");
|
|
225
|
+
resolveStreamComplete();
|
|
226
|
+
},
|
|
227
|
+
signal,
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
} else {
|
|
231
|
+
responsePromise = doFreshFetch();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Deserialize RSC payload
|
|
236
|
+
const payload = await deps.createFromFetch<RscPayload>(responsePromise);
|
|
237
|
+
if (tx) {
|
|
238
|
+
browserDebugLog(tx, "response received", {
|
|
239
|
+
isPartial: payload.metadata?.isPartial,
|
|
240
|
+
matchedCount: payload.metadata?.matched?.length ?? 0,
|
|
241
|
+
diffCount: payload.metadata?.diff?.length ?? 0,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return { payload, streamComplete };
|
|
245
|
+
} catch (error) {
|
|
246
|
+
// Convert network-level errors to NetworkError for proper handling
|
|
247
|
+
if (isNetworkError(error)) {
|
|
248
|
+
throw new NetworkError(
|
|
249
|
+
"Unable to connect to server. Please check your connection.",
|
|
250
|
+
{
|
|
251
|
+
cause: error,
|
|
252
|
+
url: fetchUrl.toString(),
|
|
253
|
+
operation: staleRevalidation ? "revalidation" : "navigation",
|
|
254
|
+
},
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|