@rangojs/router 0.20.0 → 0.22.0
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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +29 -4
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/build-shell-capture.d.ts +8 -6
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +12 -6
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/build-shell-capture.ts +11 -9
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -92,15 +92,25 @@
|
|
|
92
92
|
* - Action context (if POST)
|
|
93
93
|
*/
|
|
94
94
|
import type { InternalHandlerContext, ResolvedSegment } from "../../types.js";
|
|
95
|
-
import type
|
|
96
|
-
import type { EntryData } from "../../server/context.js";
|
|
95
|
+
import { isPprEntry, type EntryData } from "../../server/context.js";
|
|
97
96
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
98
97
|
import { getRouterContext, type RouterContext } from "../router-context.js";
|
|
99
98
|
import { observeEvent } from "../instrument.js";
|
|
100
99
|
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
101
100
|
import { treeHasStreaming } from "./segment-resolution.js";
|
|
102
|
-
import {
|
|
101
|
+
import { loaderPins } from "../segment-resolution/loader-cache.js";
|
|
103
102
|
import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
|
|
103
|
+
import {
|
|
104
|
+
isStoredEntryStale,
|
|
105
|
+
readVerifiedStoredEntry,
|
|
106
|
+
serializePrerenderKey,
|
|
107
|
+
type PrerenderKey,
|
|
108
|
+
} from "../../prerender/writable-store.js";
|
|
109
|
+
import { IN_FLIGHT_LEADER_MAX_WAIT_MS } from "../../cache/cache-policy.js";
|
|
110
|
+
import type {
|
|
111
|
+
PrerenderTargetObject,
|
|
112
|
+
ResolvedPrerender,
|
|
113
|
+
} from "../../prerender/on-demand.js";
|
|
104
114
|
import {
|
|
105
115
|
_getRequestContext,
|
|
106
116
|
type RequestContext,
|
|
@@ -112,6 +122,7 @@ import {
|
|
|
112
122
|
import { ShellRecordUnavailableError } from "../../cache/shell-snapshot.js";
|
|
113
123
|
import { prerenderStoreShortCircuits } from "../navigation-snapshot.js";
|
|
114
124
|
import { paramsEqual } from "../params-util.js";
|
|
125
|
+
import { requestHeaders } from "../../server/request-headers.js";
|
|
115
126
|
|
|
116
127
|
// Lazily initialized prerender store singleton and dynamically imported deps.
|
|
117
128
|
// Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
|
|
@@ -129,10 +140,27 @@ let _restoreHandles:
|
|
|
129
140
|
let _decodeHandles:
|
|
130
141
|
| typeof import("../../cache/handle-snapshot.js").decodeHandles
|
|
131
142
|
| undefined;
|
|
143
|
+
let _restoreRecordHandles:
|
|
144
|
+
| typeof import("../../cache/handle-snapshot.js").restoreRecordHandles
|
|
145
|
+
| undefined;
|
|
132
146
|
let _hashParams:
|
|
133
147
|
| typeof import("../../prerender/param-hash.js").hashParams
|
|
134
148
|
| undefined;
|
|
135
149
|
|
|
150
|
+
/**
|
|
151
|
+
* @internal Replace the prerender store this module serves from, and return
|
|
152
|
+
* the one it replaced. For serveShellRequest (testing/serve-shell-request.ts),
|
|
153
|
+
* which installs the production store over the artifacts it bakes for a call
|
|
154
|
+
* and puts the previous one back after it.
|
|
155
|
+
*/
|
|
156
|
+
export function setPrerenderStoreForTests(
|
|
157
|
+
store: PrerenderStore | null | undefined,
|
|
158
|
+
): PrerenderStore | null | undefined {
|
|
159
|
+
const previous = prerenderStoreInstance;
|
|
160
|
+
prerenderStoreInstance = store;
|
|
161
|
+
return previous;
|
|
162
|
+
}
|
|
163
|
+
|
|
136
164
|
async function ensurePrerenderDeps() {
|
|
137
165
|
if (!_deserializeSegments) {
|
|
138
166
|
const [codec, snapshot, paramHash, store] = await Promise.all([
|
|
@@ -145,6 +173,7 @@ async function ensurePrerenderDeps() {
|
|
|
145
173
|
_fragmentSegments = codec.fragmentSegments;
|
|
146
174
|
_restoreHandles = snapshot.restoreHandles;
|
|
147
175
|
_decodeHandles = snapshot.decodeHandles;
|
|
176
|
+
_restoreRecordHandles = snapshot.restoreRecordHandles;
|
|
148
177
|
_hashParams = paramHash.hashParams;
|
|
149
178
|
if (prerenderStoreInstance === undefined) {
|
|
150
179
|
prerenderStoreInstance = store.createPrerenderStore();
|
|
@@ -241,12 +270,21 @@ async function* yieldFromStore<TEnv>(
|
|
|
241
270
|
reqCtx: RequestContext<TEnv> | undefined,
|
|
242
271
|
resolveLoadersOnly: RouterContext<TEnv>["resolveLoadersOnly"],
|
|
243
272
|
resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
|
|
273
|
+
/**
|
|
274
|
+
* The entry may be newer than the client's copy: an on-demand overlay entry
|
|
275
|
+
* that a refresh (possibly inside this very action) replaced. On an action
|
|
276
|
+
* the route's own segments are then re-sent, as a live action re-render
|
|
277
|
+
* re-sends them (revalidation.ts "action:route-segment"); the immutable
|
|
278
|
+
* bundled manifest keeps the client's copy.
|
|
279
|
+
*/
|
|
280
|
+
replaceable?: boolean,
|
|
244
281
|
): AsyncGenerator<ResolvedSegment> {
|
|
245
282
|
if (
|
|
246
283
|
!_deserializeSegments ||
|
|
247
284
|
!_fragmentSegments ||
|
|
248
285
|
!_restoreHandles ||
|
|
249
286
|
!_decodeHandles ||
|
|
287
|
+
!_restoreRecordHandles ||
|
|
250
288
|
!_hashParams
|
|
251
289
|
) {
|
|
252
290
|
throw new Error("yieldFromStore called before ensurePrerenderDeps");
|
|
@@ -271,6 +309,16 @@ async function* yieldFromStore<TEnv>(
|
|
|
271
309
|
}
|
|
272
310
|
}
|
|
273
311
|
|
|
312
|
+
// Before the render barrier freezes the document snapshot.
|
|
313
|
+
const shellHandles = reqCtx?._shellImplicitCache?.prerenderHandles;
|
|
314
|
+
if (handleStore && shellHandles) {
|
|
315
|
+
await _restoreRecordHandles!(
|
|
316
|
+
handleStore,
|
|
317
|
+
shellHandles,
|
|
318
|
+
loaderPins(ctx.entries, reqCtx),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
274
322
|
state.cacheHit = true;
|
|
275
323
|
state.cacheSource = "prerender";
|
|
276
324
|
state.cachedSegments = segments;
|
|
@@ -293,11 +341,16 @@ async function* yieldFromStore<TEnv>(
|
|
|
293
341
|
// different content, so we must NOT nullify.
|
|
294
342
|
const paramsChanged =
|
|
295
343
|
!ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
344
|
+
const resendRouteSegments = replaceable === true && ctx.isAction;
|
|
296
345
|
for (const segment of segments) {
|
|
297
346
|
if (
|
|
298
347
|
!ctx.isFullMatch &&
|
|
299
348
|
!paramsChanged &&
|
|
300
|
-
ctx.clientSegmentSet.has(segment.id)
|
|
349
|
+
ctx.clientSegmentSet.has(segment.id) &&
|
|
350
|
+
!(
|
|
351
|
+
resendRouteSegments &&
|
|
352
|
+
(segment.type === "route" || segment.belongsToRoute === true)
|
|
353
|
+
)
|
|
301
354
|
) {
|
|
302
355
|
keepClientSegment(segment);
|
|
303
356
|
}
|
|
@@ -346,11 +399,9 @@ export async function prerenderEntryExists(
|
|
|
346
399
|
).createPrerenderStore();
|
|
347
400
|
}
|
|
348
401
|
if (!prerenderStoreInstance) return false;
|
|
349
|
-
// Non-intercept variant only: whether the navigation
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
// artifact. A wrong guess is reclassified post-match from the match
|
|
353
|
-
// pipeline's `_pprReplayPostMatchReason` stamp.
|
|
402
|
+
// Non-intercept variant only: whether the navigation is an intercept (which
|
|
403
|
+
// reads `paramHash + "/i"`) resolves during the match. A wrong guess is
|
|
404
|
+
// reclassified post-match from `_pprReplayPostMatchReason`.
|
|
354
405
|
const entry = await prerenderStoreInstance.get(
|
|
355
406
|
routeKey,
|
|
356
407
|
_hashParams!(params),
|
|
@@ -364,6 +415,63 @@ export async function prerenderEntryExists(
|
|
|
364
415
|
return entry != null;
|
|
365
416
|
}
|
|
366
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Serialized overlay key -> start time of its in-flight `onRevalidate`.
|
|
420
|
+
* Dedupes the obvious Node wiring, `(t, env) => router.prerender(t, { env })`,
|
|
421
|
+
* and queue sends alike, per isolate. Entries older than
|
|
422
|
+
* IN_FLIGHT_LEADER_MAX_WAIT_MS count as free: a never-settling onRevalidate
|
|
423
|
+
* (hung queue send) or a killed execution context never runs `.finally`, and
|
|
424
|
+
* would otherwise pin the key for the isolate's lifetime.
|
|
425
|
+
*/
|
|
426
|
+
const overlayRevalidationsInFlight = new Map<string, number>();
|
|
427
|
+
|
|
428
|
+
/** @internal Tests only (testing/serve-shell-request.ts resetShellTestState). */
|
|
429
|
+
export function resetOverlayRevalidationsForTests(): void {
|
|
430
|
+
overlayRevalidationsInFlight.clear();
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** @internal Exported for the eviction unit test. */
|
|
434
|
+
export function scheduleOverlayRevalidation<TEnv>(
|
|
435
|
+
serializedKey: string,
|
|
436
|
+
onRevalidate: NonNullable<ResolvedPrerender["config"]["onRevalidate"]>,
|
|
437
|
+
target: PrerenderTargetObject,
|
|
438
|
+
reqCtx: RequestContext<TEnv>,
|
|
439
|
+
now: number = Date.now(),
|
|
440
|
+
): void {
|
|
441
|
+
// waitUntil is a no-op under build contexts: nothing would clear the key.
|
|
442
|
+
if (reqCtx.build) return;
|
|
443
|
+
const startedAt = overlayRevalidationsInFlight.get(serializedKey);
|
|
444
|
+
if (
|
|
445
|
+
startedAt !== undefined &&
|
|
446
|
+
now - startedAt < IN_FLIGHT_LEADER_MAX_WAIT_MS
|
|
447
|
+
) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
overlayRevalidationsInFlight.set(serializedKey, now);
|
|
451
|
+
const env = reqCtx.env;
|
|
452
|
+
const executionContext = reqCtx.executionContext;
|
|
453
|
+
const reportError = reqCtx._reportBackgroundError;
|
|
454
|
+
// The stale entry still serves this request; this only schedules.
|
|
455
|
+
reqCtx.waitUntil(() =>
|
|
456
|
+
Promise.resolve()
|
|
457
|
+
.then(() => onRevalidate(target, env, executionContext))
|
|
458
|
+
.then(
|
|
459
|
+
() => {},
|
|
460
|
+
(err) => {
|
|
461
|
+
// A failed onRevalidate must not fail the response, but must reach
|
|
462
|
+
// onError like the runtime cache's stale-revalidation failures.
|
|
463
|
+
reportError?.(err, "stale-revalidation");
|
|
464
|
+
},
|
|
465
|
+
)
|
|
466
|
+
.finally(() => {
|
|
467
|
+
// An evicted-and-rescheduled entry belongs to the newer run.
|
|
468
|
+
if (overlayRevalidationsInFlight.get(serializedKey) === now) {
|
|
469
|
+
overlayRevalidationsInFlight.delete(serializedKey);
|
|
470
|
+
}
|
|
471
|
+
}),
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
367
475
|
/**
|
|
368
476
|
* Look up a prerendered (build-time cached) entry for the current route and, on
|
|
369
477
|
* a hit, yield its segments. Returns true when an entry was served (the caller
|
|
@@ -379,31 +487,99 @@ async function* tryPrerenderLookup<TEnv>(
|
|
|
379
487
|
reqCtx: RequestContext<TEnv> | undefined,
|
|
380
488
|
resolveLoadersOnly: RouterContext<TEnv>["resolveLoadersOnly"],
|
|
381
489
|
resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
|
|
490
|
+
isPassthroughPrerenderRoute: boolean,
|
|
491
|
+
overlay?: ResolvedPrerender,
|
|
382
492
|
): AsyncGenerator<ResolvedSegment, boolean> {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
(
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
493
|
+
// 1. Writable durable overlay (per-request, env-scoped), read before the
|
|
494
|
+
// bundled manifest: it is always newer. Only on-demand routes are read
|
|
495
|
+
// (router.prerender() refuses non-od routes, so a pr-only route always
|
|
496
|
+
// misses), and never for intercept navigations (only the main variant is
|
|
497
|
+
// written). Actions read it too: a plain on-demand route has no live
|
|
498
|
+
// handler, so skipping the overlay would 404 an overlay-only param
|
|
499
|
+
// (gateOnDemandProducer). A store error degrades to a miss
|
|
500
|
+
// (readVerifiedStoredEntry); a stale hit serves and may schedule onRevalidate.
|
|
501
|
+
if (overlay && ctx.matched.od && !ctx.isIntercept) {
|
|
502
|
+
const key: PrerenderKey = {
|
|
503
|
+
routerId: overlay.routerId,
|
|
504
|
+
version: overlay.version,
|
|
505
|
+
routeName: ctx.matched.routeKey,
|
|
506
|
+
paramHash: _hashParams!(ctx.matched.params),
|
|
507
|
+
};
|
|
508
|
+
const stored = await readVerifiedStoredEntry(
|
|
509
|
+
overlay.config.store,
|
|
510
|
+
key,
|
|
511
|
+
ctx.matched.params,
|
|
512
|
+
);
|
|
513
|
+
if (stored) {
|
|
514
|
+
// A stale "removed" marker is rechecked like a stale page: only a
|
|
515
|
+
// refresh that hit notFound() (or declined) stamps one with a ttl or
|
|
516
|
+
// tags. A prerender.remove() marker has neither and never gets here.
|
|
517
|
+
if (
|
|
518
|
+
overlay.config.onRevalidate &&
|
|
519
|
+
reqCtx &&
|
|
520
|
+
isStoredEntryStale(stored, Date.now())
|
|
521
|
+
) {
|
|
522
|
+
scheduleOverlayRevalidation(
|
|
523
|
+
serializePrerenderKey(key),
|
|
524
|
+
overlay.config.onRevalidate,
|
|
525
|
+
{
|
|
526
|
+
route: ctx.matched.routeKey,
|
|
527
|
+
params: ctx.matched.params,
|
|
528
|
+
} as PrerenderTargetObject,
|
|
529
|
+
reqCtx,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
if (stored.removed === true) {
|
|
533
|
+
// The page was removed. Not served, and step 2 is skipped: the
|
|
534
|
+
// build-time entry below must not come back. The route's handler
|
|
535
|
+
// answers: a Passthrough route's live handler, or a plain route's
|
|
536
|
+
// gated producer, which `_prerenderRemoved` makes a 404 in dev too
|
|
537
|
+
// (gateOnDemandProducer).
|
|
538
|
+
(
|
|
539
|
+
ctx.handlerContext as InternalHandlerContext<any, TEnv>
|
|
540
|
+
)._prerenderRemoved = true;
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
yield* yieldFromStore(
|
|
544
|
+
stored.entry,
|
|
545
|
+
ctx,
|
|
546
|
+
state,
|
|
547
|
+
pipelineStart,
|
|
548
|
+
reqCtx,
|
|
549
|
+
resolveLoadersOnly,
|
|
550
|
+
resolveLoadersOnlyWithRevalidation,
|
|
551
|
+
true,
|
|
552
|
+
);
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// 2. Bundled build manifest (immutable). Absent for on-demand-only routes.
|
|
558
|
+
if (prerenderStoreInstance) {
|
|
559
|
+
const paramHash = _hashParams!(ctx.matched.params);
|
|
560
|
+
const entry = await prerenderStoreInstance.get(
|
|
561
|
+
ctx.matched.routeKey,
|
|
562
|
+
ctx.isIntercept ? paramHash + "/i" : paramHash,
|
|
563
|
+
{
|
|
564
|
+
pathname: ctx.pathname,
|
|
565
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
566
|
+
},
|
|
567
|
+
);
|
|
568
|
+
if (entry) {
|
|
569
|
+
yield* yieldFromStore(
|
|
570
|
+
entry,
|
|
571
|
+
ctx,
|
|
572
|
+
state,
|
|
573
|
+
pipelineStart,
|
|
574
|
+
reqCtx,
|
|
575
|
+
resolveLoadersOnly,
|
|
576
|
+
resolveLoadersOnlyWithRevalidation,
|
|
577
|
+
);
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return false;
|
|
407
583
|
}
|
|
408
584
|
|
|
409
585
|
/**
|
|
@@ -464,6 +640,8 @@ export function withCacheLookup<TEnv>(
|
|
|
464
640
|
? "intercept"
|
|
465
641
|
: undefined;
|
|
466
642
|
}
|
|
643
|
+
// Per-request writable prerender overlay (durable), resolved by the handler.
|
|
644
|
+
const prerenderOverlay = pipelineReqCtx?._prerender;
|
|
467
645
|
|
|
468
646
|
const {
|
|
469
647
|
evaluateRevalidation,
|
|
@@ -474,20 +652,30 @@ export function withCacheLookup<TEnv>(
|
|
|
474
652
|
resolveAllSegmentsWithRevalidation,
|
|
475
653
|
} = getRouterContext<TEnv>();
|
|
476
654
|
|
|
477
|
-
|
|
655
|
+
// An on-demand route may have no build-baked entry yet still needs a
|
|
656
|
+
// writable-overlay lookup, so od joins pr in the gate. The retained producer
|
|
657
|
+
// is NEVER run by this pipeline: a miss falls through like pr + miss.
|
|
658
|
+
const isPassthroughPrerenderRoute = ctx.entries.some(
|
|
659
|
+
(entry) => entry.type === "route" && entry.isPassthrough === true,
|
|
660
|
+
);
|
|
661
|
+
const overlayEligible =
|
|
662
|
+
ctx.matched.od === true && !requestHeaders(ctx.request).get("X-RSC-HMR");
|
|
663
|
+
if (
|
|
664
|
+
prerenderStoreShortCircuits(ctx.matched.pr, ctx.request) ||
|
|
665
|
+
overlayEligible
|
|
666
|
+
) {
|
|
478
667
|
// Actions normally re-render fresh and skip the prerender store. But a pure
|
|
479
668
|
// Prerender route's handler is evicted at build, so there is no fresh
|
|
480
669
|
// handler to run on an action re-render -- without the fallback the
|
|
481
670
|
// re-render falls through to the evicted handler and throws "No prerender
|
|
482
671
|
// data found". Serve the prerendered entry instead (the action ran already;
|
|
483
|
-
// its result is applied client-side via useActionState).
|
|
484
|
-
//
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
);
|
|
672
|
+
// its result is applied client-side via useActionState). A plain on-demand
|
|
673
|
+
// route is the same case, served from the overlay first (an overlay entry
|
|
674
|
+
// is newer than the build one, and may be the only one). Passthrough
|
|
675
|
+
// routes keep a liveHandler, so they still re-render fresh on actions.
|
|
488
676
|
if (!ctx.isAction || !isPassthroughPrerenderRoute) {
|
|
489
677
|
await ensurePrerenderDeps();
|
|
490
|
-
if (prerenderStoreInstance) {
|
|
678
|
+
if (prerenderStoreInstance || prerenderOverlay) {
|
|
491
679
|
const served = yield* tryPrerenderLookup(
|
|
492
680
|
ctx,
|
|
493
681
|
state,
|
|
@@ -495,6 +683,8 @@ export function withCacheLookup<TEnv>(
|
|
|
495
683
|
pipelineReqCtx,
|
|
496
684
|
resolveLoadersOnly,
|
|
497
685
|
resolveLoadersOnlyWithRevalidation,
|
|
686
|
+
isPassthroughPrerenderRoute,
|
|
687
|
+
prerenderOverlay,
|
|
498
688
|
);
|
|
499
689
|
if (served) return;
|
|
500
690
|
}
|
|
@@ -519,6 +709,7 @@ export function withCacheLookup<TEnv>(
|
|
|
519
709
|
pipelineReqCtx,
|
|
520
710
|
resolveLoadersOnly,
|
|
521
711
|
resolveLoadersOnlyWithRevalidation,
|
|
712
|
+
isPassthroughPrerenderRoute,
|
|
522
713
|
);
|
|
523
714
|
if (served) return;
|
|
524
715
|
}
|
|
@@ -546,20 +737,14 @@ export function withCacheLookup<TEnv>(
|
|
|
546
737
|
return;
|
|
547
738
|
}
|
|
548
739
|
|
|
549
|
-
//
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
claim: (ctx.handlerContext as InternalHandlerContext)._claimLoaderPushes,
|
|
558
|
-
};
|
|
559
|
-
if (tailMarker) {
|
|
560
|
-
ownedPushes.liveLane = liveLaneLoaderIds(ctx.entries);
|
|
561
|
-
ownedPushes.restore = tailMarker.docTail === true;
|
|
562
|
-
}
|
|
740
|
+
// Only a ppr route's records hold loader pushes, and only its shell pins
|
|
741
|
+
// loaders (CachedEntryData.handleOwners, the loader seed): any other
|
|
742
|
+
// route's record restores as a plain replay.
|
|
743
|
+
const leaf = ctx.entries[ctx.entries.length - 1];
|
|
744
|
+
const ownedPushes =
|
|
745
|
+
leaf !== undefined && isPprEntry(leaf)
|
|
746
|
+
? () => loaderPins(ctx.entries, pipelineReqCtx)
|
|
747
|
+
: undefined;
|
|
563
748
|
const explicitLookup = await ctx.cacheScope.lookupRouteDetailed(
|
|
564
749
|
ctx.pathname,
|
|
565
750
|
ctx.matched.params,
|
|
@@ -38,12 +38,31 @@ export interface ResolveNavigationDeps {
|
|
|
38
38
|
* never produce a partial match, so the replay path must decide
|
|
39
39
|
* `no-navigation-context` BEFORE spending shell-store reads — the two
|
|
40
40
|
* predicates drifting apart would misattribute the bypass again.
|
|
41
|
+
*
|
|
42
|
+
* `requestOrigin` is the origin pathname matching uses (`url.origin`), which
|
|
43
|
+
* may not be `request.url`'s. `X-RSC-Router-Client-Path` is returned as sent.
|
|
44
|
+
* A Referer counts only when it resolves against that origin and stays there.
|
|
45
|
+
* A cross-origin Referer is dropped: resolveNavigation matches only the
|
|
46
|
+
* pathname, so a foreign URL would be treated as a route on this app. A value
|
|
47
|
+
* that does not parse is no context either.
|
|
41
48
|
*/
|
|
42
|
-
export function getNavigationContextHeader(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
49
|
+
export function getNavigationContextHeader(
|
|
50
|
+
request: Request,
|
|
51
|
+
requestOrigin: string,
|
|
52
|
+
): string | null {
|
|
53
|
+
const headers = requestHeaders(request);
|
|
54
|
+
const clientPath = headers.get("X-RSC-Router-Client-Path");
|
|
55
|
+
if (clientPath) return clientPath;
|
|
56
|
+
|
|
57
|
+
const referer = headers.get("Referer");
|
|
58
|
+
if (!referer) return null;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (new URL(referer, requestOrigin).origin !== requestOrigin) return null;
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return referer;
|
|
47
66
|
}
|
|
48
67
|
|
|
49
68
|
/**
|
|
@@ -84,7 +103,7 @@ export async function resolveNavigation(
|
|
|
84
103
|
const clientSegmentIds =
|
|
85
104
|
url.searchParams.get("_rsc_segments")?.split(",").filter(Boolean) || [];
|
|
86
105
|
const stale = url.searchParams.get("_rsc_stale") === "true";
|
|
87
|
-
const previousUrl = getNavigationContextHeader(request);
|
|
106
|
+
const previousUrl = getNavigationContextHeader(request, url.origin);
|
|
88
107
|
const interceptSourceUrl = getInterceptSourceHeader(request);
|
|
89
108
|
const isHmr = !!requestHeaders(request).get("X-RSC-HMR");
|
|
90
109
|
|
|
@@ -330,6 +330,8 @@ export interface RouteMatchResult<TEnv = any> {
|
|
|
330
330
|
pr?: true;
|
|
331
331
|
/** Passthrough: handler kept for live fallback on unknown params (from trie) */
|
|
332
332
|
pt?: true;
|
|
333
|
+
/** On-demand prerender eligible (router.prerender() refreshable) */
|
|
334
|
+
od?: true;
|
|
333
335
|
/** Response type for non-RSC routes (json, text, image, any) */
|
|
334
336
|
responseType?: string;
|
|
335
337
|
/** Negotiate variants: response-type routes sharing this path */
|
|
@@ -455,6 +457,9 @@ export function findMatch<TEnv>(
|
|
|
455
457
|
const ptFlag = entry.passthroughRouteKeys?.has(routeKey)
|
|
456
458
|
? { pt: true as const }
|
|
457
459
|
: {};
|
|
460
|
+
const odFlag = entry.onDemandRouteKeys?.has(routeKey)
|
|
461
|
+
? { od: true as const }
|
|
462
|
+
: {};
|
|
458
463
|
|
|
459
464
|
const match = regex.exec(pathname);
|
|
460
465
|
if (match) {
|
|
@@ -484,6 +489,7 @@ export function findMatch<TEnv>(
|
|
|
484
489
|
redirectTo: pathname + "/",
|
|
485
490
|
...prFlag,
|
|
486
491
|
...ptFlag,
|
|
492
|
+
...odFlag,
|
|
487
493
|
};
|
|
488
494
|
} else if (trailingSlashMode === "never" && pathnameHasTrailingSlash) {
|
|
489
495
|
return {
|
|
@@ -493,6 +499,7 @@ export function findMatch<TEnv>(
|
|
|
493
499
|
redirectTo: pathname.slice(0, -1),
|
|
494
500
|
...prFlag,
|
|
495
501
|
...ptFlag,
|
|
502
|
+
...odFlag,
|
|
496
503
|
};
|
|
497
504
|
}
|
|
498
505
|
|
|
@@ -502,6 +509,7 @@ export function findMatch<TEnv>(
|
|
|
502
509
|
params,
|
|
503
510
|
...prFlag,
|
|
504
511
|
...ptFlag,
|
|
512
|
+
...odFlag,
|
|
505
513
|
};
|
|
506
514
|
}
|
|
507
515
|
|
|
@@ -520,6 +528,7 @@ export function findMatch<TEnv>(
|
|
|
520
528
|
params,
|
|
521
529
|
...prFlag,
|
|
522
530
|
...ptFlag,
|
|
531
|
+
...odFlag,
|
|
523
532
|
};
|
|
524
533
|
} else if (trailingSlashMode === "never") {
|
|
525
534
|
if (pathnameHasTrailingSlash) {
|
|
@@ -530,6 +539,7 @@ export function findMatch<TEnv>(
|
|
|
530
539
|
redirectTo: alternatePathname,
|
|
531
540
|
...prFlag,
|
|
532
541
|
...ptFlag,
|
|
542
|
+
...odFlag,
|
|
533
543
|
};
|
|
534
544
|
}
|
|
535
545
|
return {
|
|
@@ -538,6 +548,7 @@ export function findMatch<TEnv>(
|
|
|
538
548
|
params,
|
|
539
549
|
...prFlag,
|
|
540
550
|
...ptFlag,
|
|
551
|
+
...odFlag,
|
|
541
552
|
};
|
|
542
553
|
} else if (trailingSlashMode === "always") {
|
|
543
554
|
if (!pathnameHasTrailingSlash) {
|
|
@@ -548,6 +559,7 @@ export function findMatch<TEnv>(
|
|
|
548
559
|
redirectTo: alternatePathname,
|
|
549
560
|
...prFlag,
|
|
550
561
|
...ptFlag,
|
|
562
|
+
...odFlag,
|
|
551
563
|
};
|
|
552
564
|
}
|
|
553
565
|
return {
|
|
@@ -556,6 +568,7 @@ export function findMatch<TEnv>(
|
|
|
556
568
|
params,
|
|
557
569
|
...prFlag,
|
|
558
570
|
...ptFlag,
|
|
571
|
+
...odFlag,
|
|
559
572
|
};
|
|
560
573
|
} else {
|
|
561
574
|
const canonicalPath = hasTrailingSlash
|
|
@@ -568,6 +581,7 @@ export function findMatch<TEnv>(
|
|
|
568
581
|
redirectTo: canonicalPath,
|
|
569
582
|
...prFlag,
|
|
570
583
|
...ptFlag,
|
|
584
|
+
...odFlag,
|
|
571
585
|
};
|
|
572
586
|
}
|
|
573
587
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolve the router-wide default Link prefetch strategy once, at router init.
|
|
3
|
-
* The resolved value ships to the client in payload metadata; the
|
|
4
|
-
*
|
|
5
|
-
* default-strategy.ts) and every `<Link>` without an explicit
|
|
6
|
-
* falls back to it.
|
|
3
|
+
* The resolved value ships to the client in payload metadata; the router
|
|
4
|
+
* store carries it (`NavigationStoreContext.defaultPrefetch`, see
|
|
5
|
+
* browser/prefetch/default-strategy.ts) and every `<Link>` without an explicit
|
|
6
|
+
* `prefetch` prop falls back to it.
|
|
7
7
|
*
|
|
8
8
|
* The type lives HERE (not in browser/react/Link.tsx) because both seats need
|
|
9
9
|
* it: this server-side resolver and the client Link/default-strategy modules.
|