vinext 0.2.0 → 0.2.1

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 (128) hide show
  1. package/dist/build/css-url-assets.d.ts +3 -1
  2. package/dist/build/css-url-assets.js +18 -1
  3. package/dist/build/inject-pregenerated-paths.d.ts +3 -0
  4. package/dist/build/inject-pregenerated-paths.js +4 -1
  5. package/dist/build/prerender-server-entry.d.ts +1 -0
  6. package/dist/build/prerender-server-entry.js +49 -0
  7. package/dist/build/prerender-server-pool.d.ts +44 -0
  8. package/dist/build/prerender-server-pool.js +194 -0
  9. package/dist/build/prerender.js +86 -22
  10. package/dist/build/run-prerender.js +2 -1
  11. package/dist/check.d.ts +4 -6
  12. package/dist/check.js +8 -9
  13. package/dist/cli.js +1 -1
  14. package/dist/client/vinext-next-data.d.ts +4 -1
  15. package/dist/config/config-matchers.js +33 -11
  16. package/dist/config/next-config.d.ts +36 -6
  17. package/dist/config/next-config.js +16 -2
  18. package/dist/entries/app-browser-entry.js +5 -1
  19. package/dist/entries/app-rsc-entry.d.ts +3 -2
  20. package/dist/entries/app-rsc-entry.js +4 -0
  21. package/dist/entries/pages-client-entry.js +14 -3
  22. package/dist/entries/pages-server-entry.js +18 -4
  23. package/dist/index.js +320 -25
  24. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
  25. package/dist/packages/cloudflare/src/deploy.js +1 -5
  26. package/dist/packages/cloudflare/src/tpr.js +26 -5
  27. package/dist/plugins/fonts.js +1 -1
  28. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  29. package/dist/plugins/og-assets.js +2 -1
  30. package/dist/plugins/optimize-imports.js +1 -1
  31. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  32. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  33. package/dist/plugins/sass.d.ts +17 -1
  34. package/dist/plugins/sass.js +74 -1
  35. package/dist/plugins/styled-jsx.d.ts +16 -0
  36. package/dist/plugins/styled-jsx.js +149 -0
  37. package/dist/routing/app-route-graph.js +22 -16
  38. package/dist/routing/file-matcher.d.ts +8 -1
  39. package/dist/routing/file-matcher.js +15 -3
  40. package/dist/server/app-browser-entry.js +46 -14
  41. package/dist/server/app-browser-navigation-controller.js +1 -1
  42. package/dist/server/app-browser-server-action-client.js +5 -3
  43. package/dist/server/app-browser-state.d.ts +1 -0
  44. package/dist/server/app-browser-state.js +2 -2
  45. package/dist/server/app-browser-visible-commit.js +1 -1
  46. package/dist/server/app-page-boundary.js +2 -1
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +3 -3
  49. package/dist/server/app-page-cache.js +23 -6
  50. package/dist/server/app-page-dispatch.d.ts +1 -0
  51. package/dist/server/app-page-dispatch.js +25 -8
  52. package/dist/server/app-page-element-builder.js +1 -0
  53. package/dist/server/app-page-execution.js +2 -1
  54. package/dist/server/app-page-render-identity.d.ts +1 -0
  55. package/dist/server/app-page-render-identity.js +2 -1
  56. package/dist/server/app-page-render.d.ts +2 -0
  57. package/dist/server/app-page-render.js +67 -16
  58. package/dist/server/app-page-response.d.ts +7 -0
  59. package/dist/server/app-page-response.js +16 -4
  60. package/dist/server/app-page-stream.d.ts +2 -1
  61. package/dist/server/app-page-stream.js +1 -1
  62. package/dist/server/app-route-handler-execution.js +1 -1
  63. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  64. package/dist/server/app-route-tree-prefetch.js +187 -0
  65. package/dist/server/app-router-entry.js +1 -1
  66. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  67. package/dist/server/app-rsc-cache-busting.js +9 -4
  68. package/dist/server/app-rsc-handler.d.ts +6 -0
  69. package/dist/server/app-rsc-handler.js +89 -11
  70. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  71. package/dist/server/app-rsc-render-mode.js +4 -1
  72. package/dist/server/app-rsc-request-normalization.d.ts +3 -4
  73. package/dist/server/app-rsc-request-normalization.js +4 -5
  74. package/dist/server/app-server-action-execution.js +4 -3
  75. package/dist/server/app-ssr-entry.js +3 -3
  76. package/dist/server/cache-control.d.ts +3 -1
  77. package/dist/server/cache-control.js +13 -1
  78. package/dist/server/dev-server.d.ts +11 -1
  79. package/dist/server/dev-server.js +78 -20
  80. package/dist/server/headers.d.ts +6 -2
  81. package/dist/server/headers.js +11 -5
  82. package/dist/server/isr-cache.d.ts +2 -1
  83. package/dist/server/isr-cache.js +7 -3
  84. package/dist/server/pages-data-route.d.ts +4 -2
  85. package/dist/server/pages-data-route.js +18 -4
  86. package/dist/server/pages-dev-module-url.d.ts +2 -1
  87. package/dist/server/pages-dev-module-url.js +6 -3
  88. package/dist/server/pages-node-compat.d.ts +12 -1
  89. package/dist/server/pages-node-compat.js +50 -1
  90. package/dist/server/pages-page-data.d.ts +9 -0
  91. package/dist/server/pages-page-data.js +17 -9
  92. package/dist/server/pages-page-handler.js +19 -7
  93. package/dist/server/pages-page-response.d.ts +1 -0
  94. package/dist/server/pages-page-response.js +3 -2
  95. package/dist/server/pages-request-pipeline.d.ts +8 -6
  96. package/dist/server/pages-request-pipeline.js +30 -6
  97. package/dist/server/pages-router-entry.js +1 -1
  98. package/dist/server/prod-server.d.ts +4 -2
  99. package/dist/server/prod-server.js +38 -22
  100. package/dist/server/request-pipeline.js +1 -1
  101. package/dist/shims/cache-handler.js +8 -1
  102. package/dist/shims/cache.js +3 -0
  103. package/dist/shims/fetch-cache.d.ts +3 -1
  104. package/dist/shims/fetch-cache.js +77 -52
  105. package/dist/shims/form.d.ts +1 -1
  106. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  107. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  108. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
  109. package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
  110. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
  111. package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
  112. package/dist/shims/internal/pages-data-target.d.ts +8 -3
  113. package/dist/shims/internal/pages-data-target.js +9 -4
  114. package/dist/shims/link.d.ts +1 -1
  115. package/dist/shims/link.js +179 -42
  116. package/dist/shims/navigation.d.ts +15 -3
  117. package/dist/shims/navigation.js +202 -39
  118. package/dist/shims/navigation.react-server.js +1 -1
  119. package/dist/shims/request-context.js +18 -0
  120. package/dist/shims/router.js +31 -15
  121. package/dist/shims/unified-request-context.js +1 -0
  122. package/dist/typegen.js +1 -1
  123. package/dist/utils/middleware-request-headers.js +1 -1
  124. package/dist/utils/protocol-headers.d.ts +7 -1
  125. package/dist/utils/protocol-headers.js +7 -1
  126. package/dist/utils/vite-version.d.ts +2 -0
  127. package/dist/utils/vite-version.js +11 -1
  128. package/package.json +2 -2
