vinext 1.0.0-beta.3 → 1.0.0-beta.4

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 (90) hide show
  1. package/dist/build/precompress.js +1 -1
  2. package/dist/build/prerender.d.ts +2 -1
  3. package/dist/build/prerender.js +12 -2
  4. package/dist/cli-args.d.ts +2 -1
  5. package/dist/cli-args.js +10 -0
  6. package/dist/cli.js +14 -8
  7. package/dist/client/navigation-runtime.d.ts +6 -0
  8. package/dist/client/navigation-runtime.js +1 -1
  9. package/dist/config/dotenv.d.ts +3 -4
  10. package/dist/config/dotenv.js +30 -22
  11. package/dist/config/next-config.d.ts +4 -2
  12. package/dist/config/next-config.js +3 -0
  13. package/dist/entries/app-browser-entry.js +1 -1
  14. package/dist/entries/app-rsc-entry.js +18 -3
  15. package/dist/entries/pages-server-entry.js +4 -1
  16. package/dist/index.js +11 -7
  17. package/dist/plugins/client-reference-dedup.js +7 -5
  18. package/dist/plugins/sass.js +3 -4
  19. package/dist/server/api-handler.js +4 -3
  20. package/dist/server/app-bfcache-identity.js +28 -2
  21. package/dist/server/app-browser-entry.js +73 -45
  22. package/dist/server/app-browser-navigation-controller.d.ts +1 -1
  23. package/dist/server/app-browser-navigation-controller.js +29 -4
  24. package/dist/server/app-browser-prefetch-response.d.ts +9 -0
  25. package/dist/server/app-browser-prefetch-response.js +32 -0
  26. package/dist/server/app-browser-state.d.ts +8 -3
  27. package/dist/server/app-browser-state.js +9 -3
  28. package/dist/server/app-page-dispatch.d.ts +1 -1
  29. package/dist/server/app-page-dispatch.js +6 -2
  30. package/dist/server/app-page-element-builder.d.ts +2 -1
  31. package/dist/server/app-page-element-builder.js +1 -0
  32. package/dist/server/app-page-render.d.ts +1 -1
  33. package/dist/server/app-page-render.js +13 -3
  34. package/dist/server/app-page-request.d.ts +0 -1
  35. package/dist/server/app-page-request.js +3 -12
  36. package/dist/server/app-page-response.d.ts +2 -0
  37. package/dist/server/app-page-response.js +6 -1
  38. package/dist/server/app-page-route-wiring.d.ts +3 -2
  39. package/dist/server/app-page-route-wiring.js +61 -13
  40. package/dist/server/app-pages-bridge.d.ts +2 -1
  41. package/dist/server/app-pages-bridge.js +2 -1
  42. package/dist/server/app-rsc-cache-busting.d.ts +7 -0
  43. package/dist/server/app-rsc-cache-busting.js +6 -0
  44. package/dist/server/app-rsc-handler.d.ts +2 -0
  45. package/dist/server/app-rsc-handler.js +9 -4
  46. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  47. package/dist/server/app-rsc-render-mode.js +4 -1
  48. package/dist/server/app-rsc-request-normalization.js +65 -4
  49. package/dist/server/app-server-action-execution.d.ts +1 -1
  50. package/dist/server/app-visited-response-cache.d.ts +6 -1
  51. package/dist/server/app-visited-response-cache.js +49 -1
  52. package/dist/server/dev-server.d.ts +1 -1
  53. package/dist/server/dev-server.js +61 -38
  54. package/dist/server/edge-api-runtime.d.ts +10 -1
  55. package/dist/server/edge-api-runtime.js +29 -1
  56. package/dist/server/headers.d.ts +3 -1
  57. package/dist/server/headers.js +3 -1
  58. package/dist/server/pages-api-route.d.ts +2 -0
  59. package/dist/server/pages-api-route.js +2 -2
  60. package/dist/server/pages-asset-tags.d.ts +1 -0
  61. package/dist/server/pages-asset-tags.js +6 -4
  62. package/dist/server/pages-document-asset-props.d.ts +26 -0
  63. package/dist/server/pages-document-asset-props.js +69 -0
  64. package/dist/server/pages-node-compat.js +3 -3
  65. package/dist/server/pages-page-handler.d.ts +1 -0
  66. package/dist/server/pages-page-handler.js +4 -1
  67. package/dist/server/pages-page-response.d.ts +2 -0
  68. package/dist/server/pages-page-response.js +19 -8
  69. package/dist/server/pages-router-entry.js +1 -1
  70. package/dist/server/prerender-manifest.d.ts +1 -0
  71. package/dist/server/prod-server.js +2 -1
  72. package/dist/server/seed-cache.js +1 -1
  73. package/dist/server/worker-revalidation-context.js +1 -0
  74. package/dist/shims/app-router-scroll-state.d.ts +2 -1
  75. package/dist/shims/app-router-scroll-state.js +7 -2
  76. package/dist/shims/document.js +15 -2
  77. package/dist/shims/hash-scroll.d.ts +1 -1
  78. package/dist/shims/hash-scroll.js +2 -1
  79. package/dist/shims/link.d.ts +2 -0
  80. package/dist/shims/link.js +59 -18
  81. package/dist/shims/metadata.d.ts +11 -17
  82. package/dist/shims/metadata.js +24 -32
  83. package/dist/shims/navigation.d.ts +18 -2
  84. package/dist/shims/navigation.js +69 -20
  85. package/dist/shims/request-context.d.ts +2 -1
  86. package/dist/shims/slot.d.ts +2 -1
  87. package/dist/shims/slot.js +6 -2
  88. package/dist/shims/streamed-icons.d.ts +9 -0
  89. package/dist/shims/streamed-icons.js +33 -0
  90. package/package.json +1 -1
