vinext 1.3.1 → 1.4.0

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 (234) hide show
  1. package/README.md +5 -2
  2. package/THIRD_PARTY_LICENSES.md +47 -0
  3. package/dist/_virtual/_rolldown/runtime.js +3 -2
  4. package/dist/build/prerender.js +1 -1
  5. package/dist/build/report.d.ts +0 -14
  6. package/dist/build/report.js +1 -51
  7. package/dist/check.js +1 -1
  8. package/dist/cli.js +3 -0
  9. package/dist/client/dev-error-overlay.js +1 -1
  10. package/dist/client/navigation-runtime.d.ts +13 -1
  11. package/dist/client/navigation-runtime.js +1 -1
  12. package/dist/config/next-config.d.ts +19 -0
  13. package/dist/config/next-config.js +64 -1
  14. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
  15. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
  16. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
  17. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
  18. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
  19. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
  20. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
  21. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
  22. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
  23. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
  24. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
  25. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
  26. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
  27. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
  28. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
  29. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
  30. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
  31. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
  32. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
  33. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
  34. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
  35. package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
  36. package/dist/entries/app-rsc-entry.js +17 -48
  37. package/dist/entries/app-rsc-manifest.js +3 -4
  38. package/dist/entries/app-ssr-entry.js +1 -0
  39. package/dist/entries/pages-server-entry.js +33 -8
  40. package/dist/index.js +83 -70
  41. package/dist/init-cloudflare.d.ts +1 -3
  42. package/dist/init-cloudflare.js +10 -48
  43. package/dist/init-platform.d.ts +2 -0
  44. package/dist/init-platform.js +4 -0
  45. package/dist/plugins/extensionless-dynamic-import.js +6 -2
  46. package/dist/plugins/next-intl-catalog.d.ts +12 -0
  47. package/dist/plugins/next-intl-catalog.js +85 -0
  48. package/dist/plugins/pages-node-externals.d.ts +1 -0
  49. package/dist/plugins/pages-node-externals.js +1 -1
  50. package/dist/plugins/use-cache-callable.d.ts +1 -1
  51. package/dist/plugins/use-cache-callable.js +136 -94
  52. package/dist/routing/app-route-graph.d.ts +6 -0
  53. package/dist/routing/app-route-graph.js +9 -1
  54. package/dist/server/api-handler.js +19 -4
  55. package/dist/server/app-bfcache-identity.js +1 -1
  56. package/dist/server/app-browser-entry.js +79 -63
  57. package/dist/server/app-browser-history-controller.d.ts +5 -4
  58. package/dist/server/app-browser-history-controller.js +93 -15
  59. package/dist/server/app-browser-navigation-controller.d.ts +2 -2
  60. package/dist/server/app-browser-navigation-controller.js +1 -2
  61. package/dist/server/app-browser-rsc-redirect.js +4 -4
  62. package/dist/server/app-browser-server-action-client.d.ts +2 -0
  63. package/dist/server/app-browser-server-action-client.js +4 -3
  64. package/dist/server/app-browser-state.d.ts +2 -4
  65. package/dist/server/app-browser-state.js +9 -4
  66. package/dist/server/app-browser-supplemental-refresh.js +16 -1
  67. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  68. package/dist/server/app-browser-visible-commit.js +2 -12
  69. package/dist/server/app-elements-wire.d.ts +6 -38
  70. package/dist/server/app-elements-wire.js +4 -41
  71. package/dist/server/app-elements.d.ts +2 -2
  72. package/dist/server/app-elements.js +2 -2
  73. package/dist/server/app-history-state.d.ts +2 -2
  74. package/dist/server/app-history-state.js +5 -2
  75. package/dist/server/app-mounted-layouts.d.ts +21 -0
  76. package/dist/server/app-mounted-layouts.js +67 -0
  77. package/dist/server/app-optimistic-routing.d.ts +19 -1
  78. package/dist/server/app-optimistic-routing.js +42 -2
  79. package/dist/server/app-page-boundary-render.js +7 -6
  80. package/dist/server/app-page-boundary.js +2 -2
  81. package/dist/server/app-page-cache-finalizer.d.ts +12 -1
  82. package/dist/server/app-page-cache-finalizer.js +70 -29
  83. package/dist/server/app-page-cache.d.ts +13 -1
  84. package/dist/server/app-page-cache.js +31 -9
  85. package/dist/server/app-page-dispatch.d.ts +5 -10
  86. package/dist/server/app-page-dispatch.js +84 -154
  87. package/dist/server/app-page-element-builder.d.ts +2 -2
  88. package/dist/server/app-page-element-builder.js +10 -9
  89. package/dist/server/app-page-execution.d.ts +17 -52
  90. package/dist/server/app-page-execution.js +99 -95
  91. package/dist/server/app-page-head.d.ts +13 -0
  92. package/dist/server/app-page-head.js +44 -16
  93. package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
  94. package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
  95. package/dist/server/app-page-layout-gate.d.ts +35 -0
  96. package/dist/server/app-page-layout-gate.js +50 -0
  97. package/dist/server/app-page-params.d.ts +0 -1
  98. package/dist/server/app-page-params.js +1 -14
  99. package/dist/server/app-page-probe.d.ts +3 -21
  100. package/dist/server/app-page-probe.js +4 -37
  101. package/dist/server/app-page-render.d.ts +2 -12
  102. package/dist/server/app-page-render.js +89 -220
  103. package/dist/server/app-page-request.d.ts +1 -3
  104. package/dist/server/app-page-request.js +1 -1
  105. package/dist/server/app-page-response.js +3 -3
  106. package/dist/server/app-page-route-wiring.d.ts +13 -6
  107. package/dist/server/app-page-route-wiring.js +67 -61
  108. package/dist/server/app-page-rsc-render-status.d.ts +27 -1
  109. package/dist/server/app-page-rsc-render-status.js +121 -13
  110. package/dist/server/app-page-stream.d.ts +2 -0
  111. package/dist/server/app-page-stream.js +2 -2
  112. package/dist/server/app-pages-bridge.d.ts +4 -0
  113. package/dist/server/app-pages-bridge.js +7 -3
  114. package/dist/server/app-render-dependency.d.ts +11 -4
  115. package/dist/server/app-render-dependency.js +86 -38
  116. package/dist/server/app-request-stage-dispatch.js +1 -1
  117. package/dist/server/app-route-handler-cache.js +2 -2
  118. package/dist/server/app-route-handler-dispatch.js +14 -9
  119. package/dist/server/app-route-handler-execution.js +8 -3
  120. package/dist/server/app-route-handler-policy.d.ts +1 -1
  121. package/dist/server/app-route-handler-policy.js +3 -3
  122. package/dist/server/app-route-handler-response.js +1 -1
  123. package/dist/server/app-route-handler-runtime.js +17 -4
  124. package/dist/server/app-rsc-cache-busting.d.ts +2 -2
  125. package/dist/server/app-rsc-cache-busting.js +4 -4
  126. package/dist/server/app-rsc-error-handler.d.ts +2 -1
  127. package/dist/server/app-rsc-error-handler.js +9 -1
  128. package/dist/server/app-rsc-errors.d.ts +8 -0
  129. package/dist/server/app-rsc-errors.js +8 -1
  130. package/dist/server/app-rsc-handler.d.ts +5 -5
  131. package/dist/server/app-rsc-handler.js +30 -24
  132. package/dist/server/app-rsc-request-normalization.d.ts +0 -4
  133. package/dist/server/app-rsc-request-normalization.js +1 -4
  134. package/dist/server/app-rsc-response-finalizer.js +2 -2
  135. package/dist/server/app-rsc-response-stage.js +5 -3
  136. package/dist/server/app-server-action-execution.d.ts +3 -1
  137. package/dist/server/app-server-action-execution.js +7 -4
  138. package/dist/server/app-ssr-entry.d.ts +2 -0
  139. package/dist/server/app-ssr-entry.js +9 -8
  140. package/dist/server/app-ssr-stream.js +1 -1
  141. package/dist/server/app-visited-response-cache.d.ts +36 -1
  142. package/dist/server/app-visited-response-cache.js +46 -5
  143. package/dist/server/app-worker-stages.d.ts +25 -3
  144. package/dist/server/app-worker-stages.js +45 -6
  145. package/dist/server/artifact-compatibility.d.ts +0 -1
  146. package/dist/server/artifact-compatibility.js +1 -10
  147. package/dist/server/cache-proof.d.ts +1 -115
  148. package/dist/server/cache-proof.js +1 -544
  149. package/dist/server/cacheability-request.js +13 -8
  150. package/dist/server/dev-server.js +4 -3
  151. package/dist/server/headers.d.ts +6 -3
  152. package/dist/server/headers.js +9 -5
  153. package/dist/server/isr-cache.d.ts +8 -2
  154. package/dist/server/isr-cache.js +26 -1
  155. package/dist/server/metadata-route-response.js +32 -15
  156. package/dist/server/multi-stage.d.ts +52 -11
  157. package/dist/server/multi-stage.js +13 -1
  158. package/dist/server/navigation-planner.js +1 -1
  159. package/dist/server/pages-api-route.js +28 -19
  160. package/dist/server/pages-media-type.d.ts +21 -1
  161. package/dist/server/pages-media-type.js +69 -5
  162. package/dist/server/pages-node-compat.js +52 -27
  163. package/dist/server/pages-page-handler.js +11 -20
  164. package/dist/server/pages-request-pipeline.d.ts +8 -0
  165. package/dist/server/pages-request-pipeline.js +2 -2
  166. package/dist/server/pages-request-stage-entry.js +14 -12
  167. package/dist/server/pages-response-stage-entry.js +9 -3
  168. package/dist/server/prod-server.js +5 -1
  169. package/dist/server/request-pipeline.d.ts +6 -0
  170. package/dist/server/request-pipeline.js +21 -1
  171. package/dist/server/shared-cache-identity.d.ts +23 -0
  172. package/dist/server/shared-cache-identity.js +36 -0
  173. package/dist/server/worker-stages.d.ts +16 -3
  174. package/dist/server/worker-stages.js +23 -4
  175. package/dist/shims/cache-handler.js +2 -2
  176. package/dist/shims/cache-request-state.d.ts +17 -20
  177. package/dist/shims/cache-request-state.js +16 -21
  178. package/dist/shims/cache-runtime.js +27 -11
  179. package/dist/shims/cache.d.ts +8 -7
  180. package/dist/shims/cache.js +17 -19
  181. package/dist/shims/cacheability-classification.d.ts +2 -0
  182. package/dist/shims/cdn-cache.d.ts +22 -5
  183. package/dist/shims/client-page-root.js +2 -2
  184. package/dist/shims/dynamic.js +9 -6
  185. package/dist/shims/error-boundary.js +2 -2
  186. package/dist/shims/fetch-cache-state.d.ts +5 -1
  187. package/dist/shims/fetch-cache-state.js +1 -3
  188. package/dist/shims/fetch-cache.d.ts +2 -1
  189. package/dist/shims/fetch-cache.js +34 -24
  190. package/dist/shims/form.js +2 -2
  191. package/dist/shims/headers.d.ts +8 -23
  192. package/dist/shims/headers.js +17 -67
  193. package/dist/shims/internal/navigation-untracked.js +1 -1
  194. package/dist/shims/link.js +3 -1
  195. package/dist/shims/metadata.d.ts +23 -21
  196. package/dist/shims/metadata.js +62 -24
  197. package/dist/shims/navigation-server.js +1 -1
  198. package/dist/shims/navigation.d.ts +74 -7
  199. package/dist/shims/navigation.js +183 -29
  200. package/dist/shims/navigation.react-server.js +2 -2
  201. package/dist/shims/request-state-types.d.ts +2 -2
  202. package/dist/shims/slot.d.ts +12 -0
  203. package/dist/shims/slot.js +37 -9
  204. package/dist/shims/unified-request-context.d.ts +1 -1
  205. package/dist/shims/unified-request-context.js +2 -3
  206. package/dist/utils/cache-control-metadata.d.ts +5 -0
  207. package/dist/utils/cache-control-metadata.js +9 -1
  208. package/dist/utils/project.d.ts +2 -2
  209. package/dist/utils/project.js +3 -16
  210. package/dist/utils/regex.d.ts +5 -0
  211. package/dist/utils/regex.js +11 -1
  212. package/dist/utils/text-stream.d.ts +10 -5
  213. package/dist/utils/text-stream.js +6 -6
  214. package/package.json +2 -1
  215. package/dist/build/layout-classification-types.d.ts +0 -60
  216. package/dist/build/layout-classification-types.js +0 -1
  217. package/dist/build/layout-classification.d.ts +0 -62
  218. package/dist/build/layout-classification.js +0 -98
  219. package/dist/build/route-classification-injector.d.ts +0 -33
  220. package/dist/build/route-classification-injector.js +0 -59
  221. package/dist/build/route-classification-manifest.d.ts +0 -54
  222. package/dist/build/route-classification-manifest.js +0 -143
  223. package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
  224. package/dist/server/app-browser-client-reuse-manifest.js +0 -101
  225. package/dist/server/app-layout-param-observation.d.ts +0 -42
  226. package/dist/server/app-layout-param-observation.js +0 -168
  227. package/dist/server/client-reuse-manifest.d.ts +0 -103
  228. package/dist/server/client-reuse-manifest.js +0 -209
  229. package/dist/server/skip-cache-proof.d.ts +0 -60
  230. package/dist/server/skip-cache-proof.js +0 -168
  231. package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
  232. package/dist/server/static-layout-client-reuse-proof.js +0 -33
  233. package/dist/utils/sorted-array.d.ts +0 -8
  234. package/dist/utils/sorted-array.js +0 -20