@@ -13,19 +13,20 @@ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../s
13
13
  import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
14
14
  import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
15
15
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
16
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
16
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
17
17
  import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
18
18
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
19
19
  import "../client/instrumentation-client.js";
20
- import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
21
- import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, resolveServerActionOperationLane } from "./app-browser-action-result.js";
22
- import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
23
20
  import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
24
21
  import { readHistoryStatePreviousNextUrl } from "./app-history-state.js";
25
22
  import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
26
23
  import { blockDangerousStreamedRscRedirect } from "./app-browser-rsc-redirect.js";
27
24
  import { navigationPlanner } from "./navigation-planner.js";
28
- import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, getClientNavigationRenderContext, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
25
+ import { resolveHybridClientRewriteHref } from "../shims/internal/hybrid-client-route-owner.js";
26
+ import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
27
+ import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
28
+ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, resolveServerActionOperationLane } from "./app-browser-action-result.js";
29
+ import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
29
30
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
30
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";
31
32
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch } from "./app-browser-navigation-controller.js";
@@ -193,6 +194,21 @@ function clearClientNavigationCaches() {
193
194
  clearPrefetchState();
194
195
  historyController.invalidateRestorableClientState();
195
196
  }
197
+ function normalizeBrowserRscUrlForReuse(url) {
198
+ if (!url) return null;
199
+ try {
200
+ const parsed = new URL(url, window.location.origin);
201
+ stripRscCacheBustingSearchParam(parsed);
202
+ return `${parsed.pathname}${parsed.search}`;
203
+ } catch {
204
+ return null;
205
+ }
206
+ }
207
+ function isAlternatePrefetchResponseUrl(responseUrl, additionalRscUrls) {
208
+ const normalizedResponseUrl = normalizeBrowserRscUrlForReuse(responseUrl);
209
+ if (normalizedResponseUrl === null) return false;
210
+ return additionalRscUrls.some((additionalRscUrl) => normalizeBrowserRscUrlForReuse(additionalRscUrl) === normalizedResponseUrl);
211
+ }
196
212
  function isSettledPrefetchCacheEntry(entry) {
197
213
  return entry.outcome === "cache-seeded" && entry.pending === void 0 && entry.snapshot !== void 0;
198
214
  }