@@ -9,7 +9,7 @@ import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-medi
9
9
  import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
10
10
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
11
11
  import { attachPagesPreviewApi, attachPagesRequestCookies } from "./pages-node-compat.js";
12
- import { isEdgeApiRuntime } from "./edge-api-runtime.js";
12
+ import { finalizeEdgeApiResponse, isEdgeApiRuntime } from "./edge-api-runtime.js";
13
13
  import { decode } from "node:querystring";
14
14
  import { Buffer } from "node:buffer";
15
15
  //#region src/server/api-handler.ts
@@ -227,8 +227,9 @@ async function handleApiRoute(runner, req, res, url, apiRoutes, nextConfig) {
227
227
  i18n: nextConfig.i18n ?? void 0,
228
228
  trailingSlash: nextConfig.trailingSlash
229
229
  } } : void 0);
230
- const response = await apiModule.default(nextRequest);
231
- if (!(response instanceof Response)) throw new Error("Edge API route did not return a Response");
230
+ const handlerResponse = await apiModule.default(nextRequest);
231
+ if (!(handlerResponse instanceof Response)) throw new Error("Edge API route did not return a Response");
232
+ const response = finalizeEdgeApiResponse(handlerResponse, "node");
232
233
  res.statusCode = response.status;
233
234
  res.statusMessage = response.statusText;
234
235
  const setCookieHeaders = response.headers.getSetCookie();
@@ -51,19 +51,45 @@ function createActiveSlotIdentity(id, parsed) {
51
51
  if (interception?.slotId !== id) return null;
52
52
  return `${id}@${interception.targetRouteId}`;
53
53
  }
54
+ function getDirectMatchedRoutePathname(metadata) {
55
+ if (metadata?.metadata.interception != null || metadata?.metadata.sourcePage == null) return null;
56
+ const route = AppElementsWire.parseElementKey(metadata.metadata.routeId);
57
+ return route?.kind === "route" ? route.path : null;
58
+ }
59
+ function getPageMatchedUrl(parsed, metadata) {
60
+ const interception = metadata?.metadata.interception;
61
+ if (interception === null || interception === void 0) {
62
+ const matchedRoutePathname = getDirectMatchedRoutePathname(metadata);
63
+ return matchedRoutePathname === parsed.path ? matchedRoutePathname : null;
64
+ }
65
+ for (const [routeId, matchedUrl] of [[interception.sourceRouteId, interception.sourceMatchedUrl], [interception.targetRouteId, interception.targetMatchedUrl]]) {
66
+ const route = AppElementsWire.parseElementKey(routeId);
67
+ if (route?.kind === "route" && route.path === parsed.path) return matchedUrl;
68
+ }
69
+ return null;
70
+ }
71
+ function getTreePathname(treePath, metadata) {
72
+ const interception = metadata?.metadata.interception;
73
+ if (interception === null || interception === void 0) return getDirectMatchedRoutePathname(metadata);
74
+ const slot = AppElementsWire.parseElementKey(interception.slotId);
75
+ if (slot?.kind !== "slot") return interception.sourceMatchedUrl;
76
+ const treeSegments = splitPathSegments(treePath);
77
+ const ownerSegments = splitPathSegments(slot.treePath);
78
+ return treeSegments.length > ownerSegments.length && ownerSegments.every((segment, index) => treeSegments[index] === segment) && treeSegments[ownerSegments.length] === `@${slot.name}` ? interception.targetMatchedUrl : interception.sourceMatchedUrl;
79
+ }
54
80
  /**
55
81
  * Derive BFCache identity from AppElements wire keys. Keep wire-key parsing
56
82
  * contained here until vinext has a route-manifest authority equivalent to
57
83
  * Next.js CacheNode or segment-cache state.
58
84
  */
59
85
  function createBfcacheSegmentIdentity(id, parsed, options) {
60
- if (parsed.kind === "page") return `${id}@${options.pathname}`;
86
+ if (parsed.kind === "page") return `${id}@${getPageMatchedUrl(parsed, options.metadata) ?? options.pathname}`;
61
87
  if (parsed.kind === "slot") {
62
88
  const activeSlotIdentity = createActiveSlotIdentity(id, options.metadata);
63
89
  if (activeSlotIdentity !== null) return activeSlotIdentity;
64
90
  return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
65
91
  }
66
- if (parsed.kind === "layout" || parsed.kind === "template") return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
92
+ if (parsed.kind === "layout" || parsed.kind === "template") return `${id}@${getTreePathIdentityPrefix(getTreePathname(parsed.treePath, options.metadata) ?? options.pathname, parsed.treePath)}`;
67
93
  return null;
68
94
  }
