vinext 1.4.1 → 1.4.2
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 +1 -1
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/check.js +1 -1
- package/dist/config/config-matchers.js +2 -2
- package/dist/config/destination-params.js +5 -2
- package/dist/config/next-config.d.ts +16 -1
- package/dist/config/next-config.js +31 -1
- package/dist/entries/app-rsc-entry.js +41 -18
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +2 -0
- package/dist/index.js +15 -12
- package/dist/init-cloudflare.js +18 -2
- package/dist/plugins/css-target.d.ts +18 -0
- package/dist/plugins/css-target.js +93 -0
- package/dist/routing/app-route-graph.d.ts +10 -0
- package/dist/routing/app-route-graph.js +15 -1
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +3 -5
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +21 -4
- package/dist/server/app-elements.d.ts +3 -0
- package/dist/server/app-elements.js +14 -1
- package/dist/server/app-fallback-renderer.js +2 -2
- package/dist/server/app-optimistic-routing.d.ts +12 -1
- package/dist/server/app-optimistic-routing.js +38 -16
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +73 -30
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +37 -49
- package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
- package/dist/server/app-page-intercept-segment-config.js +90 -0
- package/dist/server/app-page-navigation-params.d.ts +23 -0
- package/dist/server/app-page-navigation-params.js +49 -0
- package/dist/server/app-page-render.d.ts +5 -2
- package/dist/server/app-page-render.js +17 -3
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +16 -12
- package/dist/server/app-page-segment-plan.js +9 -1
- package/dist/server/app-page-segment-state.d.ts +9 -0
- package/dist/server/app-page-segment-state.js +54 -1
- package/dist/server/app-response-stage-entry.js +1 -0
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +75 -43
- package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
- package/dist/server/app-rsc-response-finalizer.js +11 -1
- package/dist/server/app-rsc-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +16 -10
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -1
- package/dist/server/image-local-patterns.d.ts +21 -0
- package/dist/server/image-local-patterns.js +59 -0
- package/dist/server/image-optimization.d.ts +23 -22
- package/dist/server/image-optimization.js +12 -2
- package/dist/server/metadata-route-response.js +24 -6
- package/dist/server/nitro-public-files-plugin.js +20 -8
- package/dist/server/pages-data-route.d.ts +5 -1
- package/dist/server/pages-data-route.js +14 -6
- package/dist/server/pages-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +1 -0
- package/dist/server/prod-server.js +17 -9
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +11 -1
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- package/dist/server/worker-image-optimization.d.ts +2 -2
- package/dist/server/worker-image-optimization.js +18 -3
- package/dist/server/worker-utils.d.ts +8 -0
- package/dist/server/worker-utils.js +19 -2
- package/dist/shims/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/slot.d.ts +3 -0
- package/dist/shims/slot.js +67 -9
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/package.json +1 -1
|
@@ -14,5 +14,7 @@ export declare function handleApiRoute(runner: ModuleImporter, req: IncomingMess
|
|
|
14
14
|
allowedRevalidateHeaderKeys?: readonly string[];
|
|
15
15
|
trailingSlash?: boolean;
|
|
16
16
|
skipTrailingSlashRedirect?: boolean;
|
|
17
|
+
/** Edge API request pathname, with any basePath the dev server stripped restored. */
|
|
18
|
+
requestPathname?: string;
|
|
17
19
|
}): Promise<boolean>;
|
|
18
20
|
//#endregion
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasBasePath } from "../utils/base-path.js";
|
|
2
1
|
import { matchRoute } from "../routing/pages-router.js";
|
|
3
2
|
import "./server-globals.js";
|
|
4
3
|
import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
|
|
@@ -94,7 +93,7 @@ function readEdgeRequestBody(req) {
|
|
|
94
93
|
req.on("error", (error) => controller.error(error));
|
|
95
94
|
} });
|
|
96
95
|
}
|
|
97
|
-
function createEdgeApiRequest(req, res, url, params,
|
|
96
|
+
function createEdgeApiRequest(req, res, url, params, requestPathname) {
|
|
98
97
|
const headers = new Headers();
|
|
99
98
|
for (const [name, value] of Object.entries(req.headers)) {
|
|
100
99
|
if (name.startsWith(":")) continue;
|
|
@@ -104,8 +103,7 @@ function createEdgeApiRequest(req, res, url, params, nextConfig) {
|
|
|
104
103
|
const proto = resolveRequestProtocol(req);
|
|
105
104
|
const host = resolveRequestHost(req, "localhost");
|
|
106
105
|
const requestUrl = new URL(req.url ?? url, `${proto}://${host}`);
|
|
107
|
-
|
|
108
|
-
if (basePath && !hasBasePath(requestUrl.pathname, basePath)) requestUrl.pathname = `${basePath}${requestUrl.pathname}`;
|
|
106
|
+
if (requestPathname !== void 0) requestUrl.pathname = requestPathname;
|
|
109
107
|
const query = mergeRouteParamsIntoQuery(parseQueryString(url), params);
|
|
110
108
|
requestUrl.search = urlQueryToSearchParams(query).toString();
|
|
111
109
|
const signal = signalFromNodeResponse(res);
|
|
@@ -250,7 +248,7 @@ async function handleApiRoute(runner, req, res, url, apiRoutes, nextConfig) {
|
|
|
250
248
|
try {
|
|
251
249
|
const apiModule = await importModule(runner, route.filePath);
|
|
252
250
|
if (isEdgeApiRouteModule(apiModule)) {
|
|
253
|
-
const nextRequest = new NextRequest(createEdgeApiRequest(req, res, url, params, nextConfig), nextConfig ? { nextConfig: {
|
|
251
|
+
const nextRequest = new NextRequest(createEdgeApiRequest(req, res, url, params, nextConfig?.requestPathname), nextConfig ? { nextConfig: {
|
|
254
252
|
basePath: nextConfig.basePath,
|
|
255
253
|
i18n: nextConfig.i18n ?? void 0,
|
|
256
254
|
trailingSlash: nextConfig.trailingSlash,
|
|
@@ -6,6 +6,7 @@ import { RequestCookies, ResponseCookies } from "../shims/server.js";
|
|
|
6
6
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
7
7
|
import { getSetCookieName } from "./cookie-utils.js";
|
|
8
8
|
import "../shims/internal/cookies.js";
|
|
9
|
+
import { isStreamedActionRedirectResponse, markStreamedActionRedirectResponse } from "./app-rsc-response-finalizer.js";
|
|
9
10
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
10
11
|
//#region src/server/app-action-forwarding.ts
|
|
11
12
|
const ACTION_FORWARD_FORBIDDEN_HEADERS = /* @__PURE__ */ new Set([
|
|
@@ -71,11 +72,12 @@ function filterActionForwardResponse(response, sourceMiddlewareHeaders, sourceMi
|
|
|
71
72
|
for (const [key, value] of response.headers) if (!ACTION_FORWARD_FORBIDDEN_HEADERS.has(key.toLowerCase())) headers.set(key, value);
|
|
72
73
|
for (const setCookie of response.headers.getSetCookie()) headers.append("set-cookie", setCookie);
|
|
73
74
|
const preserveResponseStatus = response.headers.get("x-nextjs-action-not-found") === "1" || response.headers.has("x-action-redirect");
|
|
74
|
-
|
|
75
|
+
const forwardedResponse = new Response(response.body, {
|
|
75
76
|
headers,
|
|
76
77
|
status: preserveResponseStatus ? response.status : sourceMiddlewareStatus ?? response.status,
|
|
77
78
|
statusText: response.statusText
|
|
78
79
|
});
|
|
80
|
+
return isStreamedActionRedirectResponse(response) ? markStreamedActionRedirectResponse(forwardedResponse) : forwardedResponse;
|
|
79
81
|
}
|
|
80
82
|
function emptyActionForwardResponse(middlewareContext) {
|
|
81
83
|
const headers = new Headers(middlewareContext.headers ?? void 0);
|
|
@@ -23,11 +23,11 @@ import { navigationPlanner } from "./navigation-planner.js";
|
|
|
23
23
|
import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
|
|
24
24
|
import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
25
25
|
import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
|
|
26
|
-
import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
|
|
26
|
+
import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, activateNavigationSnapshot, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
|
|
27
27
|
import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
|
|
28
28
|
import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
|
|
29
29
|
import { createMountedLayoutsHeader, holdsSkippedLayouts } from "./app-mounted-layouts.js";
|
|
30
|
-
import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, setAppElementsRenderedSearch } from "../shims/slot.js";
|
|
30
|
+
import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, isBfcacheIdentityRetained, setAppElementsRenderedSearch } from "../shims/slot.js";
|
|
31
31
|
import { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl } from "./app-browser-state.js";
|
|
32
32
|
import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, navigateDocumentDirectly } from "./app-browser-navigation-controller.js";
|
|
33
33
|
import { createAppRouteTree } from "./app-route-tree.js";
|
|
@@ -195,6 +195,12 @@ const RSC_HMR_SETTLE_DELAY_MS = 150;
|
|
|
195
195
|
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
196
196
|
let latestRscHmrUpdateId = 0;
|
|
197
197
|
let synchronousPopstateScrollRestoreNavigationId = null;
|
|
198
|
+
let pendingHistoryRestoreCommit = null;
|
|
199
|
+
function flushPendingHistoryRestoreCommit() {
|
|
200
|
+
const commit = pendingHistoryRestoreCommit;
|
|
201
|
+
pendingHistoryRestoreCommit = null;
|
|
202
|
+
commit?.();
|
|
203
|
+
}
|
|
198
204
|
function waitForRscHmrSettle(delayMs = RSC_HMR_SETTLE_DELAY_MS) {
|
|
199
205
|
return new Promise((resolve) => {
|
|
200
206
|
window.setTimeout(resolve, delayMs);
|
|
@@ -212,6 +218,10 @@ function restoreHistoryStateSnapshot(historyState, navId, onApprovedBeforeCommit
|
|
|
212
218
|
beforeCommit: () => {
|
|
213
219
|
onApprovedBeforeCommit?.();
|
|
214
220
|
beforeCommit();
|
|
221
|
+
if (!restoreCopiedExternalHistoryEntry) {
|
|
222
|
+
activateNavigationSnapshot();
|
|
223
|
+
pendingHistoryRestoreCommit = () => commitClientNavigationState(navId);
|
|
224
|
+
}
|
|
215
225
|
},
|
|
216
226
|
navId,
|
|
217
227
|
state,
|
|
@@ -223,7 +233,8 @@ function restoreHistoryStateSnapshot(historyState, navId, onApprovedBeforeCommit
|
|
|
223
233
|
clientNavigationCacheGeneration += 1;
|
|
224
234
|
revokeHistoryRestoreNavigationReuse(visitedResponseCache);
|
|
225
235
|
disableNavigationResponsePrefetchCacheReuse();
|
|
226
|
-
commitClientNavigationState(navId, { releaseSnapshot: false });
|
|
236
|
+
if (restoreCopiedExternalHistoryEntry) commitClientNavigationState(navId, { releaseSnapshot: false });
|
|
237
|
+
else flushPendingHistoryRestoreCommit();
|
|
227
238
|
return true;
|
|
228
239
|
}
|
|
229
240
|
function getBrowserRouterState() {
|
|
@@ -1393,7 +1404,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1393
1404
|
currentElements: navigationInitiationState.elements,
|
|
1394
1405
|
currentLayoutIds: navigationInitiationState.layoutIds,
|
|
1395
1406
|
currentParams: navigationInitiationState.navigationSnapshot.params,
|
|
1407
|
+
isBfcacheIdentityRetained,
|
|
1396
1408
|
routeManifest,
|
|
1409
|
+
shownElements: getBrowserRouterState().elements,
|
|
1410
|
+
targetElements: optimisticPayload.elements,
|
|
1397
1411
|
targetRouteParams: optimisticPayload.routeParams,
|
|
1398
1412
|
targetUrlParts: optimisticPayload.urlParts,
|
|
1399
1413
|
template: optimisticPayload.template
|
|
@@ -1635,7 +1649,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1635
1649
|
discardPendingNavigation: () => {
|
|
1636
1650
|
if (browserNavigationController.discardPendingNavigation(historyController.readCurrentTreeSnapshot())) navigationAbortCoordinator.abortActive();
|
|
1637
1651
|
},
|
|
1638
|
-
flushCommittingNavigationUrl: () =>
|
|
1652
|
+
flushCommittingNavigationUrl: () => {
|
|
1653
|
+
flushPendingHistoryRestoreCommit();
|
|
1654
|
+
browserNavigationController.flushCommittingNavigationUrl();
|
|
1655
|
+
}
|
|
1639
1656
|
});
|
|
1640
1657
|
const handlePopstate = createPopstateRestoreHandler({
|
|
1641
1658
|
getActiveNavigationId: browserNavigationController.getActiveNavigationId.bind(browserNavigationController),
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsBfcacheSegmentIdentities, AppElementsInterception, AppElementsSlotBinding, AppElementsWire, AppOutgoingElements, AppWireElements, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata } from "./app-elements-wire.js";
|
|
2
2
|
//#region src/server/app-elements.d.ts
|
|
3
3
|
export declare const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
|
|
4
|
+
type AppElementsStateKeyRebinder = (stateKey: string) => string;
|
|
5
|
+
export declare function setOptimisticStateKeyRebinder(elements: Record<string, unknown>, rebind: AppElementsStateKeyRebinder): void;
|
|
6
|
+
export declare function readOptimisticStateKeyRebinder(elements: AppElements): AppElementsStateKeyRebinder | null;
|
|
4
7
|
/** Prefix of the element that streams a route's generateMetadata() tags in the body. */
|
|
5
8
|
export declare const APP_STREAMING_METADATA_BODY_ID_PREFIX = "__vinext_streaming_metadata_body:";
|
|
6
9
|
export declare function getMountedSlotIds(elements: AppElements): string[];
|
|
@@ -2,6 +2,19 @@ import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
|
2
2
|
import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata } from "./app-elements-wire.js";
|
|
3
3
|
//#region src/server/app-elements.ts
|
|
4
4
|
const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
|
|
5
|
+
/**
|
|
6
|
+
* An optimistic shell's rebinder from the learned URL's segment state keys to
|
|
7
|
+
* the target's. Only the browser sets it, on the elements it builds a shell
|
|
8
|
+
* from, so it never reaches the wire.
|
|
9
|
+
*/
|
|
10
|
+
const APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY = "__optimisticStateKeyRebinder";
|
|
11
|
+
function setOptimisticStateKeyRebinder(elements, rebind) {
|
|
12
|
+
elements[APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY] = rebind;
|
|
13
|
+
}
|
|
14
|
+
function readOptimisticStateKeyRebinder(elements) {
|
|
15
|
+
const rebind = Reflect.get(elements, APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY);
|
|
16
|
+
return typeof rebind === "function" ? rebind : null;
|
|
17
|
+
}
|
|
5
18
|
/** Prefix of the element that streams a route's generateMetadata() tags in the body. */
|
|
6
19
|
const APP_STREAMING_METADATA_BODY_ID_PREFIX = "__vinext_streaming_metadata_body:";
|
|
7
20
|
function getMountedSlotIds(elements) {
|
|
@@ -18,4 +31,4 @@ function resolveVisitedResponseInterceptionContext(requestInterceptionContext, p
|
|
|
18
31
|
return payloadInterceptionContext ?? requestInterceptionContext;
|
|
19
32
|
}
|
|
20
33
|
//#endregion
|
|
21
|
-
export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext };
|
|
34
|
+
export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, readOptimisticStateKeyRebinder, resolveVisitedResponseInterceptionContext, setOptimisticStateKeyRebinder };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { runOutsideRequestScopes } from "../shims/internal/als-registry.js";
|
|
2
2
|
import { shareIsolatePromise } from "./isolate-shared-promise.js";
|
|
3
|
-
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
4
|
-
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
5
3
|
import { renderAppPageErrorBoundary, renderAppPageHttpAccessFallback } from "./app-page-boundary-render.js";
|
|
4
|
+
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
6
5
|
import { DEFAULT_GLOBAL_NOT_FOUND_MODULE } from "./default-global-not-found-module.js";
|
|
7
6
|
import { DEFAULT_NOT_FOUND_MODULE } from "./default-http-access-fallback-modules.js";
|
|
7
|
+
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
8
8
|
//#region src/server/app-fallback-renderer.ts
|
|
9
9
|
const EMPTY_MW_CTX = {
|
|
10
10
|
headers: null,
|
|
@@ -10,6 +10,8 @@ export type OptimisticRouteTemplate = {
|
|
|
10
10
|
omittedBfcacheSegmentIds: readonly string[];
|
|
11
11
|
omittedLayoutIds: readonly string[];
|
|
12
12
|
pageElementIds: readonly string[];
|
|
13
|
+
/** The navigation params of the URL the template was learned from. */
|
|
14
|
+
params: Readonly<Record<string, string | string[]>>;
|
|
13
15
|
routeId: string;
|
|
14
16
|
};
|
|
15
17
|
type OptimisticNavigationPayload = {
|
|
@@ -48,7 +50,7 @@ export declare function createOptimisticRouteTemplate(options: {
|
|
|
48
50
|
mountedSlotsHeader: string | null;
|
|
49
51
|
routeManifest: BrowserRouteManifest;
|
|
50
52
|
}): OptimisticRouteTemplate | null;
|
|
51
|
-
export declare function createOptimisticRouteElements(template: OptimisticRouteTemplate): AppElements;
|
|
53
|
+
export declare function createOptimisticRouteElements(template: OptimisticRouteTemplate, params?: Readonly<Record<string, string | string[]>>): AppElements;
|
|
52
54
|
/**
|
|
53
55
|
* The optimistic shell reveals the prefetch's streamed metadata, such as its
|
|
54
56
|
* title. React won't hide revealed content again in a transition, so while the
|
|
@@ -77,7 +79,16 @@ export declare function canCommitOptimisticRouteTemplate(options: {
|
|
|
77
79
|
currentElements: AppElements;
|
|
78
80
|
currentLayoutIds: readonly string[];
|
|
79
81
|
currentParams: Readonly<Record<string, string | string[]>>;
|
|
82
|
+
/** Whether a hidden BFCache entry retains a segment identity. */
|
|
83
|
+
isBfcacheIdentityRetained?: (identity: string) => boolean;
|
|
80
84
|
routeManifest: BrowserRouteManifest;
|
|
85
|
+
/**
|
|
86
|
+
* The elements on screen, when a shell earlier in this navigation replaced
|
|
87
|
+
* the current ones. Defaults to `currentElements`.
|
|
88
|
+
*/
|
|
89
|
+
shownElements?: AppElements;
|
|
90
|
+
/** The shell's elements for the target. */
|
|
91
|
+
targetElements?: AppElements;
|
|
81
92
|
targetRouteParams: Readonly<Record<string, string | string[]>>;
|
|
82
93
|
targetUrlParts: readonly string[];
|
|
83
94
|
template: OptimisticRouteTemplate;
|
|
@@ -4,10 +4,10 @@ import { decodeMatchedParams, splitPathnameForRouteMatch } from "../routing/util
|
|
|
4
4
|
import { extractRawRoutePatternParams, matchRoutePattern } from "../routing/route-pattern.js";
|
|
5
5
|
import { buildOptimisticRouteTrie, matchOptimisticRouteTrie } from "../routing/optimistic-route-trie.js";
|
|
6
6
|
import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
|
|
7
|
-
import { AppElementsWire } from "./app-elements-wire.js";
|
|
8
|
-
import "./app-elements.js";
|
|
7
|
+
import { APP_BFCACHE_SEGMENT_IDENTITIES_KEY, AppElementsWire } from "./app-elements-wire.js";
|
|
8
|
+
import { setOptimisticStateKeyRebinder } from "./app-elements.js";
|
|
9
9
|
import { createNestedBfcacheSlotSegmentId, deriveBfcacheSegmentIdentity, isNestedBfcacheSlotSegmentId } from "./bfcache-identity.js";
|
|
10
|
-
import { canonicalizeAppPageParams, resolveAppPagePatternStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
10
|
+
import { APP_PAGE_DEFAULT_SEGMENT_KEY, APP_PAGE_SEGMENT_KEY, canonicalizeAppPageParams, createAppPageSegmentStateKeyRebinder, resolveAppPagePatternStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
11
11
|
import { Suspense, createElement, isValidElement } from "react";
|
|
12
12
|
//#region src/server/app-optimistic-routing.ts
|
|
13
13
|
const routeTrieCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -114,6 +114,18 @@ function resolveTargetBfcacheSegmentIdentity(options) {
|
|
|
114
114
|
const segmentParams = binding.state === "active" && binding.slotPatternParts !== void 0 && binding.slotPatternParts.length > 0 && !binding.slotParamNames?.every((name) => routeParamNames.has(name)) ? matchRoutePattern(options.targetUrlParts, binding.slotPatternParts) ?? options.targetRouteParams : options.targetRouteParams;
|
|
115
115
|
const ownerLayout = binding.ownerLayoutId ? options.routeManifest.segmentGraph.layouts.get(binding.ownerLayoutId) : void 0;
|
|
116
116
|
const ownerStateKey = ownerLayout ? resolveAppPagePatternStateKey(ownerLayout.patternParts, options.targetRouteParams) : "";
|
|
117
|
+
const deriveLevelIdentity = (segmentKeys) => {
|
|
118
|
+
const identityKey = JSON.stringify(segmentKeys);
|
|
119
|
+
return deriveBfcacheSegmentIdentity({
|
|
120
|
+
activeRouteGraphId: null,
|
|
121
|
+
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, identityKey]) : identityKey,
|
|
122
|
+
interceptionTargetRouteGraphId: null,
|
|
123
|
+
kind: "slot",
|
|
124
|
+
ownerLayoutGraphId: binding.ownerLayoutId,
|
|
125
|
+
slotGraphId: binding.slotId,
|
|
126
|
+
state: binding.state
|
|
127
|
+
});
|
|
128
|
+
};
|
|
117
129
|
const boundSegmentKeys = [];
|
|
118
130
|
let level = 0;
|
|
119
131
|
for (const segment of binding.routeSegments ?? []) {
|
|
@@ -125,17 +137,9 @@ function resolveTargetBfcacheSegmentIdentity(options) {
|
|
|
125
137
|
segment
|
|
126
138
|
}, segmentParams));
|
|
127
139
|
if (createNestedBfcacheSlotSegmentId(binding.slotId, level) !== options.segmentId) continue;
|
|
128
|
-
|
|
129
|
-
return deriveBfcacheSegmentIdentity({
|
|
130
|
-
activeRouteGraphId: null,
|
|
131
|
-
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, identityKey]) : identityKey,
|
|
132
|
-
interceptionTargetRouteGraphId: null,
|
|
133
|
-
kind: "slot",
|
|
134
|
-
ownerLayoutGraphId: binding.ownerLayoutId,
|
|
135
|
-
slotGraphId: binding.slotId,
|
|
136
|
-
state: binding.state
|
|
137
|
-
});
|
|
140
|
+
return deriveLevelIdentity(boundSegmentKeys);
|
|
138
141
|
}
|
|
142
|
+
if (level > 0 && createNestedBfcacheSlotSegmentId(binding.slotId, level + 1) === options.segmentId) return deriveLevelIdentity([...boundSegmentKeys, binding.state === "default" ? APP_PAGE_DEFAULT_SEGMENT_KEY : APP_PAGE_SEGMENT_KEY]);
|
|
139
143
|
if (level === 0 && createNestedBfcacheSlotSegmentId(binding.slotId, 1) === options.segmentId) return deriveBfcacheSegmentIdentity({
|
|
140
144
|
activeRouteGraphId: null,
|
|
141
145
|
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, ""]) : "",
|
|
@@ -188,18 +192,31 @@ function createOptimisticRouteTemplate(options) {
|
|
|
188
192
|
if (options.allowLoadingShell && (routeElement === void 0 || routeElement === null)) return null;
|
|
189
193
|
const pageElementIds = getPageElementIds(options.elements, match.route);
|
|
190
194
|
if (pageElementIds.length === 0) return null;
|
|
195
|
+
const urlParts = hrefToRouteParts(options.href, options.basePath);
|
|
196
|
+
if (urlParts === null) return null;
|
|
191
197
|
return {
|
|
192
198
|
elements: options.elements,
|
|
193
199
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
194
200
|
omittedBfcacheSegmentIds: options.elements["__prefetchLoadingShell"] === "LoadingBoundary" ? getOmittedBfcacheSegmentIds(options.elements) : [],
|
|
195
201
|
omittedLayoutIds: options.elements["__prefetchLoadingShell"] === "LoadingBoundary" ? metadata.layoutIds.filter((layoutId) => !Object.hasOwn(options.elements, layoutId)) : [],
|
|
196
202
|
pageElementIds,
|
|
203
|
+
params: resolveOptimisticNavigationParams({
|
|
204
|
+
match,
|
|
205
|
+
rawUrlParts: urlParts.raw,
|
|
206
|
+
routeManifest: options.routeManifest,
|
|
207
|
+
urlParts: urlParts.normalized
|
|
208
|
+
}).navigationParams,
|
|
197
209
|
routeId: match.route.id
|
|
198
210
|
};
|
|
199
211
|
}
|
|
200
|
-
function createOptimisticRouteElements(template) {
|
|
212
|
+
function createOptimisticRouteElements(template, params = template.params) {
|
|
201
213
|
const elements = { ...template.elements };
|
|
202
214
|
for (const pageElementId of template.pageElementIds) elements[pageElementId] = createElement(OptimisticRouteSegment);
|
|
215
|
+
const reify = createAppPageSegmentStateKeyRebinder(template.params, params);
|
|
216
|
+
if (reify === null) return elements;
|
|
217
|
+
setOptimisticStateKeyRebinder(elements, reify);
|
|
218
|
+
const identities = AppElementsWire.readMetadata(template.elements).bfcacheSegmentIdentities;
|
|
219
|
+
if (Object.keys(identities).length > 0) elements[APP_BFCACHE_SEGMENT_IDENTITIES_KEY] = Object.fromEntries(Object.entries(identities).map(([id, identity]) => [id, reify(identity)]));
|
|
203
220
|
return elements;
|
|
204
221
|
}
|
|
205
222
|
function findStreamingMetadataBody(elements) {
|
|
@@ -244,9 +261,14 @@ function keepOptimisticStreamingMetadata(elements, optimisticElements, navigatio
|
|
|
244
261
|
* loading boundary does not re-trigger.
|
|
245
262
|
*/
|
|
246
263
|
function canCommitOptimisticRouteTemplate(options) {
|
|
264
|
+
const currentIdentities = AppElementsWire.readMetadata(options.currentElements).bfcacheSegmentIdentities;
|
|
265
|
+
const { isBfcacheIdentityRetained, targetElements } = options;
|
|
266
|
+
if (isBfcacheIdentityRetained && targetElements) {
|
|
267
|
+
const shownIdentities = new Set(Object.values(options.shownElements ? AppElementsWire.readMetadata(options.shownElements).bfcacheSegmentIdentities : currentIdentities));
|
|
268
|
+
for (const identity of Object.values(AppElementsWire.readMetadata(targetElements).bfcacheSegmentIdentities)) if (!shownIdentities.has(identity) && isBfcacheIdentityRetained(identity)) return false;
|
|
269
|
+
}
|
|
247
270
|
if (options.template.omittedLayoutIds.length === 0 && options.template.omittedBfcacheSegmentIds.length === 0) return true;
|
|
248
271
|
const currentLayoutIds = new Set(options.currentLayoutIds);
|
|
249
|
-
const currentIdentities = AppElementsWire.readMetadata(options.currentElements).bfcacheSegmentIdentities;
|
|
250
272
|
for (const layoutId of options.template.omittedLayoutIds) {
|
|
251
273
|
if (!currentLayoutIds.has(layoutId)) continue;
|
|
252
274
|
if (!Object.hasOwn(options.currentElements, layoutId)) continue;
|
|
@@ -302,7 +324,7 @@ function resolveOptimisticNavigationPayload(options) {
|
|
|
302
324
|
urlParts: urlParts.normalized
|
|
303
325
|
});
|
|
304
326
|
return {
|
|
305
|
-
elements: createOptimisticRouteElements(template),
|
|
327
|
+
elements: createOptimisticRouteElements(template, navigationParams),
|
|
306
328
|
params: navigationParams,
|
|
307
329
|
routeParams,
|
|
308
330
|
template,
|
|
@@ -20,9 +20,9 @@ import { hasAppPageDynamicMetadata, prepareAppPageHead, resolveActiveParallelRou
|
|
|
20
20
|
import { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryModule, wrapAppPageBoundaryElement } from "./app-page-boundary.js";
|
|
21
21
|
import { createRouteNotFoundHeadPlanOptions, recoverAppPageRouteHead, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
|
|
22
22
|
import "./app-rsc-route-matching.js";
|
|
23
|
-
import {
|
|
24
|
-
import { resolveSlotParamOverrides } from "./app-page-element-builder.js";
|
|
23
|
+
import { resolveSlotParamOverrides } from "./app-page-navigation-params.js";
|
|
25
24
|
import { createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
25
|
+
import { createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage } from "./app-page-route-wiring.js";
|
|
26
26
|
import { Fragment, Suspense, createElement } from "react";
|
|
27
27
|
//#region src/server/app-page-boundary-render.ts
|
|
28
28
|
async function AppPageBoundaryStreamedMetadata(props) {
|
|
@@ -4,8 +4,8 @@ import { _consumeRequestScopedCacheLife } from "../shims/cache-request-state.js"
|
|
|
4
4
|
import { getCollectedFetchTags } from "../shims/fetch-cache.js";
|
|
5
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
6
6
|
import { buildAppPageFontLinkHeader, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
|
|
7
|
-
import { recordAppPageRenderError, traceAppPageRender } from "./app-page-tracing.js";
|
|
8
7
|
import { buildAppPageLinkHeader, createAppPageSsrErrorHandler, isAppSsrRenderResult } from "./app-page-stream.js";
|
|
8
|
+
import { recordAppPageRenderError, traceAppPageRender } from "./app-page-tracing.js";
|
|
9
9
|
import { consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
|
|
10
10
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
11
11
|
//#region src/server/app-page-cache-render.ts
|
|
@@ -15,7 +15,7 @@ import { FetchCacheMode } from "../shims/fetch-cache-state.js";
|
|
|
15
15
|
import "../shims/fetch-cache.js";
|
|
16
16
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
17
17
|
import { WarmPprFallbackShellCachesOptions } from "./app-ppr-fallback-shell-render.js";
|
|
18
|
-
import { ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
|
|
18
|
+
import { AppPageInterceptState, ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
|
|
19
19
|
import { ReactNode } from "react";
|
|
20
20
|
import { ReactFormState } from "react-dom/client";
|
|
21
21
|
//#region src/server/app-page-dispatch.d.ts
|
|
@@ -96,10 +96,17 @@ type AppPageModule = {
|
|
|
96
96
|
revalidate?: unknown;
|
|
97
97
|
};
|
|
98
98
|
type AppPageDispatchSlot = {
|
|
99
|
+
configLayouts?: readonly (AppPageModule | null | undefined)[] | null;
|
|
100
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
99
101
|
default?: AppPageModule | null;
|
|
102
|
+
layout?: AppPageModule | null;
|
|
103
|
+
layoutIndex?: number;
|
|
100
104
|
loading?: AppPageModule | null;
|
|
101
105
|
loadings?: readonly (AppPageModule | null | undefined)[] | null;
|
|
106
|
+
name?: string;
|
|
107
|
+
ownerTreePosition?: number | null;
|
|
102
108
|
page?: AppPageModule | null;
|
|
109
|
+
routeSegments?: readonly string[] | null;
|
|
103
110
|
slotPatternParts?: readonly string[] | null;
|
|
104
111
|
slotParamNames?: readonly string[] | null;
|
|
105
112
|
};
|
|
@@ -184,6 +191,8 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
184
191
|
ensureRouteLoaded?: (route: TRoute) => unknown;
|
|
185
192
|
fetchCache?: FetchCacheMode | null;
|
|
186
193
|
findIntercept: (pathname: string) => AppPageDispatchIntercept | null;
|
|
194
|
+
/** This request's intercept, which dispatch resolves once before rendering. */
|
|
195
|
+
interceptState?: AppPageInterceptState<TRoute, unknown>;
|
|
187
196
|
formState?: ReactFormState | null;
|
|
188
197
|
actionError?: unknown;
|
|
189
198
|
actionFailed?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { closeAfterResponse, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import "../utils/protocol-headers.js";
|
|
3
3
|
import { VINEXT_INTERCEPTION_ID_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
|
|
4
|
-
import { VINEXT_MOUNTED_LAYOUTS_HEADER } from "./headers.js";
|
|
4
|
+
import { VINEXT_MOUNTED_LAYOUTS_HEADER, VINEXT_PARAMS_HEADER } from "./headers.js";
|
|
5
5
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
6
6
|
import { runInWorkStoreScope } from "../shims/internal/work-store-scope.js";
|
|
7
7
|
import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityPatternDynamic, readRouteCacheabilityState } from "../shims/cacheability-classification.js";
|
|
@@ -21,16 +21,17 @@ import { resolveUncacheableCacheControl } from "./app-page-response.js";
|
|
|
21
21
|
import { buildRscRedirectFlightStream } from "./app-rsc-redirect-flight.js";
|
|
22
22
|
import { buildAppPageSpecialErrorResponse, resolveAppPageCaughtNotFoundBoundaries, resolveAppPageShellSpecialError, resolveAppPageSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
|
|
23
23
|
import { resolveAppPageLayoutHttpAccessBoundary, resolveAppPageParentHttpAccessBoundary, resolveAppPageRootHttpAccessBoundaryTreePosition } from "./app-page-boundary.js";
|
|
24
|
+
import { resolveAppPageNavigationParams } from "./app-page-navigation-params.js";
|
|
25
|
+
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
24
26
|
import { isAppClientReference } from "./app-render-dependency.js";
|
|
25
27
|
import { resolveAppPageTraceOperation } from "./app-page-tracing.js";
|
|
26
|
-
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
27
|
-
import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
|
|
28
|
-
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
29
28
|
import { getDefaultHttpAccessFallbackModule } from "./default-http-access-fallback-modules.js";
|
|
29
|
+
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
30
30
|
import { consumeAppPageRenderObservationState, discardAppPageRenderState } from "./app-page-render-observation.js";
|
|
31
31
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
32
32
|
import { resolveAppPageMethodResponse } from "./app-page-method.js";
|
|
33
|
-
import {
|
|
33
|
+
import { resolveAppPageInterceptSegmentConfig } from "./app-page-intercept-segment-config.js";
|
|
34
|
+
import { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptState, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
|
|
34
35
|
import { applyIneligibleRouteCachePolicy, renderAppPageLifecycle } from "./app-page-render.js";
|
|
35
36
|
//#region src/server/app-page-dispatch.ts
|
|
36
37
|
function getActiveLoadingTreePositions(route) {
|
|
@@ -146,12 +147,48 @@ function hasNoManifestAdmissionState(routePattern) {
|
|
|
146
147
|
}, admission.representation, admission.routePathname) === null;
|
|
147
148
|
}
|
|
148
149
|
async function dispatchAppPage(options) {
|
|
149
|
-
const dispatch = () => runWithFetchDedupe(() => dispatchAppPageInner(options));
|
|
150
|
+
const dispatch = () => runWithFetchDedupe(async () => dispatchAppPageInner(await withResolvedIntercept(options)));
|
|
150
151
|
let response;
|
|
151
152
|
if (!options.pprFallbackShell || !options.pprRuntime) response = await dispatch();
|
|
152
153
|
else response = await options.pprRuntime.run(options.pprFallbackShell, dispatch);
|
|
153
154
|
return options.isRscRequest ? response : traceResponseStart(response);
|
|
154
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Resolves the request's intercept once, for the render and its cache reads.
|
|
158
|
+
*
|
|
159
|
+
* Next.js renders an interception as its own route even when its source is the
|
|
160
|
+
* matched route (`app/shots/[id]` beside `app/shots/@modal/(.)[id]`, from
|
|
161
|
+
* `/shots/1` to `/shots/2`). vinext renders that through the matched route's
|
|
162
|
+
* own page render, so the interception's segment config replaces the route's
|
|
163
|
+
* before that render reads it.
|
|
164
|
+
*/
|
|
165
|
+
async function withResolvedIntercept(options) {
|
|
166
|
+
const interceptState = await resolveAppPageInterceptState({
|
|
167
|
+
cleanPathname: options.cleanPathname,
|
|
168
|
+
currentRoute: options.route,
|
|
169
|
+
findIntercept: options.findIntercept,
|
|
170
|
+
getSourceRoute: options.getSourceRoute,
|
|
171
|
+
interceptState: options.interceptState,
|
|
172
|
+
isRscRequest: options.isRscRequest
|
|
173
|
+
});
|
|
174
|
+
if (interceptState.kind !== "current-route") return {
|
|
175
|
+
...options,
|
|
176
|
+
interceptState
|
|
177
|
+
};
|
|
178
|
+
const config = resolveAppPageInterceptSegmentConfig(options.route, toInterceptOptions(options.interceptionContext, interceptState.intercept));
|
|
179
|
+
return {
|
|
180
|
+
...options,
|
|
181
|
+
interceptState,
|
|
182
|
+
dynamicConfig: config.dynamicConfig,
|
|
183
|
+
dynamicStaleTimeSeconds: config.dynamicStaleTimeSeconds,
|
|
184
|
+
fetchCache: config.fetchCacheMode,
|
|
185
|
+
hasAnyGenerateStaticParams: config.hasAnyGenerateStaticParams,
|
|
186
|
+
hasGenerateStaticParams: config.hasGenerateStaticParams,
|
|
187
|
+
isEdgeRuntime: config.isEdgeRuntime,
|
|
188
|
+
isStaticGenerationEdgeRuntime: config.isStaticGenerationEdgeRuntime,
|
|
189
|
+
revalidateSeconds: config.revalidateSeconds
|
|
190
|
+
};
|
|
191
|
+
}
|
|
155
192
|
async function dispatchAppPageInner(options) {
|
|
156
193
|
const route = options.route;
|
|
157
194
|
beginRouteCacheability("app-page", route.pattern);
|
|
@@ -206,6 +243,7 @@ async function dispatchAppPageInner(options) {
|
|
|
206
243
|
isDynamicError,
|
|
207
244
|
isForceDynamic,
|
|
208
245
|
isForceStatic,
|
|
246
|
+
isPrerender,
|
|
209
247
|
isProduction: options.isProduction,
|
|
210
248
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
211
249
|
isRscRequest: options.isRscRequest,
|
|
@@ -280,6 +318,7 @@ async function dispatchAppPageInner(options) {
|
|
|
280
318
|
getSourceRoute(sourceRouteIndex) {
|
|
281
319
|
return options.getSourceRoute(sourceRouteIndex);
|
|
282
320
|
},
|
|
321
|
+
interceptState: options.interceptState,
|
|
283
322
|
isRscRequest: options.isRscRequest,
|
|
284
323
|
toInterceptOpts(intercept) {
|
|
285
324
|
return toInterceptOptions(options.interceptionContext, intercept);
|
|
@@ -320,9 +359,10 @@ async function dispatchAppPageInner(options) {
|
|
|
320
359
|
isDynamicRscRequest: options.pprRuntime !== void 0 && options.isRscRequest && options.request.headers.get("Next-Router-Prefetch") !== "1" && options.renderedConcreteUrlPaths?.has(options.cleanPathname) !== true,
|
|
321
360
|
renderFreshPageForCache: async ({ renderDocument }) => {
|
|
322
361
|
const revalidationTarget = await resolveCacheRenderTarget();
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const
|
|
362
|
+
const revalidationInterceptConfig = revalidationTarget.interceptOpts ? resolveAppPageInterceptSegmentConfig(revalidationTarget.route, revalidationTarget.interceptOpts) : null;
|
|
363
|
+
const revalidationDynamicConfig = revalidationInterceptConfig ? revalidationInterceptConfig.dynamicConfig : options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0);
|
|
364
|
+
const revalidationConfigRevalidateSeconds = revalidationInterceptConfig ? revalidationTarget.route === route ? currentRevalidateSeconds : revalidationInterceptConfig.revalidateSeconds : options.resolveRouteRevalidateSeconds?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? currentRevalidateSeconds : null);
|
|
365
|
+
const revalidationRouteRevalidateSeconds = revalidationTarget.route === route ? void 0 : revalidationConfigRevalidateSeconds ?? (revalidationDynamicConfig === "force-static" || revalidationDynamicConfig === "error" || options.isProduction && options.pprRuntime === void 0 && (revalidationInterceptConfig?.isStaticEligible ?? options.resolveRouteStaticEligible(revalidationTarget.route)) ? Infinity : null);
|
|
326
366
|
const revalidationRouteHead = {
|
|
327
367
|
observeSearchParams: revalidationDynamicConfig !== "force-static",
|
|
328
368
|
searchParams: new URLSearchParams(),
|
|
@@ -332,7 +372,7 @@ async function dispatchAppPageInner(options) {
|
|
|
332
372
|
return runAppPageRevalidationContext({
|
|
333
373
|
cleanPathname: options.cleanPathname,
|
|
334
374
|
displayPathname: options.displayPathname,
|
|
335
|
-
currentFetchCacheMode: options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
375
|
+
currentFetchCacheMode: revalidationInterceptConfig ? revalidationInterceptConfig.fetchCacheMode : options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
336
376
|
currentFetchRevalidate: revalidationConfigRevalidateSeconds,
|
|
337
377
|
draftModeSecret: options.draftModeSecret,
|
|
338
378
|
dynamicConfig: revalidationDynamicConfig,
|
|
@@ -459,6 +499,7 @@ async function dispatchAppPageInner(options) {
|
|
|
459
499
|
isDynamicError,
|
|
460
500
|
isForceDynamic,
|
|
461
501
|
isForceStatic,
|
|
502
|
+
isPrerender,
|
|
462
503
|
isProduction: options.isProduction,
|
|
463
504
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
464
505
|
isRscRequest: options.isRscRequest,
|
|
@@ -475,9 +516,9 @@ async function dispatchAppPageInner(options) {
|
|
|
475
516
|
}
|
|
476
517
|
const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
|
|
477
518
|
if (fallbackShellResponse) return fallbackShellResponse;
|
|
478
|
-
let
|
|
479
|
-
let
|
|
480
|
-
let
|
|
519
|
+
let interceptConfig = null;
|
|
520
|
+
let isInterceptKnownDynamic = false;
|
|
521
|
+
let isInterceptRequestIndependent = false;
|
|
481
522
|
const renderedRouteHead = {
|
|
482
523
|
observeSearchParams: !isForceStatic,
|
|
483
524
|
searchParams: pageSearchParams,
|
|
@@ -489,26 +530,27 @@ async function dispatchAppPageInner(options) {
|
|
|
489
530
|
};
|
|
490
531
|
const interceptResult = await resolveAppPageIntercept({
|
|
491
532
|
async buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams) {
|
|
492
|
-
|
|
493
|
-
|
|
533
|
+
interceptConfig ??= resolveAppPageInterceptSegmentConfig(interceptRoute, interceptOpts);
|
|
534
|
+
const interceptDynamicConfig = interceptConfig.dynamicConfig;
|
|
535
|
+
if (interceptDynamicConfig === "force-static" || interceptDynamicConfig === "error") {
|
|
494
536
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
495
537
|
setHeadersContext(createStaticGenerationHeadersContext({
|
|
496
538
|
draftModeEnabled: isDraftMode,
|
|
497
539
|
draftModeSecret: options.draftModeSecret,
|
|
498
|
-
dynamicConfig:
|
|
540
|
+
dynamicConfig: interceptDynamicConfig,
|
|
499
541
|
routeKind: "page",
|
|
500
542
|
routePattern: interceptRoute.pattern
|
|
501
543
|
}));
|
|
502
544
|
} else setHeadersContext(requestHeadersContext);
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
setCurrentFetchCacheMode(
|
|
506
|
-
setCurrentFetchRevalidate(
|
|
507
|
-
setCurrentForceDynamicFetchDefault(
|
|
545
|
+
isInterceptKnownDynamic = interceptDynamicConfig === "force-dynamic" || interceptConfig.revalidateSeconds === 0;
|
|
546
|
+
isInterceptRequestIndependent = interceptDynamicConfig === "force-static" || interceptDynamicConfig === "error";
|
|
547
|
+
setCurrentFetchCacheMode(interceptConfig.fetchCacheMode);
|
|
548
|
+
setCurrentFetchRevalidate(interceptConfig.revalidateSeconds);
|
|
549
|
+
setCurrentForceDynamicFetchDefault(interceptDynamicConfig === "force-dynamic");
|
|
508
550
|
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, {
|
|
509
|
-
isForceStatic:
|
|
510
|
-
observeMetadataSearchParamsAccess:
|
|
511
|
-
observePageSearchParamsAccess:
|
|
551
|
+
isForceStatic: interceptDynamicConfig === "force-static",
|
|
552
|
+
observeMetadataSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
553
|
+
observePageSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
512
554
|
isUncacheableRender,
|
|
513
555
|
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
514
556
|
placeStreamedMetadataInHead: options.renderWholeDocument === true,
|
|
@@ -526,18 +568,20 @@ async function dispatchAppPageInner(options) {
|
|
|
526
568
|
getSourceRoute(sourceRouteIndex) {
|
|
527
569
|
return options.getSourceRoute(sourceRouteIndex);
|
|
528
570
|
},
|
|
571
|
+
interceptState: options.interceptState,
|
|
529
572
|
isRscRequest: options.isRscRequest,
|
|
530
573
|
resolveNavigationParams(sourceRoute, navigationParams, pathname, interceptOpts) {
|
|
531
574
|
return resolveAppPageNavigationParams(sourceRoute, navigationParams, pathname, interceptOpts);
|
|
532
575
|
},
|
|
533
|
-
renderInterceptResponse(sourceRoute, interceptElement) {
|
|
576
|
+
renderInterceptResponse(sourceRoute, interceptElement, navigationParams) {
|
|
534
577
|
const interceptOnError = options.createRscOnErrorHandler(options.cleanPathname, sourceRoute.pattern);
|
|
535
578
|
const interceptStream = options.renderToReadableStream(interceptElement, { onError: interceptOnError });
|
|
536
579
|
const interceptHeaders = new Headers({
|
|
537
580
|
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
538
581
|
Vary: VINEXT_RSC_VARY_HEADER
|
|
539
582
|
});
|
|
540
|
-
if (
|
|
583
|
+
if (Object.keys(navigationParams).length > 0) interceptHeaders.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(navigationParams)));
|
|
584
|
+
if (!(options.pprRuntime !== void 0 || interceptConfig?.isStaticEligible === true) || isDraftMode || isInterceptKnownDynamic || options.isProduction && !isInterceptRequestIndependent) interceptHeaders.set("Cache-Control", resolveUncacheableCacheControl(options.isProduction));
|
|
541
585
|
mergeMiddlewareResponseHeaders(interceptHeaders, options.middlewareContext.headers);
|
|
542
586
|
applyRscCompatibilityIdHeader(interceptHeaders);
|
|
543
587
|
applyRscDeploymentIdHeader(interceptHeaders);
|
|
@@ -546,11 +590,10 @@ async function dispatchAppPageInner(options) {
|
|
|
546
590
|
headers: interceptHeaders
|
|
547
591
|
});
|
|
548
592
|
},
|
|
549
|
-
async resolveSearchParams(sourceRoute, searchParams) {
|
|
593
|
+
async resolveSearchParams(sourceRoute, searchParams, interceptOpts) {
|
|
550
594
|
await options.ensureRouteLoaded?.(sourceRoute);
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return interceptDynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
595
|
+
interceptConfig = resolveAppPageInterceptSegmentConfig(sourceRoute, interceptOpts);
|
|
596
|
+
return interceptConfig.dynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
554
597
|
},
|
|
555
598
|
searchParams: options.searchParams,
|
|
556
599
|
setNavigationContext: options.setNavigationContext,
|