@@ -242,6 +258,7 @@ async function learnOptimisticRouteTemplatesFromPrefetchCache(options) {
242
258
  if (optimisticRouteTemplateSources.has(sourceKey)) continue;
243
259
  if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
244
260
  if (!isSettledPrefetchCacheEntry(entry)) continue;
261
+ if (entry.prefetchKind === "route-tree") continue;
245
262
  const promise = learnOptimisticRouteTemplateFromPrefetch({
246
263
  cacheKey,
247
264
  entry,
@@ -545,9 +562,17 @@ function BrowserRoot({ hydrationCachePublication, initialElements, initialNaviga
545
562
  setWindowNextInternalSourcePage(AppElementsWire.readMetadata(treeState.elements).sourcePage);
546
563
  }, [treeState.elements]);
547
564
  useLayoutEffect(() => {
548
- setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
565
+ const previousMountedSlotsHeader = getMountedSlotsHeader();
566
+ const nextMountedSlotsHeader = getMountedSlotIdsHeader(stateRef.current.elements);
567
+ setMountedSlotsHeader(nextMountedSlotsHeader);
549
568
  removeStylesheetLinksCoveredByInlineCss();
550
- getNavigationRuntime()?.functions.pingVisibleLinks?.();
569
+ if (previousMountedSlotsHeader === nextMountedSlotsHeader) return;
570
+ const pingTimer = window.setTimeout(() => {
571
+ getNavigationRuntime()?.functions.pingVisibleLinks?.();
572
+ }, 0);
573
+ return () => {
574
+ window.clearTimeout(pingTimer);
575
+ };
551
576
  }, [treeState.elements]);
552
577
  useLayoutEffect(() => {
553
578
  if (treeState.renderId !== 0) return;
@@ -748,14 +773,14 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
748
773
  ...initialRscBootstrap?.dynamicStaleTimeSeconds !== void 0 ? { dynamicStaleTimeSeconds: initialRscBootstrap.dynamicStaleTimeSeconds } : {},
749
774
  mountedSlotsHeader,
750
775
  paramsHeader: encodeURIComponent(JSON.stringify(initialParams)),
776
+ renderedPathAndSearch: null,
751
777
  url: rscUrl
752
778
  };
753
779
  const fallbackTtlMs = initialRscBootstrap?.initialCacheKind === "static" ? PREFETCH_CACHE_TTL : DYNAMIC_NAVIGATION_CACHE_TTL;
754
780
  hydrationCachePublication.publish(() => {
755
781
  if (cacheGeneration !== clientNavigationCacheGeneration) return () => {};
756
782
  if (isCacheRestorableAppPayloadMetadata(metadata)) return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader);
757
- seedPrefetchResponseSnapshot(rscUrl, snapshot, metadata.interceptionContext, mountedSlotsHeader, fallbackTtlMs);
758
- return () => deletePrefetchResponseSnapshot(rscUrl, snapshot, metadata.interceptionContext);
783
+ return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader, elements);
759
784
  });
760
785
  }).catch(() => {});
761
786
  historyController.writeBootstrapHistoryMetadata();
@@ -867,6 +892,8 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
867
892
  renderMode: navigationKind === "refresh" ? APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI : void 0
868
893
  });
869
894
  const rscUrl = await createRscRequestUrl(url.pathname + url.search, requestHeaders);
895
+ const rewrittenNavigationHref = navigationKind === "navigate" ? resolveHybridClientRewriteHref(currentHref, __basePath) : null;
896
+ const additionalPrefetchRscUrls = rewrittenNavigationHref && rewrittenNavigationHref !== currentHref ? [await createRscRequestUrl(rewrittenNavigationHref, requestHeaders)] : [];
870
897
  const visitedResponseCandidate = shouldBypassNavigationCache ? {
871
898
  cacheKey: AppElementsWire.encodeCacheKey(rscUrl, requestInterceptionContext),
872
899
  entry: null,
@@ -883,7 +910,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
883
910
  visitedResponse
884
911
  });
885
912
  let routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
886
- const hasPrefetchCandidate = prefetchProbeDecision.kind === "probe" && hasPrefetchCacheEntryForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, { notifyInvalidation: false });
913
+ const hasPrefetchCandidate = prefetchProbeDecision.kind === "probe" && hasPrefetchCacheEntryForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
914
+ additionalRscUrls: additionalPrefetchRscUrls,
915
+ notifyInvalidation: false
916
+ });
887
917
  const reuseDecision = navigationPlanner.classifyNavigationReuse({
888
918
  bypassNavigationCache: shouldBypassNavigationCache,
889
919
  navigationKind,
@@ -941,12 +971,15 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
941
971
  let navResponseUrl = null;
942
972
  let fallbackReuseDecision = reuseDecision;
943
973
  if (reuseDecision.kind === "consumePrefetch") {
944
- const prefetchedResponse = await consumePrefetchResponseForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, { shouldConsume: () => browserNavigationController.isCurrentNavigation(navId) });
974
+ const prefetchedResponse = await consumePrefetchResponseForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
975
+ additionalRscUrls: additionalPrefetchRscUrls,
976
+ shouldConsume: () => browserNavigationController.isCurrentNavigation(navId)
977
+ });
945
978
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
946
979
  if (prefetchedResponse) {
947
980
  navResponse = restoreRscResponse(prefetchedResponse, false);
948
981
  navResponseExpiresAt = prefetchedResponse.expiresAt;
949
- navResponseUrl = prefetchedResponse.url;
982
+ navResponseUrl = isAlternatePrefetchResponseUrl(prefetchedResponse.url, additionalPrefetchRscUrls) ? rscUrl : prefetchedResponse.url;
950
983
  }
