vinext 1.3.1 → 1.4.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 (271) hide show
  1. package/README.md +25 -22
  2. package/THIRD_PARTY_LICENSES.md +47 -0
  3. package/dist/_virtual/_rolldown/runtime.js +3 -2
  4. package/dist/build/prerender.js +4 -3
  5. package/dist/build/report.d.ts +0 -14
  6. package/dist/build/report.js +1 -51
  7. package/dist/check.js +4 -7
  8. package/dist/cli.js +3 -0
  9. package/dist/client/dev-error-overlay-store.d.ts +1 -0
  10. package/dist/client/dev-error-overlay.d.ts +2 -0
  11. package/dist/client/dev-error-overlay.js +20 -4
  12. package/dist/client/navigation-runtime.d.ts +13 -1
  13. package/dist/client/navigation-runtime.js +1 -1
  14. package/dist/config/config-matchers.js +2 -0
  15. package/dist/config/destination-params.d.ts +2 -1
  16. package/dist/config/destination-params.js +52 -2
  17. package/dist/config/next-config.d.ts +25 -0
  18. package/dist/config/next-config.js +82 -4
  19. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
  20. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
  21. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
  22. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
  23. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
  24. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
  25. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
  26. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
  27. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
  28. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
  29. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
  30. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
  31. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
  32. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
  33. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
  34. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
  35. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
  36. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
  37. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
  38. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
  39. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
  40. package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
  41. package/dist/entries/app-rsc-entry.js +17 -49
  42. package/dist/entries/app-rsc-manifest.js +3 -4
  43. package/dist/entries/app-ssr-entry.js +1 -0
  44. package/dist/entries/pages-server-entry.js +36 -9
  45. package/dist/index.js +112 -90
  46. package/dist/init-cloudflare.d.ts +1 -3
  47. package/dist/init-cloudflare.js +10 -48
  48. package/dist/init-platform.d.ts +2 -0
  49. package/dist/init-platform.js +4 -0
  50. package/dist/plugins/extensionless-dynamic-import.js +6 -2
  51. package/dist/plugins/next-intl-catalog.d.ts +12 -0
  52. package/dist/plugins/next-intl-catalog.js +85 -0
  53. package/dist/plugins/pages-node-externals.d.ts +1 -0
  54. package/dist/plugins/pages-node-externals.js +1 -1
  55. package/dist/plugins/strip-server-exports.js +2 -1
  56. package/dist/plugins/use-cache-callable.d.ts +1 -1
  57. package/dist/plugins/use-cache-callable.js +136 -94
  58. package/dist/routing/app-route-graph.d.ts +6 -0
  59. package/dist/routing/app-route-graph.js +9 -1
  60. package/dist/server/api-handler.js +21 -5
  61. package/dist/server/app-bfcache-identity.js +1 -1
  62. package/dist/server/app-browser-entry.js +86 -66
  63. package/dist/server/app-browser-history-controller.d.ts +5 -4
  64. package/dist/server/app-browser-history-controller.js +93 -15
  65. package/dist/server/app-browser-navigation-controller.d.ts +2 -2
  66. package/dist/server/app-browser-navigation-controller.js +1 -2
  67. package/dist/server/app-browser-rsc-redirect.js +7 -7
  68. package/dist/server/app-browser-server-action-client.d.ts +2 -0
  69. package/dist/server/app-browser-server-action-client.js +5 -4
  70. package/dist/server/app-browser-state.d.ts +2 -4
  71. package/dist/server/app-browser-state.js +9 -4
  72. package/dist/server/app-browser-supplemental-refresh.js +16 -1
  73. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  74. package/dist/server/app-browser-visible-commit.js +4 -14
  75. package/dist/server/app-elements-wire.d.ts +6 -38
  76. package/dist/server/app-elements-wire.js +4 -41
  77. package/dist/server/app-elements.d.ts +2 -2
  78. package/dist/server/app-elements.js +2 -2
  79. package/dist/server/app-history-state.d.ts +2 -2
  80. package/dist/server/app-history-state.js +5 -2
  81. package/dist/server/app-mounted-layouts.d.ts +21 -0
  82. package/dist/server/app-mounted-layouts.js +67 -0
  83. package/dist/server/app-optimistic-routing.d.ts +19 -1
  84. package/dist/server/app-optimistic-routing.js +43 -4
  85. package/dist/server/app-page-boundary-render.js +10 -14
  86. package/dist/server/app-page-boundary.js +2 -2
  87. package/dist/server/app-page-cache-finalizer.d.ts +12 -1
  88. package/dist/server/app-page-cache-finalizer.js +70 -29
  89. package/dist/server/app-page-cache.d.ts +13 -1
  90. package/dist/server/app-page-cache.js +31 -9
  91. package/dist/server/app-page-dispatch.d.ts +5 -11
  92. package/dist/server/app-page-dispatch.js +84 -155
  93. package/dist/server/app-page-element-builder.d.ts +2 -2
  94. package/dist/server/app-page-element-builder.js +13 -12
  95. package/dist/server/app-page-execution.d.ts +17 -52
  96. package/dist/server/app-page-execution.js +102 -95
  97. package/dist/server/app-page-head.d.ts +13 -0
  98. package/dist/server/app-page-head.js +44 -16
  99. package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
  100. package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
  101. package/dist/server/app-page-layout-gate.d.ts +35 -0
  102. package/dist/server/app-page-layout-gate.js +50 -0
  103. package/dist/server/app-page-params.d.ts +0 -1
  104. package/dist/server/app-page-params.js +1 -14
  105. package/dist/server/app-page-probe.d.ts +3 -21
  106. package/dist/server/app-page-probe.js +4 -37
  107. package/dist/server/app-page-render.d.ts +2 -13
  108. package/dist/server/app-page-render.js +103 -234
  109. package/dist/server/app-page-request.d.ts +1 -3
  110. package/dist/server/app-page-request.js +1 -1
  111. package/dist/server/app-page-response.js +3 -3
  112. package/dist/server/app-page-route-wiring.d.ts +13 -6
  113. package/dist/server/app-page-route-wiring.js +86 -63
  114. package/dist/server/app-page-rsc-render-status.d.ts +27 -1
  115. package/dist/server/app-page-rsc-render-status.js +121 -13
  116. package/dist/server/app-page-stream.d.ts +12 -8
  117. package/dist/server/app-page-stream.js +4 -3
  118. package/dist/server/app-pages-bridge.d.ts +4 -0
  119. package/dist/server/app-pages-bridge.js +7 -3
  120. package/dist/server/app-render-dependency.d.ts +11 -4
  121. package/dist/server/app-render-dependency.js +86 -38
  122. package/dist/server/app-request-stage-dispatch.js +1 -1
  123. package/dist/server/app-request-stage-independent-entry.js +1 -1
  124. package/dist/server/app-route-handler-cache.js +2 -2
  125. package/dist/server/app-route-handler-dispatch.js +14 -9
  126. package/dist/server/app-route-handler-execution.js +11 -5
  127. package/dist/server/app-route-handler-policy.d.ts +1 -1
  128. package/dist/server/app-route-handler-policy.js +3 -3
  129. package/dist/server/app-route-handler-response.js +1 -1
  130. package/dist/server/app-route-handler-runtime.d.ts +1 -1
  131. package/dist/server/app-route-handler-runtime.js +28 -11
  132. package/dist/server/app-router-entry.js +1 -1
  133. package/dist/server/app-rsc-cache-busting.d.ts +12 -12
  134. package/dist/server/app-rsc-cache-busting.js +31 -72
  135. package/dist/server/app-rsc-error-handler.d.ts +2 -1
  136. package/dist/server/app-rsc-error-handler.js +10 -2
  137. package/dist/server/app-rsc-errors.d.ts +8 -0
  138. package/dist/server/app-rsc-errors.js +11 -1
  139. package/dist/server/app-rsc-handler.d.ts +5 -5
  140. package/dist/server/app-rsc-handler.js +80 -83
  141. package/dist/server/app-rsc-request-normalization.d.ts +10 -16
  142. package/dist/server/app-rsc-request-normalization.js +12 -18
  143. package/dist/server/app-rsc-response-finalizer.js +2 -2
  144. package/dist/server/app-rsc-response-stage.js +9 -15
  145. package/dist/server/app-server-action-execution.d.ts +3 -1
  146. package/dist/server/app-server-action-execution.js +15 -8
  147. package/dist/server/app-ssr-entry.d.ts +8 -0
  148. package/dist/server/app-ssr-entry.js +22 -16
  149. package/dist/server/app-ssr-stream.js +1 -1
  150. package/dist/server/app-visited-response-cache.d.ts +36 -1
  151. package/dist/server/app-visited-response-cache.js +46 -5
  152. package/dist/server/app-worker-stages.d.ts +37 -6
  153. package/dist/server/app-worker-stages.js +81 -9
  154. package/dist/server/artifact-compatibility.d.ts +0 -1
  155. package/dist/server/artifact-compatibility.js +1 -10
  156. package/dist/server/bfcache-identity.d.ts +7 -0
  157. package/dist/server/bfcache-identity.js +10 -1
  158. package/dist/server/cache-proof.d.ts +1 -115
  159. package/dist/server/cache-proof.js +1 -544
  160. package/dist/server/cacheability-manifest.js +1 -2
  161. package/dist/server/cacheability-request.js +13 -8
  162. package/dist/server/dev-origin-check.d.ts +2 -1
  163. package/dist/server/dev-origin-check.js +2 -1
  164. package/dist/server/dev-server.js +6 -4
  165. package/dist/server/headers.d.ts +6 -3
  166. package/dist/server/headers.js +9 -5
  167. package/dist/server/image-optimization.d.ts +5 -0
  168. package/dist/server/image-optimization.js +6 -1
  169. package/dist/server/isr-cache.d.ts +8 -2
  170. package/dist/server/isr-cache.js +30 -2
  171. package/dist/server/metadata-route-response.js +32 -15
  172. package/dist/server/middleware-matcher.js +19 -6
  173. package/dist/server/middleware-runtime.js +6 -2
  174. package/dist/server/multi-stage.d.ts +57 -12
  175. package/dist/server/multi-stage.js +13 -1
  176. package/dist/server/navigation-planner.js +1 -1
  177. package/dist/server/pages-api-route.js +28 -19
  178. package/dist/server/pages-media-type.d.ts +21 -1
  179. package/dist/server/pages-media-type.js +69 -5
  180. package/dist/server/pages-node-compat.d.ts +1 -1
  181. package/dist/server/pages-node-compat.js +54 -27
  182. package/dist/server/pages-page-data.js +2 -1
  183. package/dist/server/pages-page-handler.js +28 -26
  184. package/dist/server/pages-page-response.d.ts +9 -0
  185. package/dist/server/pages-page-response.js +18 -4
  186. package/dist/server/pages-request-pipeline.d.ts +8 -0
  187. package/dist/server/pages-request-pipeline.js +2 -2
  188. package/dist/server/pages-request-stage-entry.js +36 -14
  189. package/dist/server/pages-response-stage-entry.js +9 -3
  190. package/dist/server/pages-router-entry.js +3 -2
  191. package/dist/server/prod-server.d.ts +2 -2
  192. package/dist/server/prod-server.js +47 -9
  193. package/dist/server/request-error-log.d.ts +9 -0
  194. package/dist/server/request-error-log.js +13 -0
  195. package/dist/server/request-pipeline.d.ts +15 -4
  196. package/dist/server/request-pipeline.js +43 -15
  197. package/dist/server/rsc-completion-metadata.js +3 -0
  198. package/dist/server/shared-cache-identity.d.ts +23 -0
  199. package/dist/server/shared-cache-identity.js +36 -0
  200. package/dist/server/static-file-cache.d.ts +9 -0
  201. package/dist/server/static-file-cache.js +13 -2
  202. package/dist/server/worker-stages.d.ts +16 -3
  203. package/dist/server/worker-stages.js +23 -4
  204. package/dist/shims/cache-handler.js +2 -2
  205. package/dist/shims/cache-request-state.d.ts +23 -26
  206. package/dist/shims/cache-request-state.js +22 -57
  207. package/dist/shims/cache-runtime.d.ts +3 -1
  208. package/dist/shims/cache-runtime.js +94 -48
  209. package/dist/shims/cache.d.ts +16 -10
  210. package/dist/shims/cache.js +47 -36
  211. package/dist/shims/cacheability-classification.d.ts +2 -0
  212. package/dist/shims/cdn-cache.d.ts +22 -5
  213. package/dist/shims/client-hook-error.d.ts +2 -0
  214. package/dist/shims/client-hook-error.js +16 -1
  215. package/dist/shims/client-page-root.js +2 -2
  216. package/dist/shims/dynamic.js +9 -6
  217. package/dist/shims/error-boundary.js +2 -2
  218. package/dist/shims/fetch-cache-state.d.ts +5 -1
  219. package/dist/shims/fetch-cache-state.js +1 -3
  220. package/dist/shims/fetch-cache.d.ts +2 -1
  221. package/dist/shims/fetch-cache.js +39 -25
  222. package/dist/shims/form.js +2 -2
  223. package/dist/shims/headers.d.ts +10 -24
  224. package/dist/shims/headers.js +22 -70
  225. package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
  226. package/dist/shims/internal/navigation-untracked.js +1 -1
  227. package/dist/shims/link.js +8 -11
  228. package/dist/shims/metadata.d.ts +23 -21
  229. package/dist/shims/metadata.js +62 -24
  230. package/dist/shims/navigation-server.js +1 -1
  231. package/dist/shims/navigation.d.ts +74 -7
  232. package/dist/shims/navigation.js +184 -31
  233. package/dist/shims/navigation.react-server.js +2 -2
  234. package/dist/shims/request-state-types.d.ts +3 -2
  235. package/dist/shims/slot.d.ts +16 -0
  236. package/dist/shims/slot.js +44 -9
  237. package/dist/shims/unified-request-context.d.ts +7 -1
  238. package/dist/shims/unified-request-context.js +3 -3
  239. package/dist/utils/cache-control-metadata.d.ts +5 -0
  240. package/dist/utils/cache-control-metadata.js +9 -1
  241. package/dist/utils/cache-life-profiles.d.ts +33 -0
  242. package/dist/utils/cache-life-profiles.js +111 -0
  243. package/dist/utils/middleware-request-headers.d.ts +14 -3
  244. package/dist/utils/middleware-request-headers.js +54 -7
  245. package/dist/utils/project.d.ts +2 -2
  246. package/dist/utils/project.js +3 -16
  247. package/dist/utils/regex.d.ts +5 -0
  248. package/dist/utils/regex.js +11 -1
  249. package/dist/utils/text-stream.d.ts +10 -5
  250. package/dist/utils/text-stream.js +6 -6
  251. package/package.json +2 -1
  252. package/dist/build/layout-classification-types.d.ts +0 -60
  253. package/dist/build/layout-classification-types.js +0 -1
  254. package/dist/build/layout-classification.d.ts +0 -62
  255. package/dist/build/layout-classification.js +0 -98
  256. package/dist/build/route-classification-injector.d.ts +0 -33
  257. package/dist/build/route-classification-injector.js +0 -59
  258. package/dist/build/route-classification-manifest.d.ts +0 -54
  259. package/dist/build/route-classification-manifest.js +0 -143
  260. package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
  261. package/dist/server/app-browser-client-reuse-manifest.js +0 -101
  262. package/dist/server/app-layout-param-observation.d.ts +0 -42
  263. package/dist/server/app-layout-param-observation.js +0 -168
  264. package/dist/server/client-reuse-manifest.d.ts +0 -103
  265. package/dist/server/client-reuse-manifest.js +0 -209
  266. package/dist/server/skip-cache-proof.d.ts +0 -60
  267. package/dist/server/skip-cache-proof.js +0 -168
  268. package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
  269. package/dist/server/static-layout-client-reuse-proof.js +0 -33
  270. package/dist/utils/sorted-array.d.ts +0 -8
  271. package/dist/utils/sorted-array.js +0 -20