69
95
  function collectBfcacheSegmentIdCandidates(elements, metadata = readAppElementsMetadata(elements)) {
@@ -12,7 +12,7 @@ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../s
12
12
  import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
13
13
  import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
14
14
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
15
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
15
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
16
16
  import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
17
17
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
18
18
  import "../client/instrumentation-client.js";
@@ -24,17 +24,18 @@ import { readHistoryStatePreviousNextUrl } from "./app-history-state.js";
24
24
  import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
25
25
  import { blockDangerousStreamedRscRedirect } from "./app-browser-rsc-redirect.js";
26
26
  import { navigationPlanner } from "./navigation-planner.js";
27
- import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
27
+ import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
28
28
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
29
29
  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";
30
30
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch } from "./app-browser-navigation-controller.js";
31
31
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition } from "./app-browser-hydration.js";
32
32
  import { AppBrowserHistoryController } from "./app-browser-history-controller.js";
33
- import { createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
33
+ import { createVisitedResponseCacheEntry, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
34
34
  import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition } from "./app-browser-popstate.js";
35
35
  import { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnRecoverableError } from "./app-browser-error.js";
36
36
  import { createHydrationCachePublication } from "./app-hydration-cache-publication.js";
37
- import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
37
+ import { resolvePrefetchNavigationResponseUrl } from "./app-browser-prefetch-response.js";
38
+ import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, matchOptimisticRouteManifestRoute, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
38
39
  import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
39
40
  import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
40
41
  import { flushSync } from "react-dom";
@@ -126,6 +127,7 @@ let latestClientParams = {};
126
127
  const visitedResponseCache = /* @__PURE__ */ new Map();
127
128
  let clientNavigationCacheGeneration = 0;
128
129
  let browserRouterStateHasEverCommitted = false;
130
+ let initialPrefetchRouterState = null;
129
131
  const mpaNavigationScheduler = new AppBrowserMpaNavigationScheduler();
130
132
  const unresolvedMpaNavigation = new Promise(() => {});
131
133
  const RSC_HMR_SETTLE_DELAY_MS = 150;
@@ -193,21 +195,6 @@ function clearClientNavigationCaches() {
193
195
  clearPrefetchState();
194
196
  historyController.invalidateRestorableClientState();
195
197
  }
196
- function normalizeBrowserRscUrlForReuse(url) {
197
- if (!url) return null;
198
- try {
199
- const parsed = new URL(url, window.location.origin);
200
- stripRscCacheBustingSearchParam(parsed);
201
- return `${parsed.pathname}${parsed.search}`;
202
- } catch {
203
- return null;
204
- }
205
- }
206
- function isAlternatePrefetchResponseUrl(responseUrl, additionalRscUrls) {
207
- const normalizedResponseUrl = normalizeBrowserRscUrlForReuse(responseUrl);
208
- if (normalizedResponseUrl === null) return false;
209
- return additionalRscUrls.some((additionalRscUrl) => normalizeBrowserRscUrlForReuse(additionalRscUrl) === normalizedResponseUrl);
210
- }
211
198
  function isSettledPrefetchCacheEntry(entry) {
212
199
  return entry.outcome === "cache-seeded" && entry.pending === void 0 && entry.snapshot !== void 0;
213
200
  }
@@ -347,8 +334,8 @@ function evictVisitedResponseCacheIfNeeded() {
347
334
  }
348
335
  function readVisitedResponseCacheCandidate(rscUrl, interceptionContext, mountedSlotsHeader, navigationKind) {
349
336
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
350
- const cached = visitedResponseCache.get(cacheKey);
351
- if (!cached) return {
337
+ const match = findVisitedResponseCacheEntry(visitedResponseCache, rscUrl, interceptionContext);
338
+ if (!match) return {
352
339
  cacheKey,
353
340
  entry: null,
354
341
  facts: {
@@ -357,15 +344,15 @@ function readVisitedResponseCacheCandidate(rscUrl, interceptionContext, mountedS
357
344
  }
358
345
  };
359
346
  return {
360
- cacheKey,
361
- entry: cached,
347
+ cacheKey: match.cacheKey,
348
+ entry: match.entry,
362
349
  facts: {
363
350
  candidate: "present",
364
- fresh: isVisitedResponseCacheEntryFresh(cached, {
351
+ fresh: isVisitedResponseCacheEntryFresh(match.entry, {
365
352
  navigationKind,
366
353
  now: Date.now()
367
354
  }),
368
- mountedSlotsMatch: cached.mountedSlotsHeader === mountedSlotsHeader,
355
+ mountedSlotsMatch: match.entry.elements !== void 0 || match.entry.mountedSlotsHeader === mountedSlotsHeader,
369
356
  navigationKind
370
357
  }
371
358
  };
@@ -381,9 +368,9 @@ function applyVisitedResponseCacheCandidateDecision(candidate, decision) {
381
368
  return null;
382
369
  }
383
370
  function deleteVisitedResponse(rscUrl, interceptionContext) {
384
- visitedResponseCache.delete(AppElementsWire.encodeCacheKey(rscUrl, interceptionContext));
371
+ deleteVisitedResponseCacheEntry(visitedResponseCache, rscUrl, interceptionContext);
385
372
  }
386
- function storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, params, prefetchFallbackTtlMs = DYNAMIC_NAVIGATION_CACHE_TTL, requestMountedSlotsHeader = snapshot.mountedSlotsHeader ?? null, elements) {
373
+ function storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, params, prefetchFallbackTtlMs = DYNAMIC_NAVIGATION_CACHE_TTL, requestMountedSlotsHeader = snapshot.mountedSlotsHeader ?? null, elements, seedPrefetchCache = true) {
387
374
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
388
375
  visitedResponseCache.delete(cacheKey);
389
376
  evictVisitedResponseCacheIfNeeded();
@@ -396,10 +383,10 @@ function storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, par
396
383
  response: snapshot
397
384
  });
398
385
  visitedResponseCache.set(cacheKey, entry);
399
- seedPrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext, requestMountedSlotsHeader, prefetchFallbackTtlMs);
386
+ if (seedPrefetchCache) seedPrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext, requestMountedSlotsHeader, prefetchFallbackTtlMs);
400
387
  return () => {
401
388
  if (visitedResponseCache.get(cacheKey) === entry) visitedResponseCache.delete(cacheKey);
402
- deletePrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext);
389
+ if (seedPrefetchCache) deletePrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext);
403
390
  };