@@ -7,13 +7,14 @@ import { importModule, reportRequestError } from "./instrumentation.js";
7
7
  import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
8
8
  import { tracePagesApiHandler } from "./pages-execution-tracing.js";
9
9
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT, resolveBodyParserConfig } from "./pages-body-parser-config.js";
10
- import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
10
+ import { PagesBodyParseError, createPagesBodyDecoder, isJsonMediaType } from "./pages-media-type.js";
11
11
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
12
12
  import { attachPagesPreviewApi, attachPagesRequestCookies } from "./pages-node-compat.js";
13
13
  import { finalizeEdgeApiResponse, isEdgeApiRuntime } from "./edge-api-runtime.js";
14
14
  import { signalFromNodeResponse } from "./node-response-signal.js";
15
15
  import { Buffer } from "node:buffer";
16
16
  import { decode } from "node:querystring";
17
+ import { Stream } from "node:stream";
17
18
  //#region src/server/api-handler.ts
18
19
  /**
19
20
  * Default request body size (1 MB). Matches Next.js default bodyParser sizeLimit.
@@ -32,6 +33,8 @@ const MAX_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;
32
33
  * HMAC signature verification).
33
34
  */
34
35
  async function parseBody(req, sizeLimit = MAX_BODY_SIZE) {
36
+ const { mediaType, decoder } = await createPagesBodyDecoder(req.headers["content-type"]);
37
+ if (req.destroyed) throw req.errored ?? /* @__PURE__ */ new Error("Request aborted");
35
38
  return new Promise((resolve, reject) => {
36
39
  const chunks = [];
37
40
  let totalSize = 0;
@@ -55,10 +58,10 @@ async function parseBody(req, sizeLimit = MAX_BODY_SIZE) {
55
58
  req.on("end", () => {
56
59
  if (settled) return;
57
60
  settled = true;
58
- const raw = Buffer.concat(chunks).toString("utf-8");
59
- const mediaType = getMediaType(req.headers["content-type"]);
61
+ const body = Buffer.concat(chunks);
62
+ const raw = decoder.decode(body);
60
63
  if (!raw) {
61
- resolve(isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode(raw) : void 0);
64
+ resolve(isJsonMediaType(mediaType) ? {} : mediaType === "application/x-www-form-urlencoded" ? decode(raw) : body.length > 0 ? raw : void 0);
62
65
  return;
63
66
  }
64
67
  if (isJsonMediaType(mediaType)) try {
@@ -188,6 +191,18 @@ function enhanceApiObjects(req, res, query, body, trustedRevalidateOrigin, allow
188
191
  this.end(JSON.stringify(data));
189
192
  },
190
193
  send(data) {
194
+ if (this.statusCode === 204 || this.statusCode === 304) {
195
+ this.removeHeader("Content-Type");
196
+ this.removeHeader("Content-Length");
197
+ this.removeHeader("Transfer-Encoding");
198
+ this.end();
199
+ return;
200
+ }
201
+ if (data instanceof Stream) {
202
+ if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "application/octet-stream");
203
+ data.pipe(this);
204
+ return;
205
+ }
191
206
  if (Buffer.isBuffer(data)) {
192
207
  if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "application/octet-stream");
193
208
  this.setHeader("Content-Length", String(data.length));
@@ -1,7 +1,7 @@
1
1
  import { AppElementsWire } from "./app-elements-wire.js";
2
2
  import "./app-elements.js";
3
- import { isNestedBfcacheSlotSegmentIdFor } from "./bfcache-identity.js";
4
3
  import { isBfcacheSegmentId } from "./app-bfcache-id.js";
4
+ import { isNestedBfcacheSlotSegmentIdFor } from "./bfcache-identity.js";
5
5
  //#region src/server/app-bfcache-identity.ts
6
6
  let nextBfcacheId = 0;
7
7
  function rememberBfcacheId(value) {
@@ -1,35 +1,33 @@
1
1
  import { addBasePathToPathname, stripBasePath } from "../utils/base-path.js";
2
- import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER } from "./headers.js";
2
+ import { VINEXT_MOUNTED_LAYOUTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER } from "./headers.js";
3
3
  import { splitPathnameForRouteMatch } from "../routing/utils.js";
4
4
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
5
5
  import { matchRoutePattern } from "../routing/route-pattern.js";
6
6
  import { installWindowNext, setWindowNextInternalSourcePage } from "../client/window-next.js";
7
7
  import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
8
- import { AppElementsWire } from "./app-elements-wire.js";
9
- import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
10
- import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
11
- import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
12
- import DefaultGlobalError from "../shims/default-global-error.js";
13
- import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners } from "../client/app-nav-failure-handler.js";
14
- import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
15
- import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
16
- import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
17
- import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, setAppElementsRenderedSearch } from "../shims/slot.js";
18
8
  import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, formatRscRequestPath, isRscCompatibilityIdCompatible } from "./app-rsc-cache-busting.js";
9
+ import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners } from "../client/app-nav-failure-handler.js";
19
10
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
20
11
  import "../client/instrumentation-client.js";
21
12
  import { createNavigationRuntimeRouteManifestLoader, getNavigationRuntime, loadNavigationRuntimeRouteManifest, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
13
+ import { AppElementsWire } from "./app-elements-wire.js";
14
+ import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
22
15
  import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
23
16
  import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, resolveServerActionOperationLane } from "./app-browser-action-result.js";
24
- import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
25
17
  import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
26
18
  import { isExternalHistoryState, readHistoryStateActiveRoutePaths, readHistoryStatePreviousNextUrl, resolveActiveRoutePaths } from "./app-history-state.js";
27
19
  import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
28
20
  import { stripRscCompletionMetadataResponse } from "./rsc-completion-metadata.js";
29
21
  import { blockDangerousStreamedRscRedirect } from "./app-browser-rsc-redirect.js";
30
22
  import { navigationPlanner } from "./navigation-planner.js";
31
- import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
23
+ import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
24
+ import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
25
+ import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
26
+ import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
27
+ import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
32
28
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
29
+ import { createMountedLayoutsHeader, holdsSkippedLayouts } from "./app-mounted-layouts.js";
30
+ import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, setAppElementsRenderedSearch } from "../shims/slot.js";
33
31
  import { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl } from "./app-browser-state.js";
34
32
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, navigateDocumentDirectly } from "./app-browser-navigation-controller.js";
35
33
  import { createAppRouteTree } from "./app-route-tree.js";
@@ -38,17 +36,19 @@ import { createSupplementalRefreshCoordinator, mergeRefreshedParallelSlot, requi
38
36
  import { createAppBrowserNavigationAbortCoordinator } from "./app-browser-navigation-abort.js";
39
37
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition, resolveFetchedHydrationLocation } from "./app-browser-hydration.js";
40
38
  import { AppBrowserHistoryController } from "./app-browser-history-controller.js";
41
- import { createVisitedResponseCacheEntry, deleteAllVisitedResponseCacheEntries, deleteInvalidatedHistoryRestoreEntries, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, hasNavigationResponseHistoryLifetime, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
39
+ import { createVisitedResponseCacheEntry, deleteAllVisitedResponseCacheEntries, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, findVisitedResponseForFullPrefetch, hasNavigationResponseHistoryLifetime, isVisitedResponseCacheEntryFresh, revokeHistoryRestoreNavigationReuse } from "./app-visited-response-cache.js";
42
40
  import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition, shouldCommitPopstateUrlWithoutNavigation } from "./app-browser-popstate.js";
41
+ import DefaultGlobalError from "../shims/default-global-error.js";
42
+ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
43
43
  import { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, createProdOnRecoverableError } from "./app-browser-error.js";
44
44
  import { createHydrationCachePublication } from "./app-hydration-cache-publication.js";
45
45
  import { peekSettledPrefetchResponseForNavigation, prepareConsumedPrefetchResponseForPublication, preserveCommittedPrefetchExpiry, resolvePrefetchNavigationResponseUrl } from "./app-browser-prefetch-response.js";
46
- import { canCommitOptimisticRouteTemplate, createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, keepOptimisticStreamingMetadata, resolveOptimisticNavigationParamsForHref, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
46
+ import { canCommitOptimisticRouteTemplate, createOptimisticRouteTemplate, createOptimisticRouteTemplateStore, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, keepOptimisticStreamingMetadata, resolveOptimisticNavigationParamsForHref, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
47
47
  import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
48
48
  import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
49
- import { flushSync } from "react-dom";
50
49
  import { createRoot, hydrateRoot } from "react-dom/client";
51
50
  import { createFromFetch, createFromReadableStream, setServerCallback } from "@vitejs/plugin-rsc/browser";
51
+ import { flushSync } from "react-dom";
52
52
  import { hasServerActions, loadServerActionClient } from "virtual:vinext-app-capabilities";
53
53
  //#region src/server/app-browser-entry.ts
54
54
  const HAS_CLIENT_REWRITES = process.env.__VINEXT_HAS_CLIENT_REWRITES !== "false";
@@ -80,9 +80,7 @@ function setClientRscCompatibilityId(compatibilityId) {
80
80
  if (IS_STATIC_EXPORT || !compatibilityId) return;
81
81
  clientRscCompatibilityId = compatibilityId;
82
82
  }
83
- const optimisticRouteTemplates = /* @__PURE__ */ new Map();
84
- const optimisticRouteTemplateSources = /* @__PURE__ */ new Set();
85
- const optimisticRouteTemplateLearning = /* @__PURE__ */ new Map();
83
+ const optimisticRouteTemplates = createOptimisticRouteTemplateStore();
86
84
  function claimInitialAppRouterBootstrap() {
87
85
  if (window.__VINEXT_RSC_ROOT__ || window.__VINEXT_RSC_BOOTSTRAP_STATE__) return false;
88
86
  window.__VINEXT_RSC_BOOTSTRAP_STATE__ = "starting";
@@ -114,8 +112,8 @@ const historyController = new AppBrowserHistoryController({
114
112
  maxHistoryStateSnapshots: 50,
115
113
  readHistoryState: () => window.history.state,
116
114
  readCurrentHref: () => window.location.href,
117
- pushHistoryState: (state, href) => pushHistoryStateWithoutNotify(state, "", href),
118
- replaceHistoryState: (state, href) => replaceHistoryStateWithoutNotify(state, "", href),
115
+ pushHistoryState: (state, href, land) => pushHistoryStateWithoutNotify(state, "", href, land),
116
+ replaceHistoryState: (state, href, land) => replaceHistoryStateWithoutNotify(state, "", href, land),
119
117
  readVisibleNavigationMetadata: () => {
120
118
  if (!hasBrowserRouterState()) return null;
121
119
  const routerState = getBrowserRouterState();
@@ -223,7 +221,7 @@ function restoreHistoryStateSnapshot(historyState, navId, onApprovedBeforeCommit
223
221
  });
224
222
  if (!restored) return false;
225
223
  clientNavigationCacheGeneration += 1;
226
- deleteInvalidatedHistoryRestoreEntries(visitedResponseCache);
224
+ revokeHistoryRestoreNavigationReuse(visitedResponseCache);
227
225
  disableNavigationResponsePrefetchCacheReuse();
228
226
  commitClientNavigationState(navId, { releaseSnapshot: false });
229
227
  return true;
@@ -250,17 +248,23 @@ function stageClientParams(params) {
250
248
  }
251
249
  function clearVisitedResponseCache() {
252
250
  visitedResponseCache.clear();
251
+ invalidateVisitedResponsePrefetches();
253
252
  }
254
- function clearPrefetchState() {
255
- invalidatePrefetchCache();
253
+ function clearPrefetchState(options) {
254
+ invalidatePrefetchCache(options);
256
255
  optimisticRouteTemplates.clear();
257
- optimisticRouteTemplateSources.clear();
258
- optimisticRouteTemplateLearning.clear();
259
256
  }
260
- function clearClientNavigationCaches() {
257
+ function clearClientNavigationCaches(options) {
258
+ clientNavigationCacheGeneration += 1;
259
+ clearVisitedResponseCache();
260
+ clearPrefetchState(options);
261
+ historyController.invalidateRestorableClientState();
262
+ }
263
+ function clearDynamicClientNavigationCaches() {
261
264
  clientNavigationCacheGeneration += 1;
262
265
  clearVisitedResponseCache();
263
- clearPrefetchState();
266
+ invalidateDynamicPrefetchCache();
267
+ optimisticRouteTemplates.clear();
264
268
  historyController.invalidateRestorableClientState();
265
269
  }
266
270
  function getMatchedUrlPathname(matchedUrl) {
@@ -343,10 +347,10 @@ function parsePrefetchCacheKey(cacheKey) {
343
347
  }
344
348
  async function learnOptimisticRouteTemplateFromPrefetch(options) {
345
349
  const source = parsePrefetchCacheKey(options.cacheKey);
346
- if (source.interceptionContext !== options.interceptionContext) return false;
347
- if (resolvePrefetchCacheEntryMountedSlotsHeader(options.entry) !== options.mountedSlotsHeader) return false;
348
- if (options.interceptionContext !== null) return false;
349
- if (!isRscResponseCompatible(options.entry.snapshot.compatibilityIdHeader)) return false;
350
+ if (source.interceptionContext !== options.interceptionContext) return null;
351
+ if (resolvePrefetchCacheEntryMountedSlotsHeader(options.entry) !== options.mountedSlotsHeader) return null;
352
+ if (options.interceptionContext !== null) return null;
353
+ if (!isRscResponseCompatible(options.entry.snapshot.compatibilityIdHeader)) return null;
350
354
  const elements = await decodeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(options.entry.snapshot))));
351
355
  const template = createOptimisticRouteTemplate({
352
356
  allowLoadingShell: options.entry.optimisticRouteShell === true,
@@ -357,40 +361,36 @@ async function learnOptimisticRouteTemplateFromPrefetch(options) {
357
361
  mountedSlotsHeader: options.mountedSlotsHeader,
358
362
  routeManifest: options.routeManifest
359
363
  });
360
- if (template === null) return false;
361
- optimisticRouteTemplates.set(getOptimisticRouteTemplateKey({
362
- interceptionContext: options.interceptionContext,
363
- mountedSlotsHeader: options.mountedSlotsHeader,
364
- routeId: template.routeId
365
- }), template);
366
- return true;
364
+ if (template === null) return null;
365
+ return {
366
+ key: getOptimisticRouteTemplateKey({
367
+ interceptionContext: options.interceptionContext,
368
+ mountedSlotsHeader: options.mountedSlotsHeader,
369
+ routeId: template.routeId
370
+ }),
371
+ template
372
+ };
367
373
  }
368
374
  async function learnOptimisticRouteTemplatesFromPrefetchCache(options) {
369
- if (options.routeManifest === null) return;
370
- const learning = [...optimisticRouteTemplateLearning.values()];
375
+ const { routeManifest } = options;
376
+ if (routeManifest === null) return;
377
+ const learning = optimisticRouteTemplates.pendingLearning();
371
378
  for (const [cacheKey, entry] of getPrefetchCache()) {
372
379
  const sourceKey = getOptimisticPrefetchSourceKey({
373
380
  cacheKey,
374
381
  interceptionContext: options.interceptionContext,
375
382
  mountedSlotsHeader: options.mountedSlotsHeader
376
383
  });
377
- if (optimisticRouteTemplateSources.has(sourceKey)) continue;
378
- if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
384
+ if (optimisticRouteTemplates.hasSource(sourceKey)) continue;
379
385
  if (!isSettledPrefetchCacheEntry(entry)) continue;
380
386
  if (entry.prefetchKind === "route-tree") continue;
381
- const promise = learnOptimisticRouteTemplateFromPrefetch({
387
+ learning.push(optimisticRouteTemplates.learn(sourceKey, () => learnOptimisticRouteTemplateFromPrefetch({
382
388
  cacheKey,
383
389
  entry,
384
390
  interceptionContext: options.interceptionContext,
385
391
  mountedSlotsHeader: options.mountedSlotsHeader,
386
- routeManifest: options.routeManifest
387
- }).then((learned) => {
388
- if (learned) optimisticRouteTemplateSources.add(sourceKey);
389
- }).finally(() => {
390
- optimisticRouteTemplateLearning.delete(sourceKey);
391
- });
392
- optimisticRouteTemplateLearning.set(sourceKey, promise);
393
- learning.push(promise);
392
+ routeManifest
393
+ })));
394
394
  }
395
395
  if (learning.length === 0) return;
396
396
  await Promise.allSettled(learning);
@@ -533,7 +533,7 @@ function evictVisitedResponseCacheIfNeeded() {
533
533
  function readVisitedResponseCacheCandidate(rscUrl, interceptionContext, mountedSlotsHeader, navigationKind) {
534
534
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
535
535
  const match = findVisitedResponseCacheEntry(visitedResponseCache, rscUrl, interceptionContext);
536
- if (!match) return {
536
+ if (!match || match.entry.navigationReuseRevoked) return {
537
537
  cacheKey,
538
538
  entry: null,
539
539
  facts: {
@@ -568,13 +568,14 @@ function applyVisitedResponseCacheCandidateDecision(candidate, decision) {
568
568
  function deleteVisitedResponse(rscUrl, interceptionContext) {
569
569
  deleteVisitedResponseCacheEntry(visitedResponseCache, rscUrl, interceptionContext);
570
570
  }
571
- function storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, params, prefetchFallbackTtlMs = DYNAMIC_NAVIGATION_CACHE_TTL, requestMountedSlotsHeader = snapshot.mountedSlotsHeader ?? null, elements, seedPrefetchCache = true, prefetchSnapshot = snapshot, reuseAfterHistoryRestore = false) {
571
+ function storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, params, prefetchFallbackTtlMs = DYNAMIC_NAVIGATION_CACHE_TTL, requestMountedSlotsHeader = snapshot.mountedSlotsHeader ?? null, elements, seedPrefetchCache = true, prefetchSnapshot = snapshot, reuseAfterHistoryRestore = false, fromHydration = false) {
572
572
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
573
573
  deleteAllVisitedResponseCacheEntries(visitedResponseCache, rscUrl, interceptionContext);
574
574
  evictVisitedResponseCacheIfNeeded();
575
575
  const entry = createVisitedResponseCacheEntry({
576
576
  fallbackTtlMs: prefetchFallbackTtlMs,
577
577
  elements,
578
+ fromHydration,
578
579
  now: Date.now(),
579
580
  mountedSlotsHeader: requestMountedSlotsHeader,
580
581
  params,
@@ -699,7 +700,6 @@ function BrowserRoot({ hydrationCachePublication, initialElements, initialNaviga
699
700
  interception: initialMetadata.interception,
700
701
  interceptionContext: initialMetadata.interceptionContext,
701
702
  layoutIds: initialMetadata.layoutIds,
702
- layoutFlags: initialMetadata.layoutFlags,
703
703
  navigationSnapshot: initialNavigationSnapshot,
704
704
  previousNextUrl: null,
705
705
  renderId: 0,
@@ -966,6 +966,7 @@ function registerServerActionCallback() {
966
966
  return loadServerActionClient().then(({ invokeClientServerAction }) => invokeClientServerAction(id, args, actionInitiation, {
967
967
  basePath: __basePath,
968
968
  clearClientNavigationCaches,
969
+ clearDynamicClientNavigationCaches,
969
970
  clientRscCompatibilityId,
970
971
  commitSameUrlNavigatePayload,
971
972
  navigationPlanner,
@@ -1059,7 +1060,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1059
1060
  const fallbackTtlMs = initialRscBootstrap?.initialCacheKind === "static" ? PREFETCH_CACHE_TTL : DYNAMIC_NAVIGATION_CACHE_TTL;
1060
1061
  hydrationCachePublication.publish(() => {
1061
1062
  if (cacheGeneration !== clientNavigationCacheGeneration) return () => {};
1062
- return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader, elements, false, snapshot, initialRscBootstrap?.initialCacheKind === "static" || metadata.interceptionContext !== null);
1063
+ return storeVisitedResponseSnapshot(rscUrl, metadata.interceptionContext, snapshot, initialParams, fallbackTtlMs, mountedSlotsHeader, elements, false, snapshot, initialRscBootstrap?.initialCacheKind === "static" || metadata.interceptionContext !== null, true);
1063
1064
  });
1064
1065
  }).catch(() => {});
1065
1066
  historyController.writeBootstrapHistoryMetadata();
@@ -1151,6 +1152,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1151
1152
  };
1152
1153
  let restoredBfcacheIds = navigationKind === "traverse" ? historyController.readCurrentBfcacheVersionHistoryIds(activeTraversalIntent?.historyState ?? window.history.state) : null;
1153
1154
  const reuseCurrentBfcacheIds = navigationKind !== "traverse" || !historyController.isCacheInvalidationGuarded() && historyController.isCurrentBfcacheVersion(activeTraversalIntent?.historyState ?? window.history.state);
1155
+ const releaseNavigationInFlight = trackAppRouterNavigationInFlight();
1154
1156
  try {
1155
1157
  const shouldUsePendingRouterState = programmaticTransition;
1156
1158
  if (hasBrowserRouterState()) {
@@ -1171,6 +1173,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1171
1173
  }
1172
1174
  const navigationInitiationState = getBrowserRouterState();
1173
1175
  const mountedSlotsHeader = getMountedSlotIdsHeader(navigationInitiationState.elements);
1176
+ let mountedLayoutsHeader = navigationKind === "navigate" ? createMountedLayoutsHeader(navigationInitiationState.elements, navigationInitiationState.layoutIds) : null;
1174
1177
  while (true) {
1175
1178
  const url = new URL(currentHref, window.location.origin);
1176
1179
  const requestState = getRequestState(navigationKind, url.pathname, currentPrevNextUrl, activeTraversalIntent?.historyState);
@@ -1380,7 +1383,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1380
1383
  interceptionContext: requestInterceptionContext,
1381
1384
  mountedSlotsHeader,
1382
1385
  routeManifest,
1383
- templates: optimisticRouteTemplates
1386
+ templates: optimisticRouteTemplates.templates
1384
1387
  });
1385
1388
  if (optimisticPayload !== null && canCommitOptimisticRouteTemplate({
1386
1389
  currentElements: navigationInitiationState.elements,
@@ -1419,13 +1422,16 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1419
1422
  }
1420
1423
  }
1421
1424
  }
1425
+ let sentMountedLayouts = false;
1422
1426
  if (!navResponse) {
1423
- if (navigationKind === "navigate") {
1424
- const clientReuseManifestHeader = createClientReuseManifestHeaderFromVisibleAppState(navigationInitiationState);
1425
- if (clientReuseManifestHeader !== null) requestHeaders.set(VINEXT_CLIENT_REUSE_MANIFEST_HEADER, clientReuseManifestHeader);
1427
+ let liveRequestHeaders = requestHeaders;
1428
+ if (mountedLayoutsHeader !== null && requestInterceptionContext === null) {
1429
+ liveRequestHeaders = new Headers(requestHeaders);
1430
+ liveRequestHeaders.set(VINEXT_MOUNTED_LAYOUTS_HEADER, mountedLayoutsHeader);
1431
+ sentMountedLayouts = true;
1426
1432
  }
1427
1433
  navResponse = await fetch(rscUrl, {
1428
- headers: requestHeaders,
1434
+ headers: liveRequestHeaders,
1429
1435
  credentials: "include",
1430
1436
  priority: "auto",
1431
1437
  signal: navigationAbortHandle.signal
@@ -1508,6 +1514,15 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1508
1514
  navigationAbortHandle.release();
1509
1515
  }).then(requireCompleteSupplementalRefresh);
1510
1516
  }
1517
+ if (sentMountedLayouts) {
1518
+ const elements = await rscPayload;
1519
+ if (!browserNavigationController.isCurrentNavigation(navId)) return;
1520
+ if (!holdsSkippedLayouts(navigationInitiationState, elements) || !holdsSkippedLayouts(getBrowserRouterState(), elements)) {
1521
+ mountedLayoutsHeader = null;
1522
+ continue;
1523
+ }
1524
+ rscPayload = Promise.resolve(elements);
1525
+ }
1511
1526
  if (IS_STATIC_EXPORT) {
1512
1527
  const staticExportElements = await rscPayload;
1513
1528
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
@@ -1584,13 +1599,12 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1584
1599
  const state = committedState;
1585
1600
  const committedElements = {
1586
1601
  ...state.elements,
1587
- [AppElementsWire.keys.layoutFlags]: state.layoutFlags,
1588
1602
  [AppElementsWire.keys.layoutIds]: state.layoutIds,
1589
1603
  [AppElementsWire.keys.skippedLayoutIds]: [],
1590
1604
  [AppElementsWire.keys.slotBindings]: state.slotBindings
1591
1605
  };
1592
1606
  if (navigationCacheGeneration !== clientNavigationCacheGeneration) return;
1593
- storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, navParams, DYNAMIC_NAVIGATION_CACHE_TTL, mountedSlotsHeader, committedElements, true, prefetchSnapshot, interceptionContext !== null || hasNavigationResponseHistoryLifetime(snapshot));
1607
+ storeVisitedResponseSnapshot(rscUrl, interceptionContext, snapshot, navParams, DYNAMIC_NAVIGATION_CACHE_TTL, mountedSlotsHeader, committedElements, isCompleteAppPayloadMetadata(metadata), prefetchSnapshot, interceptionContext !== null || hasNavigationResponseHistoryLifetime(snapshot));
1594
1608
  }
1595
1609
  } catch {}
1596
1610
  return;
@@ -1603,9 +1617,11 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
1603
1617
  navigationAbortHandle.release();
1604
1618
  browserNavigationController.finalizeNavigation(navId, pendingRouterState);
1605
1619
  discardedServerActionRefreshScheduler.markNavigationSettled();
1620
+ releaseNavigationInFlight();
1606
1621
  if (startedHardNavigation) await waitForMpaNavigationRestore();
1607
1622
  }
1608
1623
  },
1624
+ readVisitedResponseForFullPrefetch: (rscUrls, interceptionContext, mountedSlotsHeader) => findVisitedResponseForFullPrefetch(visitedResponseCache, rscUrls, interceptionContext, mountedSlotsHeader),
1609
1625
  preparePrefetchResponse: (response) => {
1610
1626
  if (!isRscResponseCompatible(response.headers.get("X-Vinext-RSC-Compatibility-Id"))) return Promise.reject(/* @__PURE__ */ new Error("[vinext] Prefetched another deployment's payload"));
1611
1627
  return decodeAppElementsPromise(createFromFetch(Promise.resolve(response)));
@@ -1,3 +1,4 @@
1
+ import { RouterHistoryWriteLanding } from "../shims/navigation.js";
1
2
  import { BfcacheIdMap, HistoryTraversalIntent } from "./app-history-state.js";
2
3
  import { AppRouterState } from "./app-browser-state.js";
3
4
  import { HistoryUpdateMode } from "./app-browser-navigation-controller.js";
@@ -19,10 +20,10 @@ type AppBrowserHistoryControllerDeps = {
19
20
  readHistoryState: () => unknown;
20
21
  /** Reads `window.location.href`. Injected so the controller stays unit-testable. */
21
22
  readCurrentHref: () => string;
22
- /** Wraps `pushHistoryStateWithoutNotify(state, "", href)`. */
23
- pushHistoryState: (state: unknown, href: string) => void;
24
- /** Wraps `replaceHistoryStateWithoutNotify(state, "", href)`. */
25
- replaceHistoryState: (state: unknown, href?: string) => void;
23
+ /** Wraps `pushHistoryStateWithoutNotify(state, "", href, land)`. */
24
+ pushHistoryState: (state: unknown, href: string, land?: RouterHistoryWriteLanding) => void;
25
+ /** Wraps `replaceHistoryStateWithoutNotify(state, "", href, land)`. */
26
+ replaceHistoryState: (state: unknown, href?: string, land?: RouterHistoryWriteLanding) => void;
26
27
  readVisibleNavigationMetadata: () => VisibleNavigationMetadata | null;
27
28
  };
28
29
  /**
@@ -31,6 +31,7 @@ var AppBrowserHistoryController = class {
31
31
  #treeSnapshots = /* @__PURE__ */ new Map();
32
32
  #treeSnapshotClaimCounts = /* @__PURE__ */ new Map();
33
33
  #treeSnapshotClaimByHistoryIndex = /* @__PURE__ */ new Map();
34
+ #treeSnapshotIdPrefix = createDocumentTreeSnapshotIdPrefix();
34
35
  #readHistoryState;
35
36
  #readCurrentHref;
36
37
  #pushHistoryState;
@@ -41,6 +42,9 @@ var AppBrowserHistoryController = class {
41
42
  #currentTreeSnapshotId = null;
42
43
  #nextTreeSnapshotId = 0;
43
44
  #treeSnapshotIdPendingFreshState = null;
45
+ #historyIndicesAwaitingTreeSnapshot = /* @__PURE__ */ new Set();
46
+ #treeSnapshotPending = true;
47
+ #historyIndexAwaitingTreeClaim = null;
44
48
  constructor(deps) {
45
49
  this.#readHistoryState = deps.readHistoryState;
46
50
  this.#readCurrentHref = deps.readCurrentHref;
@@ -99,18 +103,29 @@ var AppBrowserHistoryController = class {
99
103
  const previousState = this.readCurrentTreeSnapshot();
100
104
  const previousOperation = previousState?.activeOperation;
101
105
  if (previousState && previousOperation?.navigationCommitKind === "detached" && state.activeOperation?.navigationCommitKind === "authoritative" && state.activeOperation.navigationId === previousOperation.navigationId) this.#restorableClientState.replaceHistoryStateSnapshots(previousState, state);
106
+ for (const historyIndex of this.#historyIndicesAwaitingTreeSnapshot) this.#restorableClientState.rememberHistoryStateSnapshot({
107
+ historyIndex,
108
+ state
109
+ });
110
+ this.#historyIndicesAwaitingTreeSnapshot.clear();
102
111
  this.#restorableClientState.rememberHistoryStateSnapshot({
103
112
  historyIndex: this.#currentHistoryTraversalIndex,
104
113
  state
105
114
  });
115
+ this.#treeSnapshotPending = false;
106
116
  const historyTreeSnapshotId = readHistoryStateTreeSnapshotId(this.#readHistoryState());
107
- const treeSnapshotId = historyTreeSnapshotId !== null && this.#treeSnapshots.has(historyTreeSnapshotId) && (historyTreeSnapshotId === this.#treeSnapshotIdPendingFreshState || this.#treeSnapshotClaimCounts.has(historyTreeSnapshotId)) ? historyTreeSnapshotId : this.#nextTreeSnapshotId++;
117
+ const treeSnapshotId = historyTreeSnapshotId !== null && this.#treeSnapshots.has(historyTreeSnapshotId) && (historyTreeSnapshotId === this.#treeSnapshotIdPendingFreshState || this.#treeSnapshotClaimCounts.has(historyTreeSnapshotId)) ? historyTreeSnapshotId : `${this.#treeSnapshotIdPrefix}:${this.#nextTreeSnapshotId++}`;
108
118
  this.#treeSnapshotIdPendingFreshState = null;
109
119
  const previousTreeSnapshotId = this.#currentTreeSnapshotId;
110
120
  this.#currentTreeSnapshotId = treeSnapshotId;
111
121
  this.#treeSnapshots.set(treeSnapshotId, state);
122
+ const claimingHistoryIndex = this.#historyIndexAwaitingTreeClaim;
123
+ this.#historyIndexAwaitingTreeClaim = null;
124
+ const claimsTree = claimingHistoryIndex !== null && claimingHistoryIndex === this.#currentHistoryTraversalIndex && claimingHistoryIndex === readHistoryStateTraversalIndex(this.#readHistoryState());
125
+ if (claimsTree) this.#claimTreeSnapshotAtHistoryIndex(claimingHistoryIndex, treeSnapshotId);
112
126
  if (previousTreeSnapshotId !== null && previousTreeSnapshotId !== treeSnapshotId && !this.#treeSnapshotClaimCounts.has(previousTreeSnapshotId)) this.#treeSnapshots.delete(previousTreeSnapshotId);
113
- if (historyTreeSnapshotId !== treeSnapshotId) this.#replaceHistoryState(createHistoryStateWithTreeSnapshotId(this.#readHistoryState(), treeSnapshotId));
127
+ if (claimsTree) this.#replaceHistoryState(createHistoryStateWithTreeSnapshotClaim(createHistoryStateWithTreeSnapshotId(this.#readHistoryState(), treeSnapshotId), true));
128
+ else if (historyTreeSnapshotId !== treeSnapshotId) this.#replaceHistoryState(createHistoryStateWithTreeSnapshotId(this.#readHistoryState(), treeSnapshotId));
114
129
  }
115
130
  /** The router state of the most recently committed render, if any. */
116
131
  readCurrentTreeSnapshot() {
@@ -125,7 +140,21 @@ var AppBrowserHistoryController = class {
125
140
  claimCurrentHistoryTreeSnapshot(historyUpdateMode, previousHistoryState) {
126
141
  let historyState = this.#readHistoryState();
127
142
  const treeSnapshotId = readHistoryStateTreeSnapshotId(historyState);
128
- if (treeSnapshotId === null || !this.#treeSnapshots.has(treeSnapshotId)) return;
143
+ if (treeSnapshotId === null || !this.#treeSnapshots.has(treeSnapshotId)) {
144
+ if (historyUpdateMode === "push") {
145
+ const previousHistoryIndex = readHistoryStateTraversalIndex(previousHistoryState);
146
+ if (previousHistoryIndex !== null && this.#treeSnapshotPending) this.#historyIndicesAwaitingTreeSnapshot.add(previousHistoryIndex);
147
+ this.#releaseForwardTreeSnapshotClaims();
148
+ const historyIndex = this.#nextHistoryTraversalIndex + 1;
149
+ this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(historyState, {
150
+ previousNextUrl: readHistoryStatePreviousNextUrl(historyState),
151
+ traversalIndex: historyIndex
152
+ }));
153
+ this.commitHistoryTraversalIndex(historyIndex);
154
+ this.#historyIndexAwaitingTreeClaim = this.#treeSnapshotPending ? historyIndex : null;
155
+ }
156
+ return;
157
+ }
129
158
  let historyIndex;
130
159
  if (historyUpdateMode === "push") {
131
160
  this.#releaseForwardTreeSnapshotClaims();
@@ -185,7 +214,6 @@ var AppBrowserHistoryController = class {
185
214
  if (treeSnapshotId !== this.#currentTreeSnapshotId) this.#treeSnapshots.delete(treeSnapshotId);
186
215
  }
187
216
  commitHashOnlyNavigation(href, historyUpdateMode, scroll) {
188
- if (historyUpdateMode === "push") this.#releaseForwardTreeSnapshotClaims();
189
217
  const navigationHistoryIndex = this.allocateNavigationHistoryTraversalIndex(historyUpdateMode);
190
218
  const historyState = this.#readHistoryState();
191
219
  const visible = this.#readVisibleNavigationMetadata();
@@ -199,11 +227,59 @@ var AppBrowserHistoryController = class {
199
227
  previousNextUrl,
200
228
  traversalIndex: navigationHistoryIndex
201
229
  }), true);
202
- if (historyUpdateMode === "replace") this.#replaceHistoryState(nextHistoryState, href);
203
- else this.#pushHistoryState(nextHistoryState, href);
230
+ const historyIndex = this.#writeNavigationHistoryState(historyUpdateMode, nextHistoryState, href, navigationHistoryIndex, false);
204
231
  const treeSnapshotId = readHistoryStateTreeSnapshotId(nextHistoryState);
205
- if (navigationHistoryIndex !== null && treeSnapshotId !== null) this.#claimTreeSnapshotAtHistoryIndex(navigationHistoryIndex, treeSnapshotId);
206
- this.commitHistoryTraversalIndex(navigationHistoryIndex);
232
+ if (historyIndex !== null && treeSnapshotId !== null) this.#claimTreeSnapshotAtHistoryIndex(historyIndex, treeSnapshotId);
233
+ }
234
+ /**
235
+ * Writes an app-owned push or replace entry and returns the traversal index
236
+ * it landed at. A history wrapper installed after boot can make its own
237
+ * writes before forwarding this one. When those moved the indices, the index
238
+ * is assigned as the write lands: a push goes after them, and a replace takes
239
+ * the index of the entry it actually overwrites. The index is committed as
240
+ * soon as the write succeeds, so a push the wrapper makes after forwarding
241
+ * goes after it.
242
+ */
243
+ #writeNavigationHistoryState(historyUpdateMode, state, href, allocatedIndex, rendersTree) {
244
+ const allocatedCurrentIndex = this.#currentHistoryTraversalIndex;
245
+ const allocatedNextIndex = this.#nextHistoryTraversalIndex;
246
+ const releaseClaims = (overwrittenHistoryState) => {
247
+ if (historyUpdateMode === "push") {
248
+ this.#releaseForwardTreeSnapshotClaims();
249
+ return;
250
+ }
251
+ if (!rendersTree) return;
252
+ const overwrittenIndex = readHistoryStateTraversalIndex(overwrittenHistoryState) ?? this.#currentHistoryTraversalIndex;
253
+ if (overwrittenIndex !== null) this.#releaseTreeSnapshotClaimAtHistoryIndex(overwrittenIndex);
254
+ };
255
+ let landedIndex;
256
+ let landingStarted = false;
257
+ const land = (data) => {
258
+ landingStarted = true;
259
+ const index = this.#currentHistoryTraversalIndex !== allocatedCurrentIndex || this.#nextHistoryTraversalIndex !== allocatedNextIndex ? this.allocateNavigationHistoryTraversalIndex(historyUpdateMode) : allocatedIndex;
260
+ const overwrittenHistoryState = this.#readHistoryState();
261
+ return {
262
+ data: index === allocatedIndex ? data : createHistoryStateWithNavigationMetadata(data, {
263
+ previousNextUrl: readHistoryStatePreviousNextUrl(data),
264
+ traversalIndex: index
265
+ }),
266
+ commit: () => {
267
+ releaseClaims(overwrittenHistoryState);
268
+ if (rendersTree) this.#treeSnapshotPending = true;
269
+ landedIndex = index;
270
+ this.commitHistoryTraversalIndex(index);
271
+ }
272
+ };
273
+ };
274
+ const historyStateBeforeWrite = this.#readHistoryState();
275
+ if (historyUpdateMode === "push") this.#pushHistoryState(state, href, land);
276
+ else this.#replaceHistoryState(state, href, land);
277
+ if (landedIndex !== void 0) return landedIndex;
278
+ if (landingStarted) return null;
279
+ releaseClaims(historyStateBeforeWrite);
280
+ if (rendersTree) this.#treeSnapshotPending = true;
281
+ this.commitHistoryTraversalIndex(allocatedIndex);
282
+ return allocatedIndex;
207
283
  }
208
284
  #createHashOnlyNavigationBaseHistoryState(historyUpdateMode, scroll) {
209
285
  const historyState = this.#readHistoryState();
@@ -238,19 +314,15 @@ var AppBrowserHistoryController = class {
238
314
  let wroteHistoryState = false;
239
315
  if (options.historyUpdateMode === "replace" && (currentHref !== targetHref || replacesClaimedOrExternalTree)) {
240
316
  options.stageClientParams();
241
- const currentHistoryIndex = readHistoryStateTraversalIndex(currentHistoryState) ?? this.#currentHistoryTraversalIndex;
242
- if (currentHistoryIndex !== null) this.#releaseTreeSnapshotClaimAtHistoryIndex(currentHistoryIndex);
243
- this.#replaceHistoryState(historyState, options.href);
317
+ this.#writeNavigationHistoryState("replace", historyState, options.href, navigationHistoryIndex, true);
244
318
  wroteHistoryState = true;
245
- this.commitHistoryTraversalIndex(navigationHistoryIndex);
246
319
  } else if (options.historyUpdateMode === "push" && currentHref !== targetHref) {
247
320
  options.stageClientParams();
248
- this.#releaseForwardTreeSnapshotClaims();
249
- this.#pushHistoryState(historyState, options.href);
321
+ this.#writeNavigationHistoryState("push", historyState, options.href, navigationHistoryIndex, true);
250
322
  wroteHistoryState = true;
251
- this.commitHistoryTraversalIndex(navigationHistoryIndex);
252
323
  }
253
324
  if (!wroteHistoryState) {
325
+ this.#treeSnapshotPending = true;
254
326
  this.syncCurrentHistoryStatePreviousNextUrl(options.previousNextUrl, options.bfcacheIds, options.activeRoutePaths);
255
327
  options.stageClientParams();
256
328
  if (options.targetHistoryIndex !== void 0) this.commitHistoryTraversalIndex(options.targetHistoryIndex);
@@ -306,6 +378,7 @@ var AppBrowserHistoryController = class {
306
378
  state,
307
379
  beforeCommit: () => {
308
380
  this.commitTraversalIndexFromHistoryState(options.historyState);
381
+ this.#treeSnapshotPending = true;
309
382
  options.stageClientParams(state.navigationSnapshot.params);
310
383
  }
311
384
  });
@@ -317,11 +390,16 @@ var AppBrowserHistoryController = class {
317
390
  state: decision.state,
318
391
  beforeCommit: () => {
319
392
  this.commitHistoryTraversalIndex(decision.targetHistoryIndex);
393
+ this.#treeSnapshotPending = true;
320
394
  options.stageClientParams(decision.state.navigationSnapshot.params);
321
395
  }
322
396
  });
323
397
  }
324
398
  };
399
+ function createDocumentTreeSnapshotIdPrefix() {
400
+ const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(8));
401
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
402
+ }
325
403
  function areStringArraysEqual(a, b) {
326
404
  if (a === b) return true;
327
405
  if (a === null || b === null || a.length !== b.length) return false;
@@ -1,11 +1,11 @@
1
1
  import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { AppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
3
- import { NavigationRuntimeVisibleCommitMode } from "../client/navigation-runtime.js";
4
3
  import { AppElements } from "./app-elements-wire.js";
5
4
  import "./app-elements.js";
5
+ import { ClientNavigationRenderSnapshot, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
6
+ import { NavigationRuntimeVisibleCommitMode } from "../client/navigation-runtime.js";
6
7
  import { OperationLane } from "./operation-token.js";
7
8
  import { ServerActionRevalidationKind } from "./app-browser-action-result.js";
8
- import { ClientNavigationRenderSnapshot, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
9
9
  import { AppNavigationPayloadOrigin, AppRouterState } from "./app-browser-state.js";
10
10
  import { Dispatch, ReactNode } from "react";
11
11
  //#region src/server/app-browser-navigation-controller.d.ts