@@ -1,15 +1,16 @@
1
1
  import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
2
2
  import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
3
- import { VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
3
+ import { PRERENDER_REVALIDATE_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
4
4
  import "./headers.js";
5
5
  import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders } from "./request-pipeline.js";
6
6
  import { getRequestExecutionContext } from "../shims/request-context.js";
7
7
  import { runOutsideWorkStoreScope } from "../shims/internal/work-store-scope.js";
8
+ import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
8
9
  import { applyEffectiveRequestCookieHeader, getDraftModeCookieHeader, headersContextFromRequest, restoreDraftModeTransition } from "../shims/headers.js";
9
10
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
10
11
  import { traceFindPageComponents } from "./pages-execution-tracing.js";
11
12
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
12
- import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, hasRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
13
+ import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, hasRscCacheBustingSearchParam, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
13
14
  import { traceAppPageRender } from "./app-page-tracing.js";
14
15
  import { buildPageCacheTags } from "./implicit-tags.js";
15
16
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
@@ -47,13 +48,6 @@ function requestWithoutRscCacheBustingSearchParam(request) {
47
48
  stripRscCacheBustingSearchParam(url);
48
49
  return cloneRequestWithUrl(request, url.toString());
49
50
  }
50
- function requestWithoutRscSuffix(request) {
51
- const url = new URL(request.url);
52
- const pathname = stripRscSuffix(url.pathname);
53
- if (pathname === url.pathname) return request;
54
- url.pathname = pathname;
55
- return cloneRequestWithUrl(request, url.toString());
56
- }
57
51
  function pathnameForResolvedUrl(resolvedUrl) {
58
52
  return resolvedUrl.split("#", 1)[0].split("?", 1)[0];
59
53
  }
@@ -69,7 +63,7 @@ function rematchAppWorkerResponseStageRoute(options, normalized, props) {
69
63
  return match;
70
64
  }
71
65
  async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, stageOptions) {
72
- if (props.protocolVersion !== 11 || props.buildId !== options.buildId) return new Response("Incompatible vinext App response stage", { status: 409 });
66
+ if (props.protocolVersion !== 13 || props.buildId !== options.buildId) return new Response("Incompatible vinext App response stage", { status: 409 });
73
67
  if (props.kind === "app-full-request") return new Response("Invalid vinext App response stage", { status: 400 });
74
68
  const rawRequestSignal = rawRequest.signal;
75
69
  options.registerCacheAdapters();
@@ -104,6 +98,7 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
104
98
  const requestContext = createRequestContext({
105
99
  headersContext,
106
100
  executionContext,
101
+ isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER)),
107
102
  requestSignal: executionContext?.requestSignal ?? rawRequestSignal,
108
103
  unstableCacheRevalidation: "background"
109
104
  });