404
391
  }
405
392
  function clientNavigationSnapshotHref(snapshot) {
@@ -778,6 +765,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
778
765
  Promise.all([root, initialCacheBuffer]).then(async ([elements, buffer]) => {
779
766
  if (cacheGeneration !== clientNavigationCacheGeneration) return;
780
767
  const metadata = AppElementsWire.readMetadata(elements);
768
+ initialPrefetchRouterState = {
769
+ pathAndSearch: initialPathAndSearch,
770
+ routeId: metadata.routeId
771
+ };
781
772
  if (!isCompleteAppPayloadMetadata(metadata)) return;
782
773
  const mountedSlotsHeader = getMountedSlotIdsHeader(elements);
783
774
  const headers = createRscRequestHeaders({ mountedSlotsHeader });
@@ -796,8 +787,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
796
787
  const fallbackTtlMs = initialRscBootstrap?.initialCacheKind === "static" ? PREFETCH_CACHE_TTL : DYNAMIC_NAVIGATION_CACHE_TTL;
797
788
  hydrationCachePublication.publish(() => {
798
789
  if (cacheGeneration !== clientNavigationCacheGeneration) return () => {};
799
- if (isCacheRestorableAppPayloadMetadata(metadata)) return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader);
800
- return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader, elements);
790
+ return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader, elements, false);
801
791
  });
802
792
  }).catch(() => {});
803
793
  historyController.writeBootstrapHistoryMetadata();
@@ -855,6 +845,26 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
855
845
  registerNavigationRuntimeFunctions({
856
846
  clearNavigationCaches: clearClientNavigationCaches,
857
847
  commitHashNavigation: (href, historyUpdateMode, scroll) => historyController.commitHashOnlyNavigation(href, historyUpdateMode, scroll),
848
+ getPrefetchRouterState: () => {
849
+ if (!browserNavigationController.hasBrowserRouterState()) {
850
+ if (initialPrefetchRouterState) return initialPrefetchRouterState;
851
+ const routeManifest = getNavigationRuntime()?.bootstrap.routeManifest ?? null;
852
+ const match = routeManifest ? matchOptimisticRouteManifestRoute({
853
+ basePath: __basePath,
854
+ href: window.location.href,
855
+ routeManifest
856
+ }) : null;
857
+ return match ? {
858
+ pathAndSearch: createBasePathStrippedPathAndSearch(new URL(window.location.href), __basePath),
859
+ routeId: match.route.id
860
+ } : null;
861
+ }
862
+ const state = browserNavigationController.getBrowserRouterState();
863
+ return {
864
+ pathAndSearch: createSnapshotPathAndSearch(state.navigationSnapshot),
865
+ routeId: state.routeId
866
+ };
867
+ },
858
868
  navigate: async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false, traversalIntent, scrollIntent, visibleCommitMode = "transition") {
859
869
  abortSupersededNavigation();
860
870
  const navigationAbortController = new AbortController();
@@ -879,8 +889,9 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
879
889
  const reuseCurrentBfcacheIds = navigationKind !== "traverse" || !historyController.isCacheInvalidationGuarded() && historyController.isCurrentBfcacheVersion(activeTraversalIntent?.historyState ?? window.history.state);
880
890
  try {
881
891
  const shouldUsePendingRouterState = programmaticTransition;
882
- if (shouldUsePendingRouterState && hasBrowserRouterState()) pendingRouterState = beginPendingBrowserRouterState();
883
- else {
892
+ if (hasBrowserRouterState()) {
893
+ if (shouldUsePendingRouterState) pendingRouterState = beginPendingBrowserRouterState();
894
+ } else {
884
895
  await waitForBrowserRouterStateReady();
885
896
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
886
897
  if (shouldUsePendingRouterState) pendingRouterState = beginPendingBrowserRouterState();
@@ -903,12 +914,21 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
903
914
  }) : null;
904
915
  const shouldBypassNavigationCache = earlyIntentDecision?.kind === "flightNavigation" && earlyIntentDecision.bypassNavigationCache;
905
916
  const requestHeaders = createRscRequestHeaders({
917
+ fetchPriority: "auto",
906
918
  interceptionContext: requestInterceptionContext,
907
919
  mountedSlotsHeader
908
920
  });
909
- const rscUrl = await createRscRequestUrl(url.pathname + url.search, requestHeaders);
910
921
  const rewrittenNavigationHref = navigationKind === "navigate" && HAS_CLIENT_REWRITES ? resolveLoadedHybridClientRewriteHref(currentHref, __basePath) : null;
911
- const additionalPrefetchRscUrls = rewrittenNavigationHref && rewrittenNavigationHref !== currentHref ? [await createRscRequestUrl(rewrittenNavigationHref, requestHeaders)] : [];
922
+ const targetPathAndSearch = url.pathname + url.search;
923
+ const additionalPrefetchPathAndSearch = rewrittenNavigationHref && rewrittenNavigationHref !== currentHref ? [rewrittenNavigationHref] : [];
924
+ const settledPrefetchedResponse = navigationKind === "navigate" && !shouldBypassNavigationCache ? consumePrefetchResponse(targetPathAndSearch, requestInterceptionContext, mountedSlotsHeader, { additionalRscUrls: additionalPrefetchPathAndSearch }) : null;
925
+ const rscUrl = settledPrefetchedResponse ? resolvePrefetchNavigationResponseUrl({
926
+ additionalRscUrls: additionalPrefetchPathAndSearch,
927
+ origin: window.location.origin,
928
+ responseUrl: settledPrefetchedResponse.url,
929
+ visibleRscUrl: targetPathAndSearch
930
+ }) : await createRscRequestUrl(targetPathAndSearch, requestHeaders);
931
+ const additionalPrefetchRscUrls = settledPrefetchedResponse ? additionalPrefetchPathAndSearch : await Promise.all(additionalPrefetchPathAndSearch.map((href) => createRscRequestUrl(href, requestHeaders)));
912
932
  const visitedResponseCandidate = shouldBypassNavigationCache ? {
913
933
  cacheKey: AppElementsWire.encodeCacheKey(rscUrl, requestInterceptionContext),
914
934
  entry: null,
@@ -925,7 +945,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
925
945
  visitedResponse
926
946
  });
927
947
  let routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
928
- const hasPrefetchCandidate = prefetchProbeDecision.kind === "probe" && hasPrefetchCacheEntryForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
948
+ const hasPrefetchCandidate = settledPrefetchedResponse !== null || prefetchProbeDecision.kind === "probe" && hasPrefetchCacheEntryForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
929
949
  additionalRscUrls: additionalPrefetchRscUrls,
930
950
  notifyInvalidation: false
931
951
  });