951
984
  if (!navResponse) {
952
985
  routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
@@ -1053,7 +1086,6 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1053
1086
  committedState = state;
1054
1087
  if (activeNavigationAbortController === navigationAbortController) activeNavigationAbortController = null;
1055
1088
  }, detachedNavigationCommits ? "authoritative" : void 0) !== "committed") return;
1056
- if (!browserNavigationController.isCurrentNavigation(navId)) return;
1057
1089
  try {
1058
1090
  const renderedElements = await rscPayload;
1059
1091
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
@@ -1074,7 +1106,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1074
1106
  if (isCacheRestorableAppPayloadMetadata(metadata)) {
1075
1107
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
1076
1108
  storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, navParams, PREFETCH_CACHE_TTL, mountedSlotsHeader);
1077
- } else if (committedState !== null && getMountedSlotIdsHeader(committedState.elements) === null) {
1109
+ } else if (committedState !== null) {
1078
1110
  const state = committedState;
1079
1111
  const committedElements = {
1080
1112
  ...state.elements,
@@ -1,8 +1,8 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
3
3
  import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
4
- import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
5
4
  import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
5
+ import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
6
6
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit } from "./app-browser-state.js";
7
7
  import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
8
8
  import { startTransition, useInsertionEffect, useLayoutEffect } from "react";
@@ -1,3 +1,4 @@
1
+ import { hasBasePath } from "../utils/base-path.js";
1
2
  import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER } from "./headers.js";
2
3
  import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
3
4
  import { AppElementsWire } from "./app-elements-wire.js";
@@ -9,7 +10,7 @@ import { applyServerActionResultDecision } from "./app-browser-server-action-nav
9
10
  import { throwOnServerActionNotFound } from "./server-action-not-found.js";
10
11
  import { createFromFetch, createTemporaryReferenceSet, encodeReply } from "@vitejs/plugin-rsc/browser";
11
12
  //#region src/server/app-browser-server-action-client.ts