@@ -171,6 +166,7 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
171
166
  pathname: props.resolvedUrl,
172
167
  pagesDataRequest: props.isDataRequest ? request : null,
173
168
  request: pageRequest,
169
+ sharedAcrossHosts: props.sharedAcrossHosts,
174
170
  url: new URL(props.requestUrl)
175
171
  }));
176
172
  if (!pagesResponse) return new Response("Invalid vinext App response stage", { status: 404 });
@@ -189,9 +185,8 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
189
185
  setRootParams(rootParams);
190
186
  if (props.kind === "app-route-handler") {
191
187
  setCurrentFetchSoftTags(buildPageCacheTags(props.cleanPathname, [], [...route.routeSegments], "route"));
192
- const normalizedUserlandRequest = requestWithoutRscSuffix(request);
193
- const userlandRequest = requestWithoutRscCacheBustingSearchParam(normalizedUserlandRequest);
194
- const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest : normalizedUserlandRequest;
188
+ const userlandRequest = requestWithoutRscCacheBustingSearchParam(request);
189
+ const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest : request;
195
190
  const routeHandlerUrl = new URL(routeHandlerRequest.url);
196
191
  const internalRscValues = isEdgeRouteHandler(route.routeHandler) ? [] : routeHandlerUrl.searchParams.getAll(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
197
192
  routeHandlerUrl.search = searchParams.toString();
@@ -216,14 +211,13 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
216
211
  return options.dispatchMatchedPage({
217
212
  bypassInterceptionContextCache: props.bypassInterceptionContextCache,
218
213
  cachePathname: props.cachePathname,
219
- clientReuseManifest: normalized.clientReuseManifest,
220
214
  cleanPathname: props.cleanPathname,
221
215
  displayPathname: props.canonicalPathname,
222
216
  formState: null,
223
217
  handlerStart: process.env.NODE_ENV !== "production" ? performance.now() : 0,
224
218
  interceptionContext: normalized.interceptionContextHeader,
225
219
  interceptionId: normalized.interceptionIdHeader,
226
- interceptionPathname: props.matchKind === "resolved" ? props.cleanPathname : normalized.requestCleanPathname,
220
+ interceptionPathname: props.matchKind === "resolved" ? props.cleanPathname : normalized.requestPathname,
227
221
  isProgressiveActionRender: false,
228
222
  isRscRequest: normalized.isRscRequest,
229
223
  middlewareContext,
@@ -1,10 +1,10 @@
1
1
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
2
- import { ActionRevalidationKind } from "../shims/cache-request-state.js";
3
2
  import { AppRenderErrorContextOverrides } from "./app-rsc-error-handler.js";
4
3
  import { FetchCacheMode } from "../shims/fetch-cache-state.js";
5
4
  import "../shims/fetch-cache.js";
6
5
  import { HeadersAccessPhase } from "../shims/internal/headers-state.js";
7
6
  import "../shims/headers.js";
7
+ import { ActionRevalidationKind } from "../shims/cache-request-state.js";
8
8
  import { ReactFormState } from "react-dom/client";
9
9
  //#region src/server/app-server-action-execution.d.ts
10
10
  type AppPageParams = Record<string, string | string[]>;
@@ -156,6 +156,8 @@ export type HandleProgressiveServerActionRequestOptions = {
156
156
  * routes fall through. See issue #1340.
157
157
  */
158
158
  hasPageRoute: boolean;
159
+ /** The App Router route the form posted to, whose implicit tags the action runs with. */
160
+ currentRoute?: AppServerActionRoute | null;
159
161
  maxActionBodySize: number;
160
162
  middlewareHeaders: Headers | null;
161
163
  readFormDataWithLimit: ReadFormDataWithLimit;
@@ -6,24 +6,25 @@ import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
6
6
  import { isExternalUrl } from "../utils/external-url.js";
7
7
  import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
8
8
  import { NEXT_ROUTER_STATE_TREE_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
9
- import { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
9
+ import { ACTION_FORWARDED_HEADER, ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, ACTION_REDIRECT_TYPE_HEADER, ACTION_REVALIDATED_HEADER, VINEXT_MOUNTED_LAYOUTS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
10
10
  import { internalServerErrorResponse, payloadTooLargeResponse } from "./http-error-responses.js";
11
11
  import { attachRequestCfMetadata, validateCsrfOrigin, validateServerActionPayload } from "./request-pipeline.js";
12
12
  import { splitPathSegments } from "../routing/utils.js";
13
13
  import { getRequestExecutionContext } from "../shims/request-context.js";
14
+ import { logRequestError } from "./request-error-log.js";
14
15
  import { shareIsolatePromise } from "./isolate-shared-promise.js";
15
16
  import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
16
17
  import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
17
18
  import { _drainPendingRevalidations, getAndClearActionRevalidationKind } from "../shims/cache-request-state.js";
18
19
  import { setCurrentFetchCacheMode, setCurrentFetchRevalidate, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
19
20
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
20
- import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscRequestUrl, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
21
21
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
22
+ import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscRequestUrl, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
23
+ import { getSetCookieName } from "./cookie-utils.js";
24
+ import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
22
25
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
23
26
  import { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
24
27
  import { hasDigest } from "./app-rsc-errors.js";
25
- import { getSetCookieName } from "./cookie-utils.js";
26
- import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
27
28
  import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
28
29
  import "./app-page-stream.js";
29
30
  import { buildAppPageTags } from "./implicit-tags.js";
@@ -211,6 +212,7 @@ async function createActionRedirectTargetRequest(options) {
211
212
  headers.set("cookie", cookieHeader ?? "");
212
213
  headers.set("RSC", "1");
213
214
  headers.delete(NEXT_ROUTER_STATE_TREE_HEADER);
215
+ headers.delete(VINEXT_MOUNTED_LAYOUTS_HEADER);
214
216
  stripRscCacheBustingSearchParam(options.url);
215
217
  const requestPath = await createRscRequestUrl(`${options.url.pathname}${options.url.search}`, headers);
216
218
  const requestUrl = new URL(requestPath, options.url.origin);
@@ -508,7 +510,10 @@ function createRejectedActionResult(error) {
508
510
  * Next.js, a thrown string is not logged in development.
509
511
  */
510
512
  function logRejectedActionResult(error) {
511
- if (process.env.NODE_ENV === "production" || hasDigest(error)) console.error("[vinext] Server action error:", error);
513
+ if (process.env.NODE_ENV === "production" || hasDigest(error)) {
514
+ if (typeof error === "string") console.error("[vinext] Server action error:", error);
515
+ else logRequestError("[vinext] Server action error:", error);
516
+ }
512
517
  }
513
518
  function getActionHttpFallbackStatus(error) {
514
519
  const digest = getNextErrorDigest(error);
@@ -519,7 +524,7 @@ function getActionHttpFallbackStatus(error) {
519
524
  }
520
525
  function createServerActionErrorResponse(error, options) {
521
526
  options.getAndClearPendingCookies();
522
- console.error("[vinext] Server action error:", error);
527
+ logRequestError("[vinext] Server action error:", error);
523
528
  options.reportRequestError(error, {
524
529
  path: options.cleanPathname,
525
530
  method: options.request.method,
@@ -614,6 +619,7 @@ async function handleProgressiveServerActionRequest(options) {
614
619
  let actionThrew = false;
615
620
  let actionResult;
616
621
  const rootParamsUsage = createRootParamsUsageController();
622
+ if (options.currentRoute) setCurrentFetchSoftTags(buildServerActionPageTags(options.currentRoute, options.cleanPathname));
617
623
  const previousHeadersPhase = options.setHeadersAccessPhase("action");
618
624
  try {
619
625
  actionResult = await runWithRootParamsUsage({ kind: "server-action" }, action, rootParamsUsage);
@@ -625,7 +631,7 @@ async function handleProgressiveServerActionRequest(options) {
625
631
  actionFailed = true;
626
632
  actionFailedWithError = getActionHttpFallbackStatus(error) === null && !isServerActionNotFoundError(error, null);
627
633
  if (actionFailedWithError) {
628
- console.error("[vinext] Server action error:", error);
634
+ logRequestError("[vinext] Server action error:", error);
629
635
  options.reportRequestError(error, {
630
636
  path: options.cleanPathname,
631
637
  method: options.request.method,
@@ -697,7 +703,7 @@ async function handleProgressiveServerActionRequest(options) {
697
703
  });
698
704
  getAndClearActionRevalidationKind();
699
705
  options.getAndClearPendingCookies();
700
- console.error("[vinext] Server action payload parsing error:", error);
706
+ logRequestError("[vinext] Server action payload parsing error:", error);
701
707
  options.reportRequestError(error, {
702
708
  path: options.cleanPathname,
703
709
  method: options.request.method,
@@ -823,6 +829,7 @@ async function handleServerActionRscRequest(options) {
823
829
  let actionThrew = false;
824
830
  const actionWasForwarded = Boolean(options.request.headers.get(ACTION_FORWARDED_HEADER));
825
831
  const rootParamsUsage = createRootParamsUsageController();
832
+ if (options.currentRouteMatch) setCurrentFetchSoftTags(buildServerActionPageTags(options.currentRouteMatch.route, options.cleanPathname));
826
833
  const previousHeadersPhase = options.setHeadersAccessPhase("action");
827
834
  try {
828
835
  try {
@@ -25,6 +25,8 @@ export declare function handleSsr(rscStream: ReadableStream<Uint8Array>, navCont
25
25
  value: Promise<ArrayBuffer> | null;
26
26
  };
27
27
  pprFallbackShellSignal?: AbortSignal;
28
+ /** Aborts a streaming render whose document is given up. */
29
+ signal?: AbortSignal;
28
30
  /**
29
31
  * Pattern of the route this render shows, whose client references load
30
32
  * before it starts, or null for a render without a route (a route-miss
@@ -70,6 +72,12 @@ export declare function handleSsr(rscStream: ReadableStream<Uint8Array>, navCont
70
72
  */
71
73
  isCacheCandidate?: boolean;
72
74
  fallbackToErrorDocumentOnShellError?: boolean;
75
+ /**
76
+ * Whether the RSC render threw the given shell error. As in Next.js, in
77
+ * dev the error document carries only an error that the HTML render alone
78
+ * threw, for the overlay: the browser reports the others itself.
79
+ */
80
+ isServerComponentError?: (error: unknown) => boolean;
73
81
  /**
74
82
  * The parallel slot not-found boundaries that catch the error that
75
83
  * rejected the shell, or null when none catches it. The document then
@@ -2,6 +2,7 @@ import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
2
2
  import { notFoundResponse } from "./http-error-responses.js";
3
3
  import { isOpenRedirectShaped, repeatedSlashRedirectResponse } from "./open-redirect.js";
4
4
  import "./server-globals.js";
5
+ import { isNavigationSignalError } from "../utils/navigation-signal.js";
5
6
  import { isPprFallbackShellAbortError } from "../shims/ppr-fallback-shell.js";
6
7
  import { onRenderDynamicLatched } from "../shims/internal/headers-state.js";
7
8
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
@@ -10,23 +11,24 @@ import { withScriptNonce } from "../shims/script-nonce-context.js";
10
11
  import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
11
12
  import { getClientTraceMetadataHTML, markClientTraceMetadataBlock } from "./client-trace-metadata.js";
12
13
  import { setPagesClientAssets } from "./pages-client-assets.js";
14
+ import { RSC_FORM_STATE_GLOBAL } from "../client/browser-globals.js";
15
+ import { createNavigationRuntimeRenderedSearchScript, createNavigationRuntimeRscCompatibilityScript, createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, rewriteInlineCssStylesheetLinks, waitAtLeastOneReactRenderTask } from "./app-ssr-stream.js";
13
16
  import { AppElementsWire } from "./app-elements-wire.js";
14
17
  import "./app-elements.js";
18
+ import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
19
+ import { isBailoutToCSRError, isDynamicServerError } from "../shims/navigation-errors.js";
15
20
  import { ServerInsertedHTMLContext, clearServerInsertedHTML, getBfcacheIdMapContext, registerServerInsertedHTMLCallback, renderServerInsertedHTML, setNavigationContext } from "../shims/navigation-context-state.js";
16
21
  import "../shims/navigation-server.js";
17
- import DefaultGlobalError from "../shims/default-global-error.js";
18
- import { CAUGHT_NOT_FOUND_BOUNDARIES_GLOBAL, withCaughtNotFoundBoundaries } from "../shims/caught-not-found-boundaries.js";
19
22
  import { BfcacheIdentityMapContext } from "../shims/slot.js";
20
- import { getNextErrorDigest } from "./next-error-digest.js";
21
- import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
22
- import { createRenderStreamCancellation, isAppRenderAbortError } from "./app-render-abort-error.js";
23
- import { RSC_FORM_STATE_GLOBAL } from "../client/browser-globals.js";
24
- import { createNavigationRuntimeRenderedSearchScript, createNavigationRuntimeRscCompatibilityScript, createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, rewriteInlineCssStylesheetLinks, waitAtLeastOneReactRenderTask } from "./app-ssr-stream.js";
25
- import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
26
23
  import { createAppRouteTree } from "./app-route-tree.js";
24
+ import DefaultGlobalError from "../shims/default-global-error.js";
25
+ import { CAUGHT_NOT_FOUND_BOUNDARIES_GLOBAL, withCaughtNotFoundBoundaries } from "../shims/caught-not-found-boundaries.js";
27
26
  import { ssrServerConsumerManifest } from "./app-client-reference-manifest.js";
28
27
  import { createClientReferencePreloader, resolveRouteClientReferences } from "./app-client-reference-preloader.js";
28
+ import { getNextErrorDigest } from "./next-error-digest.js";
29
+ import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
29
30
  import { createClientPageSsrSearchParamsSource } from "./app-page-search-params-observation.js";
31
+ import { createRenderStreamCancellation, isAppRenderAbortError } from "./app-render-abort-error.js";
30
32
  import { runWithRootParamsScope } from "../shims/root-params.js";
31
33
  import { runWithNavigationContext } from "../shims/navigation-state.js";
32
34
  import { startCandidateSearchParamsGate } from "./app-ssr-search-params-gate.js";
@@ -71,13 +73,14 @@ function createUtf8Stream(html) {
71
73
  controller.close();
72
74
  } });
73
75
  }
74
- function buildBootstrapModuleScript(bootstrapModuleUrl, nonce) {
76
+ function buildBootstrapModuleScript(bootstrapModuleUrl, nonce, crossOrigin) {
75
77
  if (!bootstrapModuleUrl) return "";
76
- return `<script type="module"${createNonceAttribute(nonce)} src="` + escapeHtmlAttr(bootstrapModuleUrl) + "\" id=\"_R_\" async=\"\" fetchPriority=\"low\"><\/script>";
78
+ const crossOriginAttribute = crossOrigin === void 0 ? "" : ` crossorigin="${crossOrigin === "use-credentials" ? "use-credentials" : ""}"`;
79
+ return `<script type="module"${createNonceAttribute(nonce)} src="` + escapeHtmlAttr(bootstrapModuleUrl) + `"${crossOriginAttribute} id="_R_" async="" fetchPriority="low"><\/script>`;
77
80
  }
78
- function renderSsrErrorDocumentShell(bootstrapModuleUrl, nonce) {
79
- const html = renderToStaticMarkup(createElement(DefaultGlobalError, { error: null })).replace("<style>", "<style data-vinext-error-shell-style=\"\">");
80
- const bootstrapScript = buildBootstrapModuleScript(bootstrapModuleUrl, nonce);
81
+ function renderSsrErrorDocumentShell(bootstrapModuleUrl, nonce, crossOrigin) {
82
+ const html = renderToStaticMarkup(createElement(DefaultGlobalError, { error: null })).replace("<head>", "<head><meta name=\"robots\" content=\"noindex\"/>").replace("<style>", "<style data-vinext-error-shell-style=\"\">");
83
+ const bootstrapScript = buildBootstrapModuleScript(bootstrapModuleUrl, nonce, crossOrigin);
81
84
  if (!bootstrapScript) return createUtf8Stream(`<!DOCTYPE html>${html}`);
82
85
  const documentClose = "</body></html>";
83
86
  if (!html.endsWith(documentClose)) return createUtf8Stream(`<!DOCTYPE html>${html}${bootstrapScript}`);
@@ -277,6 +280,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
277
280
  if (link) reactLinkHeader = link;
278
281
  } : void 0,
279
282
  maxHeadersLength: captureHeaders ? maxHeadersLength : void 0,
283
+ signal: options?.signal,
280
284
  onError(error) {
281
285
  if (pprFallbackShellSignal && isPprFallbackShellAbortError(error)) return;
282
286
  if (isAppRenderAbortError(error) || htmlCancellation.isReason(error)) return;
@@ -291,6 +295,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
291
295
  let htmlStream;
292
296
  let renderComplete = Promise.resolve();
293
297
  let shellErrorRecovered = false;
298
+ let ssrOnlyShellError;
294
299
  let caughtShellError;
295
300
  let caughtBoundaries = null;
296
301
  let shouldDelayInitialHtmlPull = false;
@@ -354,10 +359,11 @@ async function handleSsr(rscStream, navContext, fontData, options) {
354
359
  shouldDelayInitialHtmlPull = options?.waitForAllReady !== true;
355
360
  caughtShellError = error;
356
361
  htmlStream = caughtHtmlStream;
357
- } else if (options?.fallbackToErrorDocumentOnShellError !== true || options?.waitForAllReady === true || typeof error?.digest === "string") throw error;
362
+ } else if (options?.fallbackToErrorDocumentOnShellError !== true || isNavigationSignalError(error) || isBailoutToCSRError(error) || isDynamicServerError(error)) throw error;
358
363
  else {
359
364
  shellErrorRecovered = true;
360
- htmlStream = renderSsrErrorDocumentShell(bootstrapModuleUrl, options?.scriptNonce);
365
+ if (options?.isServerComponentError?.(error) !== true) ssrOnlyShellError = error;
366
+ htmlStream = renderSsrErrorDocumentShell(bootstrapModuleUrl, options?.scriptNonce, assetCrossOrigin);
361
367
  }
362
368
  }
363
369
  }
@@ -384,7 +390,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
384
390
  const getInsertedHTML = () => {
385
391
  const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());
386
392
  const errorMetaHTML = errorMetaRenderer.flush();
387
- const initialDevServerErrorHTML = createInitialDevServerErrorScript(options?.initialDevServerError, options?.scriptNonce);
393
+ const initialDevServerErrorHTML = createInitialDevServerErrorScript(options?.initialDevServerError ?? ssrOnlyShellError, options?.scriptNonce);
388
394
  if (didInjectHeadHTML) return insertedHTML + errorMetaHTML + getRenderedSearchHTML();
389
395
  didInjectHeadHTML = true;
390
396
  const hidesQuery = searchParamsGate !== null && searchParamsGate.gate.decision !== "real";
@@ -1,7 +1,7 @@
1
1
  import { createNonceAttribute, escapeHtmlAttr, htmlTokenListContains, safeJsonStringify, scriptSafeJsonStringify } from "./html.js";
2
- import { getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
3
2
  import { bytesToBase64, concatUint8Arrays } from "./app-rsc-embedded-chunks.js";
4
3
  import { NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION } from "../client/browser-globals.js";
4
+ import { getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
5
5
  import { Buffer, isUtf8 } from "node:buffer";
6
6
  //#region src/server/app-ssr-stream.ts
7
7
  const RSC_EMBED_TEXT_BATCH_MAX_BYTES = 65536;
@@ -7,7 +7,17 @@ export type VisitedResponseCacheEntry = {
7
7
  createdAt: number;
8
8
  elements?: AppElements;
9
9
  expiresAt: number;
10
+ /**
11
+ * Stored by initial hydration, which Next.js keeps out of its route cache
12
+ * (outside Cache Components), so a visible Link still prefetches the URL.
13
+ */
14
+ fromHydration?: true;
10
15
  mountedSlotsHeader: string | null;
16
+ /**
17
+ * A history restore revoked navigation reuse. The entry stays only as the
18
+ * BFCache that a full prefetch reads (see `findVisitedResponseForFullPrefetch`).
19
+ */
20
+ navigationReuseRevoked?: true;
11
21
  params: Record<string, string | string[]>;
12
22
  response: CachedRscResponse;
13
23
  reuseAfterHistoryRestore: boolean;
@@ -18,6 +28,7 @@ export declare function hasNavigationResponseHistoryLifetime(snapshot: CachedRsc
18
28
  export declare function createVisitedResponseCacheEntry(options: {
19
29
  elements?: AppElements;
20
30
  fallbackTtlMs?: number;
31
+ fromHydration?: boolean;
21
32
  now: number;
22
33
  mountedSlotsHeader?: string | null;
23
34
  params: Record<string, string | string[]>;
@@ -34,6 +45,30 @@ export declare function findVisitedResponseCacheEntry(cache: Map<string, Visited
34
45
  } | null;
35
46
  export declare function deleteVisitedResponseCacheEntry(cache: Map<string, VisitedResponseCacheEntry>, rscUrl: string, interceptionContext: string | null): boolean;
36
47
  export declare function deleteAllVisitedResponseCacheEntries(cache: Map<string, VisitedResponseCacheEntry>, rscUrl: string, interceptionContext: string | null): number;
37
- export declare function deleteInvalidatedHistoryRestoreEntries(cache: Map<string, VisitedResponseCacheEntry>): void;
48
+ export declare function revokeHistoryRestoreNavigationReuse(cache: Map<string, VisitedResponseCacheEntry>): void;
49
+ /**
50
+ * Next.js fulfills a full prefetch from the BFCache, which holds the data of
51
+ * every navigation, while it is within the static stale time of that
52
+ * navigation (`attemptToFulfillDynamicSegmentFromBFCache`). Navigation reuse
53
+ * that a history restore revoked does not matter here.
54
+ *
55
+ * Next.js dates a BFCache entry from its navigation, even one that committed an
56
+ * older prefetched payload. Its re-prefetch of an expired route still waits for
57
+ * a fresh route tree first, so a navigation made then fetches fresh data
58
+ * (`client-cache.experimental.test.ts`, "re-use the cache for 5 minutes").
59
+ * vinext seeds the full prefetch synchronously, so dating it from the
60
+ * navigation would replay that expired payload. It dates from when the payload
61
+ * arrived instead, which only costs a request Next.js might have saved.
62
+ *
63
+ * The match follows direct visited reuse: an entry with committed elements
64
+ * replays them, because its raw response may be skip-pruned against the tree
65
+ * it was requested from; otherwise the request-time or response-declared slot
66
+ * context must match.
67
+ */
68
+ export declare function findVisitedResponseForFullPrefetch(cache: Map<string, VisitedResponseCacheEntry>, rscUrls: readonly string[], interceptionContext: string | null, mountedSlotsHeader: string | null): {
69
+ navigatedAt: number;
70
+ navigationFreshUntil: number | null;
71
+ response: CachedRscResponse;
72
+ } | null;
38
73
  //#endregion
39
74
  export {};
@@ -1,6 +1,6 @@
1
+ import { parseRscRequestPath, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
1
2
  import { AppElementsWire } from "./app-elements-wire.js";
2
3
  import "./app-elements.js";
3
- import { parseRscRequestPath, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
4
4
  import { resolveCachedRscResponseExpiresAt } from "../shims/navigation.js";
5
5
  //#region src/server/app-visited-response-cache.ts
6
6
  const VISITED_RESPONSE_CACHE_TTL = 3e5;
@@ -14,6 +14,7 @@ function createVisitedResponseCacheEntry(options) {
14
14
  createdAt: options.now,
15
15
  ...options.elements ? { elements: options.elements } : {},
16
16
  expiresAt: resolveCachedRscResponseExpiresAt(options.now, options.response, options.fallbackTtlMs ?? 3e5),
17
+ ...options.fromHydration === true ? { fromHydration: true } : {},
17
18
  mountedSlotsHeader: options.mountedSlotsHeader ?? null,
18
19
  params: options.params,
19
20
  response: options.response,
@@ -75,11 +76,51 @@ function deleteAllVisitedResponseCacheEntries(cache, rscUrl, interceptionContext
75
76
  while (deleteVisitedResponseCacheEntry(cache, rscUrl, interceptionContext)) deleted++;
76
77
  return deleted;
77
78
  }
78
- function deleteInvalidatedHistoryRestoreEntries(cache) {
79
- for (const [cacheKey, entry] of cache) {
79
+ function revokeHistoryRestoreNavigationReuse(cache) {
80
+ for (const entry of cache.values()) {
80
81
  if (entry.reuseAfterHistoryRestore) continue;
81
- cache.delete(cacheKey);
82
+ entry.navigationReuseRevoked = true;
83
+ }
84
+ }
85
+ /**
86
+ * Next.js fulfills a full prefetch from the BFCache, which holds the data of
87
+ * every navigation, while it is within the static stale time of that
88
+ * navigation (`attemptToFulfillDynamicSegmentFromBFCache`). Navigation reuse
89
+ * that a history restore revoked does not matter here.
90
+ *
91
+ * Next.js dates a BFCache entry from its navigation, even one that committed an
92
+ * older prefetched payload. Its re-prefetch of an expired route still waits for
93
+ * a fresh route tree first, so a navigation made then fetches fresh data
94
+ * (`client-cache.experimental.test.ts`, "re-use the cache for 5 minutes").
95
+ * vinext seeds the full prefetch synchronously, so dating it from the
96
+ * navigation would replay that expired payload. It dates from when the payload
97
+ * arrived instead, which only costs a request Next.js might have saved.
98
+ *
99
+ * The match follows direct visited reuse: an entry with committed elements
100
+ * replays them, because its raw response may be skip-pruned against the tree
101
+ * it was requested from; otherwise the request-time or response-declared slot
102
+ * context must match.
103
+ */
104
+ function findVisitedResponseForFullPrefetch(cache, rscUrls, interceptionContext, mountedSlotsHeader) {
105
+ for (const rscUrl of rscUrls) {
106
+ const match = findVisitedResponseCacheEntry(cache, rscUrl, interceptionContext);
107
+ if (match === null) continue;
108
+ const { entry } = match;
109
+ if (entry.elements === void 0 && entry.mountedSlotsHeader !== mountedSlotsHeader && (entry.response.mountedSlotsHeader ?? null) !== mountedSlotsHeader) continue;
110
+ const navigationFresh = entry.fromHydration !== true && entry.navigationReuseRevoked !== true && (entry.elements !== void 0 || entry.mountedSlotsHeader === mountedSlotsHeader) && isVisitedResponseCacheEntryFresh(entry, {
111
+ navigationKind: "navigate",
112
+ now: Date.now()
113
+ });
114
+ return {
115
+ navigatedAt: entry.response.receivedAt ?? entry.createdAt,
116
+ navigationFreshUntil: navigationFresh ? entry.expiresAt : null,
117
+ response: entry.elements === void 0 ? entry.response : {
118
+ ...entry.response,
119
+ preparedElements: entry.elements
120
+ }
121
+ };
82
122
  }
123
+ return null;
83
124
  }
84
125
  //#endregion
85
- export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, createVisitedResponseCacheEntry, deleteAllVisitedResponseCacheEntries, deleteInvalidatedHistoryRestoreEntries, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, hasNavigationResponseHistoryLifetime, isVisitedResponseCacheEntryFresh };
126
+ export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, createVisitedResponseCacheEntry, deleteAllVisitedResponseCacheEntries, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, findVisitedResponseForFullPrefetch, hasNavigationResponseHistoryLifetime, isVisitedResponseCacheEntryFresh, revokeHistoryRestoreNavigationReuse };
@@ -3,7 +3,7 @@ import { VinextResponseStageCacheability, VinextResponseStageDispatchOptions, Vi
3
3
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
4
  import { TrustedPrerenderState } from "./prerender-route-params.js";
5
5
  //#region src/server/app-worker-stages.d.ts
6
- export declare const APP_WORKER_RESPONSE_STAGE_PROTOCOL_VERSION = 11;
6
+ export declare const APP_WORKER_RESPONSE_STAGE_PROTOCOL_VERSION = 13;
7
7
  export declare const APP_METADATA_RESPONSE_STAGE_NO_MATCH_HEADER = "x-vinext-app-metadata-stage-no-match";
8
8
  type AppPageParams = Record<string, string | string[]>;
9
9
  type AppWorkerResponseStageEnvelope = {
@@ -66,7 +66,7 @@ type AppMetadataWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
66
66
  resolvedUrl: string;
67
67
  routePathname: string;
68
68
  };
69
- type HybridPagesWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
69
+ export type HybridPagesWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
70
70
  kind: "hybrid-pages";
71
71
  allowRscDocumentFallback: boolean;
72
72
  appRouteMatch: {
@@ -83,19 +83,50 @@ type HybridPagesWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
83
83
  resourceKind: "api" | "page";
84
84
  requestUrl: string;
85
85
  resolvedUrl: string;
86
+ /**
87
+ * The shared cache entry answers every host, as Next.js keys a static page
88
+ * by its path, so a getInitialProps render of a page without
89
+ * getStaticProps, which reads the request, is not stored.
90
+ */
91
+ sharedAcrossHosts: boolean;
86
92
  };
87
93
  export type AppWorkerResponseStageProps = AppFullRequestWorkerResponseStageProps | AppMatchedWorkerResponseStageProps | AppMetadataWorkerResponseStageProps | AppNotFoundWorkerResponseStageProps | HybridPagesWorkerResponseStageProps;
88
94
  export type DispatchAppWorkerResponseStage = VinextResponseStageTransport<AppWorkerResponseStageProps>;
89
95
  export type RenderAppWorkerResponseStageLocally = (request: Request, props: AppWorkerResponseStageProps) => Promise<Response>;
90
96
  /** Normalize a shared App page HEAD request onto its method-invariant GET representation. */
91
97
  export declare function prepareSharedAppPageDispatch(request: Request, cache: VinextResponseStageDispatchOptions["cache"]): Request;
98
+ type SharedAppCacheIdentity = NonNullable<VinextResponseStageDispatchOptions["cacheIdentity"]>;
99
+ /** App Router dispatches whose shared cache entry every host can reuse. */
100
+ export type SharedAppCacheIdentityProps = Exclude<AppWorkerResponseStageProps, {
101
+ kind: "app-full-request" | "hybrid-pages";
102
+ }>;
103
+ /**
104
+ * Build the cache identity of a shared App Router dispatch: the dispatched
105
+ * request and props under the cache identity origin.
106
+ */
107
+ export declare function createSharedAppCacheIdentity(request: Request, props: SharedAppCacheIdentityProps): SharedAppCacheIdentity;
92
108
  /**
93
109
  * Build the query-free cache identity of a shared App page dispatch. The user
94
- * query leaves both the URL and `resolvedUrl`; the `.rsc` suffix, an RSC
95
- * request's validated `_rsc`, and the render mode stay because they select the
96
- * representation. HTML identities also drop the RSC selector headers.
110
+ * query leaves both the URL and `resolvedUrl`; an RSC request's validated
111
+ * `_rsc` and the render mode stay because they select the representation. HTML identities also drop the RSC selector headers.
112
+ */
113
+ export declare function createSharedAppPageCacheIdentity(request: Request, props: AppMatchedWorkerResponseStageProps): SharedAppCacheIdentity;
114
+ /**
115
+ * Build the query-free cache identity of a shared Route Handler or metadata
116
+ * route dispatch. Next.js keys a route handler by its pathname: the query and
117
+ * the RSC selectors pick no representation of a handler's response, and a
118
+ * handler that reads the request's URL or headers is dynamic, so admission
119
+ * refuses its response. Keeping them in the identity would only let a client
120
+ * store one entry per query or selector value. The method, path and route
121
+ * props stay; the selector headers and the props derived from them leave.
122
+ */
123
+ export declare function createSharedAppRouteCacheIdentity(request: Request, props: AppMatchedWorkerResponseStageProps | AppMetadataWorkerResponseStageProps): SharedAppCacheIdentity;
124
+ /**
125
+ * Build the cache identity of a shared hybrid Pages page dispatch: the
126
+ * dispatched request and props under `origin`, so every host that names it
127
+ * shares one entry.
97
128
  */
98
- export declare function createSharedAppPageCacheIdentity(request: Request, props: AppMatchedWorkerResponseStageProps): NonNullable<VinextResponseStageDispatchOptions["cacheIdentity"]>;
129
+ export declare function createSharedHybridPagesCacheIdentity(request: Request, props: HybridPagesWorkerResponseStageProps, origin: string): SharedAppCacheIdentity;
99
130
  /**
100
131
  * Drop the user query from an App page dispatch URL and its `resolvedUrl`,
101
132
  * keeping an RSC request's validated `_rsc`, the rule the query-free cache