@@ -1003,17 +1023,24 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1003
1023
  let navResponse;
1004
1024
  let navResponseExpiresAt;
1005
1025
  let navResponseUrl = null;
1026
+ let prefetchedElements;
1006
1027
  let fallbackReuseDecision = reuseDecision;
1007
1028
  if (reuseDecision.kind === "consumePrefetch") {
1008
- const prefetchedResponse = await consumePrefetchResponseForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
1029
+ const prefetchedResponse = settledPrefetchedResponse ?? await consumePrefetchResponseForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, {
1009
1030
  additionalRscUrls: additionalPrefetchRscUrls,
1010
1031
  shouldConsume: () => browserNavigationController.isCurrentNavigation(navId)
1011
1032
  });
1012
1033
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
1013
1034
  if (prefetchedResponse) {
1035
+ prefetchedElements = prefetchedResponse.preparedElements;
1014
1036
  navResponse = restoreRscResponse(prefetchedResponse, false);
1015
1037
  navResponseExpiresAt = prefetchedResponse.expiresAt;
1016
- navResponseUrl = isAlternatePrefetchResponseUrl(prefetchedResponse.url, additionalPrefetchRscUrls) ? rscUrl : prefetchedResponse.url;
1038
+ navResponseUrl = resolvePrefetchNavigationResponseUrl({
1039
+ additionalRscUrls: additionalPrefetchRscUrls,
1040
+ origin: window.location.origin,
1041
+ responseUrl: prefetchedResponse.url,
1042
+ visibleRscUrl: rscUrl
1043
+ });
1017
1044
  }
1018
1045
  if (!navResponse) {
1019
1046
  routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
@@ -1082,6 +1109,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1082
1109
  navResponse = await fetch(rscUrl, {
1083
1110
  headers: requestHeaders,
1084
1111
  credentials: "include",
1112
+ priority: "auto",
1085
1113
  signal: navigationAbortController.signal
1086
1114
  });
1087
1115
  }
@@ -1135,7 +1163,8 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1135
1163
  const cacheBufferPromise = new Response(cacheBranch).arrayBuffer();
1136
1164
  cacheBufferPromise.catch(() => {});
1137
1165
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
1138
- const rscPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(reactResponse)));
1166
+ if (prefetchedElements) reactBranch.cancel().catch(() => {});
1167
+ const rscPayload = prefetchedElements ? prefetchedElements : decodeAppElementsPromise(createFromFetch(Promise.resolve(reactResponse)));
1139
1168
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
1140
1169
  let committedState = null;
1141
1170
  if (await renderNavigationPayload({
@@ -1160,8 +1189,9 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1160
1189
  scrollIntent,
1161
1190
  targetHref: currentHref,
1162
1191
  traversalIntent: activeTraversalIntent,
1163
- visibleCommitMode
1192
+ visibleCommitMode: prefetchedElements ? "synchronous" : visibleCommitMode
1164
1193
  }) !== "committed") return;
