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.
Files changed (83) hide show
  1. package/README.md +1 -1
  2. package/dist/build/action-owner-manifest.js +1 -0
  3. package/dist/check.js +1 -1
  4. package/dist/config/config-matchers.js +2 -2
  5. package/dist/config/destination-params.js +5 -2
  6. package/dist/config/next-config.d.ts +16 -1
  7. package/dist/config/next-config.js +31 -1
  8. package/dist/entries/app-rsc-entry.js +41 -18
  9. package/dist/entries/app-rsc-manifest.js +4 -0
  10. package/dist/entries/pages-server-entry.js +2 -0
  11. package/dist/index.js +15 -12
  12. package/dist/init-cloudflare.js +18 -2
  13. package/dist/plugins/css-target.d.ts +18 -0
  14. package/dist/plugins/css-target.js +93 -0
  15. package/dist/routing/app-route-graph.d.ts +10 -0
  16. package/dist/routing/app-route-graph.js +15 -1
  17. package/dist/server/api-handler.d.ts +2 -0
  18. package/dist/server/api-handler.js +3 -5
  19. package/dist/server/app-action-forwarding.js +3 -1
  20. package/dist/server/app-browser-entry.js +21 -4
  21. package/dist/server/app-elements.d.ts +3 -0
  22. package/dist/server/app-elements.js +14 -1
  23. package/dist/server/app-fallback-renderer.js +2 -2
  24. package/dist/server/app-optimistic-routing.d.ts +12 -1
  25. package/dist/server/app-optimistic-routing.js +38 -16
  26. package/dist/server/app-page-boundary-render.js +2 -2
  27. package/dist/server/app-page-cache-render.js +1 -1
  28. package/dist/server/app-page-dispatch.d.ts +10 -1
  29. package/dist/server/app-page-dispatch.js +73 -30
  30. package/dist/server/app-page-element-builder.d.ts +9 -20
  31. package/dist/server/app-page-element-builder.js +37 -49
  32. package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
  33. package/dist/server/app-page-intercept-segment-config.js +90 -0
  34. package/dist/server/app-page-navigation-params.d.ts +23 -0
  35. package/dist/server/app-page-navigation-params.js +49 -0
  36. package/dist/server/app-page-render.d.ts +5 -2
  37. package/dist/server/app-page-render.js +17 -3
  38. package/dist/server/app-page-request.d.ts +24 -2
  39. package/dist/server/app-page-request.js +10 -10
  40. package/dist/server/app-page-route-wiring.d.ts +10 -0
  41. package/dist/server/app-page-route-wiring.js +16 -12
  42. package/dist/server/app-page-segment-plan.js +9 -1
  43. package/dist/server/app-page-segment-state.d.ts +9 -0
  44. package/dist/server/app-page-segment-state.js +54 -1
  45. package/dist/server/app-response-stage-entry.js +1 -0
  46. package/dist/server/app-route-module-loader.d.ts +2 -0
  47. package/dist/server/app-route-module-loader.js +1 -0
  48. package/dist/server/app-rsc-handler.d.ts +10 -1
  49. package/dist/server/app-rsc-handler.js +75 -43
  50. package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
  51. package/dist/server/app-rsc-response-finalizer.js +11 -1
  52. package/dist/server/app-rsc-route-matching.d.ts +14 -0
  53. package/dist/server/app-rsc-route-matching.js +42 -18
  54. package/dist/server/app-server-action-execution.js +16 -10
  55. package/dist/server/cache-control.d.ts +2 -0
  56. package/dist/server/cache-control.js +3 -1
  57. package/dist/server/image-local-patterns.d.ts +21 -0
  58. package/dist/server/image-local-patterns.js +59 -0
  59. package/dist/server/image-optimization.d.ts +23 -22
  60. package/dist/server/image-optimization.js +12 -2
  61. package/dist/server/metadata-route-response.js +24 -6
  62. package/dist/server/nitro-public-files-plugin.js +20 -8
  63. package/dist/server/pages-data-route.d.ts +5 -1
  64. package/dist/server/pages-data-route.js +14 -6
  65. package/dist/server/pages-request-pipeline.js +6 -5
  66. package/dist/server/pages-request-stage-entry.js +1 -0
  67. package/dist/server/prod-server.js +17 -9
  68. package/dist/server/request-pipeline.d.ts +5 -0
  69. package/dist/server/request-pipeline.js +11 -1
  70. package/dist/server/response-stage-cacheability.d.ts +7 -0
  71. package/dist/server/response-stage-cacheability.js +6 -5
  72. package/dist/server/worker-image-optimization.d.ts +2 -2
  73. package/dist/server/worker-image-optimization.js +18 -3
  74. package/dist/server/worker-utils.d.ts +8 -0
  75. package/dist/server/worker-utils.js +19 -2
  76. package/dist/shims/image-props.d.ts +6 -0
  77. package/dist/shims/image-props.js +39 -3
  78. package/dist/shims/image.js +3 -3
  79. package/dist/shims/slot.d.ts +3 -0
  80. package/dist/shims/slot.js +67 -9
  81. package/dist/utils/base-path.d.ts +7 -0
  82. package/dist/utils/base-path.js +11 -1
  83. 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, nextConfig) {
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
- const basePath = nextConfig?.basePath;
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
- return new Response(response.body, {
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: () => browserNavigationController.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
- const identityKey = JSON.stringify(boundSegmentKeys);
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 { createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage } from "./app-page-route-wiring.js";
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 { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
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 revalidationDynamicConfig = options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0);
324
- const revalidationConfigRevalidateSeconds = options.resolveRouteRevalidateSeconds?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? currentRevalidateSeconds : null);
325
- const revalidationRouteRevalidateSeconds = revalidationTarget.route === route ? void 0 : revalidationConfigRevalidateSeconds ?? (revalidationDynamicConfig === "force-static" || revalidationDynamicConfig === "error" || options.isProduction && options.pprRuntime === void 0 && options.resolveRouteStaticEligible(revalidationTarget.route) ? Infinity : null);
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 interceptDynamicConfig;
479
- let interceptDynamicConfigResolved = false;
480
- let isInterceptSourceKnownDynamic = false;
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
- const sourceDynamicConfig = interceptDynamicConfigResolved ? interceptDynamicConfig : options.resolveRouteDynamicConfig?.(interceptRoute);
493
- if (sourceDynamicConfig === "force-static" || sourceDynamicConfig === "error") {
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: sourceDynamicConfig,
540
+ dynamicConfig: interceptDynamicConfig,
499
541
  routeKind: "page",
500
542
  routePattern: interceptRoute.pattern
501
543
  }));
502
544
  } else setHeadersContext(requestHeadersContext);
503
- const sourceRevalidateSeconds = options.resolveRouteRevalidateSeconds?.(interceptRoute) ?? null;
504
- isInterceptSourceKnownDynamic = sourceDynamicConfig === "force-dynamic" || sourceRevalidateSeconds === 0;
505
- setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(interceptRoute) ?? null);
506
- setCurrentFetchRevalidate(sourceRevalidateSeconds);
507
- setCurrentForceDynamicFetchDefault(sourceDynamicConfig === "force-dynamic");
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: sourceDynamicConfig === "force-static",
510
- observeMetadataSearchParamsAccess: sourceDynamicConfig !== "force-static",
511
- observePageSearchParamsAccess: sourceDynamicConfig !== "force-static",
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 (!(options.pprRuntime !== void 0 || options.resolveRouteStaticEligible(sourceRoute)) || isDraftMode || isInterceptSourceKnownDynamic) interceptHeaders.set("Cache-Control", resolveUncacheableCacheControl(options.isProduction));
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
- interceptDynamicConfig = options.resolveRouteDynamicConfig?.(sourceRoute);
552
- interceptDynamicConfigResolved = true;
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,