12
- function resolveActionRedirectTarget(response, performHardNavigation) {
13
+ function resolveActionRedirectTarget(response, basePath, performHardNavigation) {
13
14
  const actionRedirect = response.headers.get(ACTION_REDIRECT_HEADER);
14
15
  if (!actionRedirect) return null;
15
16
  if (isDangerousScheme(actionRedirect)) {
@@ -25,7 +26,7 @@ function resolveActionRedirectTarget(response, performHardNavigation) {
25
26
  if (!baseDir.endsWith("/")) baseDir += "/";
26
27
  redirectUrl = new URL(actionRedirect, `${baseParsed.origin}${baseDir}${baseParsed.search}`);
27
28
  }
28
- if (redirectUrl.origin !== window.location.origin) {
29
+ if (redirectUrl.origin !== window.location.origin || basePath !== "" && !hasBasePath(redirectUrl.pathname, basePath)) {
29
30
  performHardNavigation(actionRedirect);
30
31
  return null;
31
32
  }
@@ -60,6 +61,7 @@ async function invokeClientServerAction(id, args, actionInitiation, deps) {
60
61
  actionId: id,
61
62
  basePath: deps.basePath,
62
63
  elements: actionInitiation.routerState.elements,
64
+ interceptionContext: actionInitiation.routerState.interception !== null ? actionInitiation.routerState.interceptionContext : null,
63
65
  previousNextUrl: actionInitiation.routerState.previousNextUrl
64
66
  }).headers;
65
67
  const fetchResponse = await fetch(createServerActionRequestUrl(actionInitiation.path), {
@@ -69,7 +71,7 @@ async function invokeClientServerAction(id, args, actionInitiation, deps) {
69
71
  });
70
72
  throwOnServerActionNotFound(fetchResponse, id);
71
73
  const hasActionRedirect = fetchResponse.headers.has(ACTION_REDIRECT_HEADER);
72
- const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse, (url, historyMode) => deps.performHardNavigation(url, historyMode));
74
+ const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse, deps.basePath, (url, historyMode) => deps.performHardNavigation(url, historyMode));
73
75
  if (hasActionRedirect && !actionRedirectTarget) return void 0;
74
76
  const actionResultFacts = createServerActionResultFacts({
75
77
  actionRedirectHref: actionRedirectTarget?.href ?? null,
@@ -107,6 +107,7 @@ type ResolveServerActionRequestStateOptions = {
107
107
  actionId: string;
108
108
  basePath: string;
109
109
  elements: AppElements;
110
+ interceptionContext?: string | null;
110
111
  previousNextUrl: string | null;
111
112
  };
112
113
  type ResolveServerActionRequestStateResult = {
@@ -6,12 +6,12 @@ import { AppElementsWire } from "./app-elements-wire.js";
6
6
  import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
7
7
  import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
8
8
  import { createCacheEntryReuseProof } from "./cache-proof.js";
9
- import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
10
9
  import { createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
11
10
  import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
12
11
  import { verifyOperationTokenForCommit } from "./operation-token.js";
13
12
  import { navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts } from "./navigation-planner.js";
14
13
  import { createSnapshotPathAndSearch } from "../shims/navigation.js";
14
+ import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
15
15
  //#region src/server/app-browser-state.ts
16
16
  const COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "committed-cache" };
17
17
  const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "fresh" };
@@ -68,7 +68,7 @@ function resolveServerActionRequestState(options) {
68
68
  const headers = createRscRequestHeaders();
69
69
  headers.set(RSC_ACTION_HEADER, options.actionId);
70
70
  headers.set(NEXT_ACTION_HEADER, options.actionId);
71
- const interceptionContext = resolveInterceptionContextFromPreviousNextUrl(options.previousNextUrl, options.basePath);
71
+ const interceptionContext = resolveInterceptionContextFromPreviousNextUrl(options.previousNextUrl, options.basePath) ?? options.interceptionContext ?? null;
72
72
  if (interceptionContext !== null) headers.set(VINEXT_INTERCEPTION_CONTEXT_HEADER, interceptionContext);
73
73
  const mountedSlotsHeader = getMountedSlotIdsHeader(options.elements);
74
74
  if (mountedSlotsHeader !== null) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
@@ -1,8 +1,8 @@
1
1
  import { normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
2
2
  import "./app-elements.js";
3
3
  import { mergeElements } from "../shims/slot.js";
4
- import { preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
5
4
  import { NavigationTraceReasonCodes, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry } from "./navigation-trace.js";
5
+ import { preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
6
6
  import { createPendingNavigationCommit, resolvePendingNavigationCommitDispositionDecision } from "./app-browser-state.js";
7
7
  //#region src/server/app-browser-visible-commit.ts
8
8
  const approvedVisibleCommitBrand = Symbol("ApprovedVisibleCommit");
@@ -1,6 +1,6 @@
1
1
  import { runWithFetchDedupe } from "../shims/fetch-cache.js";
2
2
  import { resolveAppPageSegmentParams } from "./app-page-params.js";
3
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
3
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
4
4
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
5
5
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
6
6
  //#region src/server/app-page-boundary.ts
@@ -109,6 +109,7 @@ async function renderAppPageBoundaryResponse(options) {
109
109
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
110
110
  mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
111
111
  applyRscCompatibilityIdHeader(headers);
112
+ applyRscDeploymentIdHeader(headers);
112
113
  return new Response(rscStream, {
113
114
  status: options.status,
114
115
  headers
@@ -50,6 +50,7 @@ type ScheduleAppPageRscCacheWriteOptions = {
50
50
  isrSet: AppPageCacheSetter;
51
51
  interceptionContext?: string | null;
52
52
  mountedSlotsHeader?: string | null;
53
+ omitPendingDynamicCacheState?: boolean;
53
54
  renderMode?: AppRscRenderMode;
54
55
  preserveClientResponseHeaders?: boolean;
55
56
  expireSeconds?: number;
@@ -83,7 +83,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
83
83
  if (!scheduleAppPageRscCacheWrite(options)) return response;
84
84
  if (options.preserveClientResponseHeaders === true) return response;
85
85
  const clientHeaders = new Headers(response.headers);
86
- applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags());
86
+ applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
87
87
  return new Response(response.body, {
88
88
  status: response.status,
89
89
  statusText: response.statusText,
@@ -92,8 +92,8 @@ function finalizeAppPageRscCacheResponse(response, options) {
92
92
  }
93
93
  function scheduleAppPageRscCacheWrite(options) {
94
94
  const capturedRscDataPromise = options.capturedRscDataPromise;
95
- if (!capturedRscDataPromise || options.dynamicUsedDuringBuild) return false;
96
- const rscKey = options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext);
95
+ if (!capturedRscDataPromise || options.dynamicUsedDuringBuild || options.mountedSlotsHeader) return false;
96
+ const rscKey = options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext);
97
97
  const cachePromise = (async () => {
98
98
  try {
99
99
  const rscData = await capturedRscDataPromise;
@@ -4,7 +4,7 @@ import { applyCdnResponseHeaders } from "./cache-control.js";
4
4
  import { decideIsr } from "./isr-decision.js";
5
5
  import { buildAppPageCacheValue } from "./isr-cache.js";
6
6
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
7
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
7
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
8
8
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
9
9
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
10
10
  import { hasCompleteNegativeRequestApiProof } from "./cache-proof.js";
@@ -55,6 +55,15 @@ function getCachedAppPageValue(entry) {
55
55
  function hasQueryInvariantAppPageProof(cachedValue) {
56
56
  return cachedValue.renderObservation !== void 0 && hasCompleteNegativeRequestApiProof(cachedValue.renderObservation, ["searchParams"]);
57
57
  }
58
+ function resolveRegeneratedAppPageCachePolicy(options) {
59
+ let revalidateSeconds = options.routeRevalidateSeconds;
60
+ const renderRevalidateSeconds = options.renderCacheControl?.revalidate;
61
+ if (renderRevalidateSeconds !== void 0) revalidateSeconds = revalidateSeconds > 0 ? Math.min(revalidateSeconds, renderRevalidateSeconds) : renderRevalidateSeconds;
62
+ return {
63
+ expireSeconds: options.renderCacheControl?.expire ?? options.expireSeconds,
64
+ revalidateSeconds
65
+ };
66
+ }
58
67
  function buildAppPageCachedResponse(cachedValue, options) {
59
68
  const status = options.middlewareStatus ?? (cachedValue.status || 200);
60
69
  const { cacheControl } = decideIsr({
@@ -75,6 +84,7 @@ function buildAppPageCachedResponse(cachedValue, options) {
75
84
  mountedSlotsHeader: options.mountedSlotsHeader
76
85
  });
77
86
  applyRscCompatibilityIdHeader(rscHeaders);
87
+ applyRscDeploymentIdHeader(rscHeaders);
78
88
  return new Response(cachedValue.rscData, {
79
89
  status,
80
90
  headers: rscHeaders
@@ -118,7 +128,11 @@ async function serveAppPageCachedHtml(options, transformValue) {
118
128
  return response;
119
129
  }
120
130
  async function readAppPageCacheResponse(options) {
121
- const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
131
+ if (options.isRscRequest && options.mountedSlotsHeader) {
132
+ options.isrDebug?.("MISS (mounted slots RSC variant)", options.cleanPathname);
133
+ return null;
134
+ }
135
+ const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
122
136
  const artifact = options.isRscRequest ? "rsc" : "html";
123
137
  try {
124
138
  const cached = await options.isrGet(isrKey);
@@ -177,10 +191,13 @@ async function readAppPageCacheResponse(options) {
177
191
  if (cached?.isStale && cachedValue) {
178
192
  options.scheduleBackgroundRegeneration(isrKey, async () => {
179
193
  const revalidatedPage = await options.renderFreshPageForCache();
180
- const revalidateSeconds = revalidatedPage.cacheControl?.revalidate ?? options.revalidateSeconds;
181
- const expireSeconds = revalidatedPage.cacheControl?.expire ?? options.expireSeconds;
182
- const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), revalidateSeconds, revalidatedPage.tags, expireSeconds)];
183
- if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? { link: revalidatedPage.linkHeader } : void 0), revalidateSeconds, revalidatedPage.tags, expireSeconds));
194
+ const cachePolicy = resolveRegeneratedAppPageCachePolicy({
195
+ expireSeconds: options.expireSeconds,
196
+ renderCacheControl: revalidatedPage.cacheControl,
197
+ routeRevalidateSeconds: options.revalidateSeconds
198
+ });
199
+ const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds)];
200
+ if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? { link: revalidatedPage.linkHeader } : void 0), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds));
184
201
  await Promise.all(writes);
185
202
  options.isrDebug?.("regen complete", options.cleanPathname);
186
203
  });
@@ -199,6 +199,7 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
199
199
  }>;
200
200
  request: Request;
201
201
  revalidateSeconds: number | null;
202
+ renderedPathAndSearch?: string | null;
202
203
  resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;
203
204
  resolveRouteDynamicConfig?: (route: TRoute) => string | null | undefined;
204
205
  rootForbiddenModule?: AppPageModule | null;
@@ -1,12 +1,13 @@
1
1
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
+ import "../utils/protocol-headers.js";
3
4
  import { AppElementsWire } from "./app-elements-wire.js";
4
- import { shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
5
+ import { APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
5
6
  import "./app-elements.js";
6
7
  import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersContext, isDraftModeRequest, markDynamicUsage, peekDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
7
8
  import { _consumeRequestScopedCacheLife, _peekRequestScopedCacheLife } from "../shims/cache-request-state.js";
8
- import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
9
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
9
+ import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground } from "../shims/fetch-cache.js";
10
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
10
11
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
11
12
  import "./app-page-response.js";
12
13
  import { buildAppPageSpecialErrorResponse, probeAppPageThrownError, resolveAppPageSpecialError } from "./app-page-execution.js";
@@ -100,6 +101,10 @@ function getEffectiveLayoutClassifications(route, debugClassification) {
100
101
  function shouldReadAppPageCache(options) {
101
102
  return options.isProduction && !options.isProgressiveActionRender && !options.isDraftMode && !options.isForceDynamic && (options.isRscRequest || !options.scriptNonce) && (options.revalidateSeconds === null || options.revalidateSeconds > 0);
102
103
  }
104
+ function resolveAppPageCacheReadRevalidateSeconds(options) {
105
+ if (options.revalidateSeconds === null && (options.isForceStatic || options.isDynamicError)) return Infinity;
106
+ return options.revalidateSeconds ?? 0;
107
+ }
103
108
  function hasSearchParams(searchParams) {
104
109
  return searchParams !== null && searchParams !== void 0 && searchParams.size > 0;
105
110
  }
@@ -119,6 +124,7 @@ async function runAppPageRevalidationContext(options, renderFn) {
119
124
  unstableCacheRevalidation: "foreground"
120
125
  }), async () => {
121
126
  ensureFetchPatch();
127
+ setRefreshStaleFetchesInForeground(process.env.VINEXT_PRERENDER === "1");
122
128
  setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], options.routeSegments));
123
129
  options.setNavigationContext({
124
130
  pathname: options.displayPathname ?? options.cleanPathname,
@@ -154,10 +160,12 @@ async function dispatchAppPageInner(options) {
154
160
  const isForceStatic = dynamicConfig === "force-static";
155
161
  const isDynamicError = dynamicConfig === "error";
156
162
  const isForceDynamic = dynamicConfig === "force-dynamic";
163
+ const isPrefetchDynamicShell = options.renderMode === APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL;
157
164
  const isDraftMode = isDraftModeRequest(options.request, options.draftModeSecret);
158
165
  const requestHeadersContext = getHeadersContext();
159
- const hasRequestSearchParams = !isForceStatic && hasSearchParams(options.searchParams);
160
- const pageSearchParams = isForceStatic ? new URLSearchParams() : options.searchParams;
166
+ const shouldUseEmptySearchParams = isForceStatic || isPrefetchDynamicShell;
167
+ const hasRequestSearchParams = !shouldUseEmptySearchParams && hasSearchParams(options.searchParams);
168
+ const pageSearchParams = shouldUseEmptySearchParams ? new URLSearchParams() : options.searchParams;
161
169
  const layoutParamAccess = createAppLayoutParamAccessTracker();
162
170
  const hasActiveLoadingBoundary = shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") ? false : Boolean(route.loading?.default);
163
171
  setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
@@ -222,7 +230,11 @@ async function dispatchAppPageInner(options) {
222
230
  mountedSlotsHeader: options.mountedSlotsHeader,
223
231
  renderMode: options.renderMode,
224
232
  expireSeconds: options.expireSeconds,
225
- revalidateSeconds: currentRevalidateSeconds ?? 0,
233
+ revalidateSeconds: resolveAppPageCacheReadRevalidateSeconds({
234
+ isDynamicError,
235
+ isForceStatic,
236
+ revalidateSeconds: currentRevalidateSeconds
237
+ }),
226
238
  renderFreshPageForCache: async () => {
227
239
  const revalidationTarget = await resolveAppPageInterceptionRerenderTarget({
228
240
  cleanPathname: options.cleanPathname,
@@ -361,6 +373,7 @@ async function dispatchAppPageInner(options) {
361
373
  });
362
374
  mergeMiddlewareResponseHeaders(interceptHeaders, options.middlewareContext.headers);
363
375
  applyRscCompatibilityIdHeader(interceptHeaders);
376
+ applyRscDeploymentIdHeader(interceptHeaders);
364
377
  return new Response(interceptStream, {
365
378
  status: options.middlewareContext.status ?? 200,
366
379
  headers: interceptHeaders
@@ -428,6 +441,8 @@ async function dispatchAppPageInner(options) {
428
441
  const activeFallbackShellState = options.pprRuntime?.getState() ?? null;
429
442
  const pprFallbackShellSignal = activeFallbackShellState?.abortController.signal;
430
443
  const pprFallbackShellReactSignal = activeFallbackShellState?.reactAbortController.signal;
444
+ const isPrerender = process.env.VINEXT_PRERENDER === "1";
445
+ const isSpeculativePrerender = isPrerender && options.request.headers.get("x-vinext-prerender-speculative") === "1";
431
446
  return renderAppPageLifecycle({
432
447
  basePath: options.basePath,
433
448
  clientTraceMetadata: options.clientTraceMetadata,
@@ -459,7 +474,7 @@ async function dispatchAppPageInner(options) {
459
474
  },
460
475
  handlerStart: options.handlerStart,
461
476
  hasLoadingBoundary: hasActiveLoadingBoundary,
462
- omitPendingDynamicCacheState: !options.isRscRequest && hasRequestSearchParams,
477
+ omitPendingDynamicCacheState: hasRequestSearchParams,
463
478
  formState: options.formState ?? null,
464
479
  isProgressiveActionRender: options.isProgressiveActionRender === true,
465
480
  isDynamicError,
@@ -467,7 +482,8 @@ async function dispatchAppPageInner(options) {
467
482
  isForceDynamic,
468
483
  isForceStatic,
469
484
  isEdgeRuntime: options.isEdgeRuntime === true,
470
- isPrerender: process.env.VINEXT_PRERENDER === "1",
485
+ isPrerender,
486
+ isSpeculativePrerender,
471
487
  isProduction: options.isProduction,
472
488
  isRscRequest: options.isRscRequest,
473
489
  isrDebug: options.isrDebug,
@@ -483,6 +499,7 @@ async function dispatchAppPageInner(options) {
483
499
  params: options.params,
484
500
  pprFallbackShellSignal,
485
501
  pprFallbackShellReactSignal,
502
+ renderedPathAndSearch: options.renderedPathAndSearch,
486
503
  abortPprFallbackShell: activeFallbackShellState ? () => {
487
504
  options.pprRuntime.beginFinalRender(activeFallbackShellState);
488
505
  } : void 0,
@@ -51,6 +51,7 @@ async function buildPageElements(options) {
51
51
  const hasPageModule = !!pageModule;
52
52
  const renderIdentity = createAppPageRenderIdentity({
53
53
  displayPathname,
54
+ matchedRoutePathname: routePath,
54
55
  targetMatchedPathname: routePath,
55
56
  interceptionContext: opts?.interceptionContext ?? null,
56
57
  interceptSourceMatchedUrl: opts?.interceptSourceMatchedUrl ?? null,
@@ -1,7 +1,7 @@
1
1
  import { addBasePathToPathname } from "../utils/base-path.js";
2
2
  import { VINEXT_RSC_REDIRECT_HEADER } from "./headers.js";
3
3
  import { runWithConnectionProbe } from "../shims/headers.js";
4
- import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscRedirectLocation } from "./app-rsc-cache-busting.js";
4
+ import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, createRscRedirectLocation } from "./app-rsc-cache-busting.js";
5
5
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
6
6
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
7
7
  import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
@@ -161,6 +161,7 @@ async function buildAppPageSpecialErrorResponse(options) {
161
161
  });
162
162
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
163
163
  applyRscCompatibilityIdHeader(headers);
164
+ applyRscDeploymentIdHeader(headers);
164
165
  mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);
165
166
  const pendingCookies = options.getAndClearPendingCookies?.() ?? [];
166
167
  for (const cookie of pendingCookies) headers.append("Set-Cookie", cookie);
@@ -2,6 +2,7 @@ import { AppElementsInterception } from "./app-elements-wire.js";
2
2
  //#region src/server/app-page-render-identity.d.ts
3
3
  type AppPageRenderIdentityInput = {
4
4
  displayPathname: string;
5
+ matchedRoutePathname?: string;
5
6
  targetMatchedPathname?: string;
6
7
  interceptionContext?: string | null;
7
8
  interceptSourceMatchedUrl?: string | null;
@@ -14,9 +14,10 @@ function normalizeAppPageInterceptionProofPathname(pathname) {
14
14
  function createAppPageRenderIdentity(input) {
15
15
  const interceptionContext = input.interceptionContext ?? null;
16
16
  const targetMatchedPathname = normalizeAppPageRenderMatchedPathname(input.targetMatchedPathname ?? input.displayPathname);
17
+ const requestedMatchedRoutePathname = normalizeAppPageRenderMatchedPathname(input.matchedRoutePathname ?? input.targetMatchedPathname ?? input.displayPathname);
17
18
  const sourceMatchedPathname = normalizeAppPageInterceptionProofPathname(input.interceptSourceMatchedUrl ?? null);
18
19
  const slotId = input.interceptSlotId ?? null;
19
- const matchedRoutePathname = sourceMatchedPathname ?? targetMatchedPathname;
20
+ const matchedRoutePathname = sourceMatchedPathname ?? requestedMatchedRoutePathname;
20
21
  const routeId = AppElementsWire.encodeRouteId(matchedRoutePathname, null);
21
22
  const pageId = AppElementsWire.encodePageId(matchedRoutePathname, null);
22
23
  const interception = sourceMatchedPathname === null || slotId === null ? null : {
@@ -60,6 +60,7 @@ type RenderAppPageLifecycleOptions = {
60
60
  isForceStatic: boolean;
61
61
  isProgressiveActionRender?: boolean;
62
62
  isPrerender?: boolean;
63
+ isSpeculativePrerender?: boolean;
63
64
  isProduction: boolean;
64
65
  probePageBeforeRender?: boolean;
65
66
  omitPendingDynamicCacheState?: boolean;
@@ -103,6 +104,7 @@ type RenderAppPageLifecycleOptions = {
103
104
  clientReuseManifest?: ClientReuseManifestParseResult;
104
105
  skipDisposition?: ClientReuseManifestSkipDisposition;
105
106
  mountedSlotsHeader?: string | null;
107
+ renderedPathAndSearch?: string | null;
106
108
  renderMode?: AppRscRenderMode;
107
109
  waitUntil?: (promise: Promise<void>) => void;
108
110
  layoutParamAccess?: AppLayoutParamAccessTracker;