1194
+ committedState ??= getBrowserRouterState();
1165
1195
  try {
1166
1196
  const renderedElements = await rscPayload;
1167
1197
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
@@ -1182,7 +1212,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1182
1212
  if (isCacheRestorableAppPayloadMetadata(metadata)) {
1183
1213
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
1184
1214
  storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, navParams, PREFETCH_CACHE_TTL, mountedSlotsHeader);
1185
- } else if (committedState !== null) {
1215
+ } else {
1186
1216
  const state = committedState;
1187
1217
  const committedElements = {
1188
1218
  ...state.elements,
@@ -1193,9 +1223,6 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1193
1223
  };
1194
1224
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
1195
1225
  storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, navParams, DYNAMIC_NAVIGATION_CACHE_TTL, mountedSlotsHeader, committedElements);
1196
- } else {
1197
- if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
1198
- seedPrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext, mountedSlotsHeader, DYNAMIC_NAVIGATION_CACHE_TTL);
1199
1226
  }
1200
1227
  } catch {}
1201
1228
  return;
@@ -1209,7 +1236,8 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1209
1236
  browserNavigationController.finalizeNavigation(navId, pendingRouterState);
1210
1237
  discardedServerActionRefreshScheduler.markNavigationSettled();
1211
1238
  }
1212
- }
1239
+ },
1240
+ preparePrefetchResponse: (response) => decodeAppElementsPromise(createFromFetch(Promise.resolve(response)))
1213
1241
  });
1214
1242
  const handlePopstate = createPopstateRestoreHandler({
1215
1243
  getActiveNavigationId: browserNavigationController.getActiveNavigationId.bind(browserNavigationController),
@@ -51,7 +51,7 @@ type BrowserNavigationPayloadOptions = {
51
51
  navigationInitiationState: AppRouterState;
52
52
  navigationSnapshot: ClientNavigationRenderSnapshot;
53
53
  navId: number;
54
- nextElements: Promise<AppElements>;
54
+ nextElements: Promise<AppElements> | AppElements;
55
55
  onCommittedState?: (state: AppRouterState) => void;
56
56
  operationLane: OperationLane;
57
57
  params: Record<string, string | string[]>;
@@ -3,7 +3,7 @@ import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "
3
3
  import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
4
4
  import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
5
5
  import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
6
- import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit } from "./app-browser-state.js";
6
+ import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit, createPendingNavigationCommitFromElements } 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";
9
9
  import { flushSync } from "react-dom";
@@ -255,6 +255,9 @@ function createAppBrowserNavigationController(deps = {}) {
255
255
  pendingRouterState.settled = true;
256
256
  pendingRouterState.resolve(committedState);
257
257
  if (activePendingBrowserRouterState === pendingRouterState) activePendingBrowserRouterState = null;
258
+ if (visibleCommitMode === "synchronous") flushSync(() => {
259
+ setter(committedState);
260
+ });
258
261
  return;
259
262
  }
260
263
  if (visibleCommitMode === "synchronous") {
@@ -332,6 +335,22 @@ function createAppBrowserNavigationController(deps = {}) {
332
335
  if (!shouldScheduleRefreshForDiscardedServerAction(lifecycleOptions?.revalidation ?? "none")) return;
333
336
  lifecycleOptions?.onDiscardedRevalidation?.();
334
337
  }
338
+ function isSamePathSearchHashCommit(targetHref) {
339
+ if (typeof window === "undefined") return false;
340
+ try {
341
+ const currentUrl = new URL(window.location.href);
342
+ const targetUrl = new URL(targetHref, currentUrl.href);
343
+ return targetUrl.origin === currentUrl.origin && targetUrl.pathname === currentUrl.pathname && targetUrl.search !== currentUrl.search && targetUrl.hash !== "";
344
+ } catch {
345
+ return false;
346
+ }
347
+ }
348
+ function shouldForceSynchronousCommit(options) {
349
+ if (options.actionType === "traverse") return false;
350
+ if (options.historyUpdateMode === void 0) return false;
351
+ if (options.scrollIntent?.hash == null) return false;
352
+ return isSamePathSearchHashCommit(options.targetHref);
353
+ }
335
354
  async function renderNavigationPayload(options) {
336
355
  if (options.navId === pendingUserNavigationId) pendingUserNavigationLane = options.operationLane;
337
356
  const renderId = allocateRenderId();
@@ -348,11 +367,10 @@ function createAppBrowserNavigationController(deps = {}) {
348
367
  });
349
368
  let snapshotActivated = false;
350
369
  try {
351
- const pending = await createPendingNavigationCommit({
370
+ const pendingOptions = {
352
371
  currentState: options.navigationInitiationState,
353
372
  navigationCommitKind: options.navigationCommitKind,
354
373
  navigationId: options.navId,
355
- nextElements: options.nextElements,
356
374
  navigationSnapshot: options.navigationSnapshot,
357
375
  operationLane: options.operationLane,
358
376
  payloadOrigin: options.payloadOrigin,
@@ -361,6 +379,13 @@ function createAppBrowserNavigationController(deps = {}) {
361
379
  restoredBfcacheIds: options.restoredBfcacheIds,
362
380
  reuseCurrentBfcacheIds: options.reuseCurrentBfcacheIds,
363
381
  type: options.actionType
382
+ };
383
+ const pending = options.nextElements instanceof Promise ? await createPendingNavigationCommit({
384
+ ...pendingOptions,
385
+ nextElements: options.nextElements
386
+ }) : createPendingNavigationCommitFromElements({
387
+ ...pendingOptions,
388
+ nextElements: options.nextElements
364
389
  });
365
390
  const approval = approvePendingNavigationCommit({
366
391
  activeNavigationId,
@@ -402,7 +427,7 @@ function createAppBrowserNavigationController(deps = {}) {
402
427
  claimAppRouterScrollIntentForCommit(options.scrollIntent, renderId);
403
428
  activateNavigationSnapshot();
404
429
  snapshotActivated = true;
405
- dispatchApprovedVisibleCommit(renderId, approvedCommit, options.pendingRouterState, options.visibleCommitMode ?? "transition");
430
+ dispatchApprovedVisibleCommit(renderId, approvedCommit, options.pendingRouterState, shouldForceSynchronousCommit(options) ? "synchronous" : options.visibleCommitMode ?? "transition");
406
431
  } catch (error) {
407
432
  pendingNavigationFailureTargets.delete(renderId);
408
433
  pendingNavigationPrePaintEffects.delete(renderId);
@@ -0,0 +1,9 @@
1
+ //#region src/server/app-browser-prefetch-response.d.ts
2
+ declare function resolvePrefetchNavigationResponseUrl(options: {
3
+ additionalRscUrls: readonly string[];
4
+ origin: string;
5
+ responseUrl: string;
6
+ visibleRscUrl: string;
7
+ }): string;
8
+ //#endregion
9
+ export { resolvePrefetchNavigationResponseUrl };
@@ -0,0 +1,32 @@
1
+ import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
2
+ //#region src/server/app-browser-prefetch-response.ts
3
+ function normalizeBrowserRscUrlForReuse(url, origin) {
4
+ if (!url) return null;
5
+ try {
6
+ const parsed = new URL(url, origin);
7
+ stripRscCacheBustingSearchParam(parsed);
8
+ return `${parsed.pathname}${parsed.search}`;
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+ function isSameOriginBrowserRscUrl(url, origin) {
14
+ try {
15
+ return new URL(url, origin).origin === new URL(origin).origin;
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+ function canonicalizeBrowserRscResponseUrl(responseUrl, origin) {
21
+ try {
22
+ const parsed = new URL(responseUrl, origin);
23
+ if (parsed.origin === new URL(origin).origin) return `${parsed.pathname}${parsed.search}`;
24
+ } catch {}
25
+ return responseUrl;
26
+ }
27
+ function resolvePrefetchNavigationResponseUrl(options) {
28
+ const normalizedResponseUrl = normalizeBrowserRscUrlForReuse(options.responseUrl, options.origin);
29
+ return normalizedResponseUrl !== null && isSameOriginBrowserRscUrl(options.responseUrl, options.origin) && options.additionalRscUrls.some((additionalRscUrl) => normalizeBrowserRscUrlForReuse(additionalRscUrl, options.origin) === normalizedResponseUrl) ? options.visibleRscUrl : canonicalizeBrowserRscResponseUrl(options.responseUrl, options.origin);
30
+ }
31
+ //#endregion
32
+ export { resolvePrefetchNavigationResponseUrl };
@@ -133,11 +133,10 @@ declare function resolvePendingNavigationCommitDispositionDecision(options: {
133
133
  startedNavigationId: number;
134
134
  targetHref?: string;
135
135
  }): PendingNavigationCommitDispositionDecision;
136
- declare function createPendingNavigationCommit(options: {
136
+ type CreatePendingNavigationCommitOptions = {
137
137
  currentState: AppRouterState;
138
138
  navigationCommitKind?: "authoritative" | "detached";
139
139
  navigationId?: number;
140
- nextElements: Promise<AppElements>;
141
140
  navigationSnapshot: ClientNavigationRenderSnapshot;
142
141
  operationLane: OperationLane;
143
142
  payloadOrigin: AppNavigationPayloadOrigin;
@@ -146,6 +145,12 @@ declare function createPendingNavigationCommit(options: {
146
145
  restoredBfcacheIds?: BfcacheIdMap | null;
147
146
  reuseCurrentBfcacheIds?: boolean;
148
147
  type: "navigate" | "replace" | "traverse";
148
+ };
149
+ declare function createPendingNavigationCommitFromElements(options: CreatePendingNavigationCommitOptions & {
150
+ nextElements: AppElements;
151
+ }): PendingNavigationCommit;
152
+ declare function createPendingNavigationCommit(options: CreatePendingNavigationCommitOptions & {
153
+ nextElements: Promise<AppElements>;
149
154
  }): Promise<PendingNavigationCommit>;
150
155
  //#endregion
151
- export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, type BfcacheIdMap, COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, CommittedOperationRecord, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, type HistoryTraversalIntent, type OperationLane, PendingNavigationCommit, PendingOperationRecord, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
156
+ export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, CommittedOperationRecord, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, type HistoryTraversalIntent, type OperationLane, PendingNavigationCommit, PendingOperationRecord, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, createPendingNavigationCommitFromElements, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
@@ -279,8 +279,8 @@ function mergeSkippedLayoutSlotPreservation(options) {
279
279
  }
280
280
  return preservePreviousSlotIds;
281
281
  }
282
- async function createPendingNavigationCommit(options) {
283
- const elements = await options.nextElements;
282
+ function createPendingNavigationCommitFromElements(options) {
283
+ const elements = options.nextElements;
284
284
  const metadata = AppElementsWire.readMetadata(elements);
285
285
  const cacheEntryReuseProof = metadata.cacheEntryReuseProof ?? (requiresCacheEntryReuseProof(options.payloadOrigin) ? createCacheEntryReuseProof(null) : void 0);
286
286
  const requestedPreviousNextUrl = options.previousNextUrl !== void 0 ? options.previousNextUrl : options.currentState.previousNextUrl;
@@ -328,5 +328,11 @@ async function createPendingNavigationCommit(options) {
328
328
  skippedLayoutIds: metadata.skippedLayoutIds
329
329
  };
330
330
  }
331
+ async function createPendingNavigationCommit(options) {
332
+ return createPendingNavigationCommitFromElements({
333
+ ...options,
334
+ nextElements: await options.nextElements
335
+ });
336
+ }
331
337
  //#endregion
332
- export { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
338
+ export { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, createPendingNavigationCommitFromElements, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
@@ -1,11 +1,11 @@
1
1
  import { ClassificationReason } from "../build/layout-classification-types.js";
2
2
  import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
3
3
  import { AppOutgoingElements } from "./app-elements-wire.js";
4
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
5
  import { NavigationContext } from "../shims/navigation-context-state.js";
5
6
  import { AppPageFontPreload, LayoutClassificationOptions } from "./app-page-execution.js";
6
7
  import { AppPageMiddlewareContext } from "./app-page-response.js";
7
8
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
8
- import { AppRscRenderMode } from "./app-rsc-render-mode.js";
9
9
  import { RootParams } from "../shims/root-params.js";
10
10
  import { AppPageSsrHandler } from "./app-page-stream.js";
11
11
  import { CachedAppPageValue } from "../shims/cache-handler.js";
@@ -348,13 +348,17 @@ async function dispatchAppPageInner(options) {
348
348
  }
349
349
  if (options.skipStaticParamsValidation !== true && !(options.isProduction && isForceDynamic)) {
350
350
  const dynamicParamsResponse = await validateAppPageDynamicParams({
351
- clearRequestContext: options.clearRequestContext,
352
351
  enforceStaticParamsOnly: options.dynamicParamsConfig === false,
353
352
  generateStaticParams: options.generateStaticParams,
354
353
  isDynamicRoute: route.isDynamic,
355
354
  params: options.staticParamsValidationParams ?? options.params
356
355
  });
357
- if (dynamicParamsResponse) return dynamicParamsResponse;
356
+ if (dynamicParamsResponse) {
357
+ const renderedNotFound = await options.renderHttpAccessFallbackPage(404, { matchedParams: options.params }, options.middlewareContext);
358
+ if (renderedNotFound) return renderedNotFound;
359
+ options.clearRequestContext();
360
+ return dynamicParamsResponse;
361
+ }
358
362
  }
359
363
  const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
360
364
  if (fallbackShellResponse) return fallbackShellResponse;
@@ -1,9 +1,9 @@
1
1
  import { MetadataFileRoute } from "./metadata-routes.js";
2
2
  import { AppElements } from "./app-elements-wire.js";
3
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
3
4
  import { AppPageParams } from "./app-page-boundary.js";
4
5
  import { ApplyAppPageFileBasedMetadata } from "./app-page-head.js";
5
6
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
6
- import { AppRscRenderMode } from "./app-rsc-render-mode.js";
7
7
  import { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute } from "./app-page-route-wiring.js";
8
8
 
9
9
  //#region src/server/app-page-element-builder.d.ts
@@ -66,6 +66,7 @@ type BuildPageElementsOptions<TModule extends AppPageModule = AppPageModule, TEr
66
66
  basePath?: string; /** Configured next.config `trailingSlash`, threaded into canonical URL rendering. */
67
67
  trailingSlash?: boolean; /** Serialized next.config `htmlLimitedBots` regexp source. */
68
68
  htmlLimitedBots?: string;
69
+ scriptNonce?: string;
69
70
  };
70
71
  type AppPageNavigationParamModule = {
71
72
  default?: unknown;
@@ -254,6 +254,7 @@ async function buildPageElements(options) {
254
254
  resolvedMetadata,
255
255
  resolvedMetadataPathname: routePath,
256
256
  resolvedViewport,
257
+ scriptNonce: options.scriptNonce,
257
258
  streamingMetadata,
258
259
  streamingMetadataOutlet,
259
260
  streamingMetadataOutletSuspended: streamGeneratedHead,
@@ -1,10 +1,10 @@
1
1
  import { ClientReuseManifestParseResult, ClientReuseManifestSkipDisposition } from "./client-reuse-manifest.js";
2
2
  import { AppOutgoingElements } from "./app-elements-wire.js";
3
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
3
4
  import { NavigationContext } from "../shims/navigation-context-state.js";
4
5
  import { AppPageFontPreload, AppPageSpecialError, LayoutClassificationOptions } from "./app-page-execution.js";
5
6
  import { AppPageMiddlewareContext } from "./app-page-response.js";
6
7
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
7
- import { AppRscRenderMode } from "./app-rsc-render-mode.js";
8
8
  import { RootParams } from "../shims/root-params.js";
9
9
  import { AppPageSsrHandler } from "./app-page-stream.js";
10
10
  import { CachedAppPageValue } from "../shims/cache-handler.js";