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
@@ -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
@@ -1,9 +1,9 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { withBasePath } from "../shims/url-utils.js";
3
3
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
4
- import { claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
5
4
  import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
6
5
  import { resolveActiveRoutePaths } from "./app-history-state.js";
6
+ import { claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
7
7
  import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
8
8
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit, createPendingNavigationCommitFromElements } from "./app-browser-state.js";
9
9
  import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
@@ -408,7 +408,6 @@ function createAppBrowserNavigationController(deps = {}) {
408
408
  elements: options.restoredState.elements,
409
409
  interception: options.restoredState.interception,
410
410
  interceptionContext: options.restoredState.interceptionContext,
411
- layoutFlags: options.restoredState.layoutFlags,
412
411
  layoutIds: options.restoredState.layoutIds,
413
412
  navigationSnapshot: options.restoredState.navigationSnapshot,
414
413
  operation,
@@ -1,5 +1,5 @@
1
1
  import { isDangerousScheme, reportBlockedDangerousNavigation } from "../shims/url-safety.js";
2
- import { resolveHardNavigationTargetFromRscResponse, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
2
+ import { resolveHardNavigationTargetFromRscResponse, stripRscCacheBustingSearchParam, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
3
3
  //#region src/server/app-browser-rsc-redirect.ts
4
4
  const MAX_RSC_REDIRECT_DEPTH = 10;
5
5
  function blockDangerousStreamedRscRedirect(response, streamedRedirectTarget) {
@@ -11,11 +11,10 @@ function blockDangerousStreamedRscRedirect(response, streamedRedirectTarget) {
11
11
  function toVisibleAppHref(href, origin) {
12
12
  const url = new URL(href, origin);
13
13
  stripRscCacheBustingSearchParam(url);
14
- return `${stripRscSuffix(url.pathname)}${url.search}${url.hash}`;
14
+ return `${toPathAbsolutePathname(url.pathname)}${url.search}${url.hash}`;
15
15
  }
16
- function toStreamedRedirectVisibleAppHref(href, origin) {
17
- const url = new URL(href, origin);
18
- return `${url.pathname}${url.search}${url.hash}`;
16
+ function toStreamedRedirectVisibleAppHref(url) {
17
+ return `${toPathAbsolutePathname(url.pathname)}${url.search}${url.hash}`;
19
18
  }
20
19
  function resolveRedirectLifecycleHopFromTarget(options) {
21
20
  if (options.targetUrl.origin !== options.origin) return {
@@ -53,10 +52,11 @@ function resolveRscRedirectLifecycleHop(options) {
53
52
  });
54
53
  }
55
54
  function resolveStreamedRscRedirectLifecycleHop(options) {
56
- const streamedRedirectUrl = new URL(options.streamedRedirectTarget, options.origin);
55
+ const requestedUrl = new URL(options.currentHref, options.origin);
56
+ const streamedRedirectUrl = new URL(options.streamedRedirectTarget, requestedUrl);
57
57
  return resolveRedirectLifecycleHopFromTarget({
58
58
  ...options,
59
- redirectedHref: toStreamedRedirectVisibleAppHref(options.streamedRedirectTarget, options.origin),
59
+ redirectedHref: toStreamedRedirectVisibleAppHref(streamedRedirectUrl),
60
60
  targetUrl: streamedRedirectUrl
61
61
  });
62
62
  }
@@ -21,6 +21,8 @@ type ActionRedirectTarget = {
21
21
  export type ClientServerActionDeps = {
22
22
  basePath: string;
23
23
  clearClientNavigationCaches(): void;
24
+ /** Evict only the cached navigation data that may be dynamic. */
25
+ clearDynamicClientNavigationCaches(): void;
24
26
  clientRscCompatibilityId: string | null;
25
27
  commitSameUrlNavigatePayload(elements: Promise<AppElements>, actionInitiation: ClientServerActionInitiation, returnValue: ServerActionResult["returnValue"] | undefined, revalidation: ServerActionRevalidationKind, renderedPathAndSearch: string | null): Promise<unknown>;
26
28
  navigationPlanner: typeof navigationPlanner;
@@ -1,10 +1,10 @@
1
1
  import { hasBasePath } from "../utils/base-path.js";
2
2
  import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
3
3
  import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
4
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
5
+ import { throwOnServerActionNotFound } from "./server-action-not-found.js";
4
6
  import { AppElementsWire } from "./app-elements-wire.js";
5
7
  import "./app-elements.js";
6
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl } from "./app-rsc-cache-busting.js";
7
- import { throwOnServerActionNotFound } from "./server-action-not-found.js";
8
8
  import { createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldSyncServerActionHttpFallbackHead } from "./app-browser-action-result.js";
9
9
  import { parseRenderedPathAndSearchHeader } from "../shims/navigation.js";
10
10
  import { resolveServerActionRequestState } from "./app-browser-state.js";
@@ -49,7 +49,7 @@ var ServerActionRedirectError = class extends Error {
49
49
  constructor(target) {
50
50
  super("NEXT_REDIRECT");
51
51
  const redirectUrl = new URL(target.href, window.location.href);
52
- const redirectHref = redirectUrl.pathname + redirectUrl.search + redirectUrl.hash;
52
+ const redirectHref = toPathAbsolutePathname(redirectUrl.pathname) + redirectUrl.search + redirectUrl.hash;
53
53
  const redirectType = target.type === "push" ? "push" : "replace";
54
54
  this.digest = `NEXT_REDIRECT;${redirectType};${redirectHref};${target.status};`;
55
55
  }
@@ -89,7 +89,8 @@ async function invokeClientServerAction(id, args, actionInitiation, deps) {
89
89
  const actionResultDecision = deps.navigationPlanner.classifyServerActionResult(actionResultFacts);
90
90
  if (applyServerActionResultDecision(actionResultDecision, () => deps.clearClientNavigationCaches(), (url, historyMode) => deps.performHardNavigation(url, historyMode))) return;
91
91
  const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
92
- if (revalidation !== "none") deps.clearClientNavigationCaches();
92
+ if (revalidation === "staticAndDynamic") deps.clearClientNavigationCaches();
93
+ else if (revalidation === "dynamicOnly") deps.clearDynamicClientNavigationCaches();
93
94
  const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
94
95
  if (invalidResponseError) throw invalidResponseError;
95
96
  if (actionRedirectTarget && !fetchResponseIsRsc) {
@@ -1,13 +1,13 @@
1
1
  import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { CacheEntryReuseProof } from "./cache-proof.js";
3
- import { AppElements, AppElementsInterception, AppElementsSlotBinding, LayoutFlags } from "./app-elements-wire.js";
3
+ import { AppElements, AppElementsInterception, AppElementsSlotBinding } from "./app-elements-wire.js";
4
4
  import "./app-elements.js";
5
+ import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
5
6
  import { NavigationTrace } from "./navigation-trace.js";
6
7
  import { OperationLane } from "./operation-token.js";
7
8
  import "./navigation-planner.js";
8
9
  import { BfcacheIdMap, HistoryTraversalIntent, createAppOwnedHistoryState, createExternalHistoryStatePreservingMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createHistoryStateWithTreeSnapshotId, isExternalHistoryState, isHistoryStateBfcacheVersionCurrent, readHistoryStateActiveRoutePaths, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveActiveRoutePaths, resolveHistoryTraversalIntent } from "./app-history-state.js";
9
10
  import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
10
- import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
11
11
  //#region src/server/app-browser-state.d.ts
12
12
  type OperationRecordBase = {
13
13
  id: number;
@@ -30,7 +30,6 @@ export type AppRouterState = {
30
30
  elements: AppElements;
31
31
  interception: AppElementsInterception | null;
32
32
  interceptionContext: string | null;
33
- layoutFlags: LayoutFlags;
34
33
  layoutIds: readonly string[];
35
34
  previousNextUrl: string | null;
36
35
  renderId: number;
@@ -46,7 +45,6 @@ export type AppRouterAction = {
46
45
  elements: AppElements;
47
46
  interception: AppElementsInterception | null;
48
47
  interceptionContext: string | null;
49
- layoutFlags: LayoutFlags;
50
48
  layoutIds: readonly string[];
51
49
  navigationSnapshot: ClientNavigationRenderSnapshot;
52
50
  operation: PendingOperationRecord;
@@ -3,17 +3,18 @@ import { VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } from
3
3
  import { NEXT_ACTION_HEADER, RSC_ACTION_HEADER } from "./headers.js";
4
4
  import { normalizePathnameForRouteMatch } from "../routing/utils.js";
5
5
  import { normalizePath } from "./normalize-path.js";
6
+ import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
6
7
  import { AppElementsWire } from "./app-elements-wire.js";
7
8
  import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
8
- import { bindAppElementsRenderedSearch } from "../shims/slot.js";
9
- import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
10
9
  import { createBfcacheSegmentIdentityMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
11
- import { createCacheEntryReuseProof } from "./cache-proof.js";
12
10
  import { createAppOwnedHistoryState, createExternalHistoryStatePreservingMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createHistoryStateWithTreeSnapshotId, isExternalHistoryState, isHistoryStateBfcacheVersionCurrent, readHistoryStateActiveRoutePaths, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveActiveRoutePaths, resolveHistoryTraversalIntent } from "./app-history-state.js";
13
11
  import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
14
12
  import { verifyOperationTokenForCommit } from "./operation-token.js";
15
13
  import { navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts } from "./navigation-planner.js";
16
14
  import { createSnapshotPathAndSearch } from "../shims/navigation.js";
15
+ import { holdsSkippedLayouts } from "./app-mounted-layouts.js";
16
+ import { createCacheEntryReuseProof } from "./cache-proof.js";
17
+ import { bindAppElementsRenderedSearch } from "../shims/slot.js";
17
18
  //#region src/server/app-browser-state.ts
18
19
  const COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "committed-cache" };
19
20
  const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "fresh" };
@@ -239,6 +240,11 @@ function mapNavigationDecisionToPendingDisposition(decision) {
239
240
  function mergeSkippedLayoutPreservation(options) {
240
241
  if (options.decision.disposition !== "dispatch") return options.decision;
241
242
  if (options.pending.skippedLayoutIds.length === 0) return options.decision;
243
+ if (!holdsSkippedLayouts(options.currentState, options.pending.action.elements)) return {
244
+ disposition: "hard-navigate",
245
+ preserveElementIds: [],
246
+ trace: options.decision.trace
247
+ };
242
248
  const currentLayoutIds = new Set(options.currentState.layoutIds);
243
249
  const targetLayoutIds = new Set(options.pending.action.layoutIds);
244
250
  const preserveElementIds = [...options.decision.preserveElementIds];
@@ -303,7 +309,6 @@ function createPendingNavigationCommitFromElements(options) {
303
309
  interception: metadata.interception,
304
310
  interceptionContext: metadata.interceptionContext,
305
311
  layoutIds: metadata.layoutIds,
306
- layoutFlags: metadata.layoutFlags,
307
312
  slotBindings: metadata.slotBindings,
308
313
  navigationSnapshot: options.navigationSnapshot,
309
314
  operation: createOperationRecord({
@@ -1,8 +1,9 @@
1
1
  import { addBasePathToPathname, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
2
2
  import { normalizePathnameForRouteMatch } from "../routing/utils.js";
3
3
  import { normalizePath } from "./normalize-path.js";
4
- import { APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_SLOT_BINDINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
4
+ import { APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_SLOT_BINDINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
5
5
  import "./app-elements.js";
6
+ import { isNestedBfcacheSlotSegmentIdFor } from "./bfcache-identity.js";
6
7
  //#region src/server/app-browser-supplemental-refresh.ts
7
8
  const SUPPLEMENTAL_REFRESH_TIMEOUT_MS = 1e4;
8
9
  var SupplementalRefreshError = class extends Error {
@@ -67,6 +68,7 @@ function mergeRefreshedParallelSlot(currentElements, refreshedElements) {
67
68
  [APP_SLOT_BINDINGS_KEY]: normalizeAppElementsSlotBindings(slotBindings, { layoutIds: refreshedMetadata.layoutIds })
68
69
  };
69
70
  for (const binding of retainedBindings) merged[binding.slotId] = currentElements[binding.slotId];
71
+ copySlotIdentities(merged, refreshedElements, currentElements, retainedBindings.map((binding) => binding.slotId));
70
72
  if (promotedBindings.length === 1) merged[promotedBindings[0].slotId] = refreshedElements[refreshedChildrenBindings[0].slotId];
71
73
  copyRefreshedBranchElements(merged, currentElements, { overwrite: false });
72
74
  return merged;
@@ -79,6 +81,7 @@ function mergeRefreshedParallelSlot(currentElements, refreshedElements) {
79
81
  [APP_SLOT_BINDINGS_KEY]: normalizeAppElementsSlotBindings(slotBindings, { layoutIds: currentMetadata.layoutIds })
80
82
  };
81
83
  for (const binding of refreshedBindings) merged[binding.slotId] = refreshedElements[binding.slotId];
84
+ copySlotIdentities(merged, currentElements, refreshedElements, refreshedBindings.map((binding) => binding.slotId));
82
85
  copyRefreshedBranchElements(merged, refreshedElements);
83
86
  return merged;
84
87
  }
@@ -93,9 +96,21 @@ function mergeRefreshedParallelSlot(currentElements, refreshedElements) {
93
96
  [interception.slotId]: refreshedSlot,
94
97
  [APP_SLOT_BINDINGS_KEY]: normalizeAppElementsSlotBindings(slotBindings, { layoutIds: currentMetadata.layoutIds })
95
98
  };
99
+ copySlotIdentities(merged, currentElements, refreshedElements, [interception.slotId]);
96
100
  copyRefreshedBranchElements(merged, refreshedElements);
97
101
  return merged;
98
102
  }
103
+ function copySlotIdentities(target, baseElements, slotElements, slotIds) {
104
+ const isSlotSegment = (id) => slotIds.some((slotId) => id === slotId || isNestedBfcacheSlotSegmentIdFor(id, slotId));
105
+ const isNestedSegment = (id) => !slotIds.includes(id) && isSlotSegment(id);
106
+ for (const id of Object.keys(baseElements)) if (isNestedSegment(id)) delete target[id];
107
+ for (const [id, element] of Object.entries(slotElements)) if (isNestedSegment(id)) target[id] = element;
108
+ const identities = {};
109
+ for (const [id, identity] of Object.entries(AppElementsWire.readMetadata(baseElements).bfcacheSegmentIdentities)) if (!isSlotSegment(id)) identities[id] = identity;
110
+ for (const [id, identity] of Object.entries(AppElementsWire.readMetadata(slotElements).bfcacheSegmentIdentities)) if (isSlotSegment(id)) identities[id] = identity;
111
+ if (Object.keys(identities).length > 0) target[APP_BFCACHE_SEGMENT_IDENTITIES_KEY] = identities;
112
+ else delete target[APP_BFCACHE_SEGMENT_IDENTITIES_KEY];
113
+ }
99
114
  function copyRefreshedBranchElements(target, refreshedElements, options = {}) {
100
115
  for (const [elementId, element] of Object.entries(refreshedElements)) {
101
116
  const parsed = AppElementsWire.parseElementKey(elementId);
@@ -1,9 +1,9 @@
1
1
  import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { AppElements } from "./app-elements-wire.js";
3
3
  import "./app-elements.js";
4
+ import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
4
5
  import { NavigationTrace } from "./navigation-trace.js";
5
6
  import { OperationLane } from "./operation-token.js";
6
- import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
7
7
  import { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, PendingNavigationCommit } from "./app-browser-state.js";
8
8
  //#region src/server/app-browser-visible-commit.d.ts
9
9
  type VisibleCommitDecision = {
@@ -1,10 +1,10 @@
1
1
  import { AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
2
2
  import "./app-elements.js";
3
- import { mergeElements } from "../shims/slot.js";
4
- import { resolveAppPageRouteStateKey } from "./app-page-segment-state.js";
5
3
  import { createBfcacheSegmentIdentityMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
6
4
  import { NavigationTraceReasonCodes, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry } from "./navigation-trace.js";
5
+ import { mergeElements } from "../shims/slot.js";
7
6
  import { createPendingNavigationCommit, resolvePendingNavigationCommitDispositionDecision } from "./app-browser-state.js";
7
+ import { resolveAppPageRouteStateKey } from "./app-page-segment-state.js";
8
8
  //#region src/server/app-browser-visible-commit.ts
9
9
  const approvedVisibleCommitBrand = Symbol("ApprovedVisibleCommit");
10
10
  function hasSameServerTemplateSeedIdentity(id, currentSnapshot, nextSnapshot) {
@@ -87,11 +87,11 @@ function reduceApprovedVisibleCommitState(state, commit) {
87
87
  const hmrUniquePreserveElementIds = hmrPreserveElementIds.length > 1 ? [...new Set(hmrPreserveElementIds)] : hmrPreserveElementIds;
88
88
  const preserveElementIds = action.operation.lane === "hmr" ? hmrUniquePreserveElementIds : bfcacheCompatiblePreserveElementIds;
89
89
  const preserveTemplateIds = action.reuseCurrentBfcacheIds && (action.operation.lane === "navigation" || action.operation.lane === "traverse" || action.operation.lane === "server-action") ? Object.keys(state.elements).filter((id) => Object.hasOwn(action.elements, id) && hasSameServerTemplateSeedIdentity(id, state.navigationSnapshot, action.navigationSnapshot)) : [];
90
- const mergedPreserveElementIds = preserveTemplateIds.length === 0 ? preserveElementIds : [.../* @__PURE__ */ new Set([...preserveElementIds, ...preserveTemplateIds])];
91
90
  const mergedElements = mergeElements(state.elements, action.elements, {
92
91
  clearAbsentSlots: action.type === "traverse" || !action.reuseCurrentBfcacheIds,
93
92
  preserveAbsentSlots: action.reuseCurrentBfcacheIds && commit.decision.preserveAbsentSlots,
94
- preserveElementIds: mergedPreserveElementIds,
93
+ preserveElementIds,
94
+ preserveElementSeedIds: preserveTemplateIds,
95
95
  preservePreviousSlotIds: effectivePreservePreviousSlotIds
96
96
  });
97
97
  return commitVisibleRouterState(state, {
@@ -105,7 +105,6 @@ function reduceApprovedVisibleCommitState(state, commit) {
105
105
  elements: mergedElements,
106
106
  interception: action.interception,
107
107
  interceptionContext: action.interceptionContext,
108
- layoutFlags: mergeLayoutFlags(state.layoutFlags, action.layoutFlags, preserveElementIds),
109
108
  layoutIds: action.layoutIds,
110
109
  navigationSnapshot: action.navigationSnapshot,
111
110
  previousNextUrl: action.previousNextUrl,
@@ -145,15 +144,6 @@ function createVisibleCommitDecision(trace = createNavigationTrace(NavigationTra
145
144
  trace
146
145
  };
147
146
  }
148
- function mergeLayoutFlags(previousFlags, nextFlags, preserveElementIds) {
149
- const merged = { ...nextFlags };
150
- for (const id of preserveElementIds) {
151
- if (Object.hasOwn(merged, id)) continue;
152
- const value = previousFlags[id];
153
- if (value) merged[id] = value;
154
- }
155
- return merged;
156
- }
157
147
  function createApprovedVisibleCommit(options) {
158
148
  return {
159
149
  [approvedVisibleCommitBrand]: true,
@@ -1,6 +1,5 @@
1
1
  import { ArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
2
2
  import { CacheEntryReuseProof } from "./cache-proof.js";
3
- import { ClientReuseManifestSkipDisposition } from "./client-reuse-manifest.js";
4
3
  import { BfcacheSegmentIdentity } from "./bfcache-identity.js";
5
4
  import { compareStrings } from "../utils/compare.js";
6
5
  import { AppElementsWireElementKey } from "./app-elements-wire-key.js";
@@ -12,7 +11,6 @@ export declare const APP_DYNAMIC_STALE_TIME_KEY = "__dynamicStaleTime";
12
11
  export declare const APP_INTERCEPTION_KEY = "__interception";
13
12
  export declare const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
14
13
  export declare const APP_LAYOUT_IDS_KEY = "__layoutIds";
15
- export declare const APP_LAYOUT_FLAGS_KEY = "__layoutFlags";
16
14
  export declare const APP_ROUTE_KEY = "__route";
17
15
  export declare const APP_ROOT_LAYOUT_KEY = "__rootLayout";
18
16
  export declare const APP_SKIPPED_LAYOUT_IDS_KEY = "__skippedLayoutIds";
@@ -51,28 +49,10 @@ export declare const compareAppElementsSlotIds: typeof compareStrings;
51
49
  export declare function normalizeAppElementsSlotBindings(slotBindings: readonly AppElementsSlotBinding[], options?: {
52
50
  layoutIds?: readonly string[];
53
51
  }): readonly AppElementsSlotBinding[];
54
- export type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null | LayoutFlags | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | readonly string[] | readonly AppElementsSlotBinding[];
55
- type AppWireElementValue = ReactNode | string | null | LayoutFlags | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | readonly string[] | readonly AppElementsSlotBinding[];
52
+ export type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | readonly string[] | readonly AppElementsSlotBinding[];
53
+ type AppWireElementValue = ReactNode | string | null | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | readonly string[] | readonly AppElementsSlotBinding[];
56
54
  export type AppElements = Readonly<Record<string, AppElementValue>>;
57
55
  export type AppWireElements = Readonly<Record<string, AppWireElementValue>>;
58
- /**
59
- * Per-layout static/dynamic flags. `"s"` = static (skippable on next nav);
60
- * `"d"` = dynamic (must always render).
61
- *
62
- * Lifecycle (partial — later PRs extend this):
63
- *
64
- * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns
65
- * LayoutFlags for every layout in the route at render time.
66
- *
67
- * 2. ATTACH — AppElementsWire.encodeOutgoingPayload writes `__layoutFlags`
68
- * into the outgoing App Router payload record.
69
- *
70
- * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.
71
- *
72
- * 4. PARSE — AppElementsWire.readMetadata extracts layoutFlags from the
73
- * wire payload on the client side.
74
- */
75
- export type LayoutFlags = Readonly<Record<string, "s" | "d">>;
76
56
  export type AppElementsBfcacheSegmentIdentities = Readonly<Record<string, BfcacheSegmentIdentity>>;
77
57
  type AppElementsMetadata = {
78
58
  artifactCompatibility: ArtifactCompatibilityEnvelope;
@@ -81,7 +61,6 @@ type AppElementsMetadata = {
81
61
  interception: AppElementsInterception | null;
82
62
  interceptionContext: string | null;
83
63
  layoutIds: readonly string[];
84
- layoutFlags: LayoutFlags;
85
64
  routeId: string;
86
65
  rootLayoutTreePath: string | null;
87
66
  bfcacheSegmentIdentities: AppElementsBfcacheSegmentIdentities;
@@ -113,11 +92,11 @@ type AppElementsWireMetadataEntries = Readonly<{
113
92
  }>;
114
93
  /**
115
94
  * The outgoing wire payload shape. Includes ReactNode values for the
116
- * rendered tree plus metadata values like LayoutFlags attached under
117
- * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements
95
+ * rendered tree plus metadata values attached under known keys (e.g.
96
+ * __artifactCompatibility). Distinct from AppElements / AppWireElements
118
97
  * which only carry render-time values.
119
98
  */
120
- export type AppOutgoingElements = Readonly<Record<string, ReactNode | LayoutFlags | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | number | readonly string[] | readonly AppElementsSlotBinding[]>>;
99
+ export type AppOutgoingElements = Readonly<Record<string, ReactNode | AppElementsBfcacheSegmentIdentities | ArtifactCompatibilityEnvelope | CacheEntryReuseProof | AppElementsInterception | number | readonly string[] | readonly AppElementsSlotBinding[]>>;
121
100
  type AppElementsWireKeys = {
122
101
  readonly artifactCompatibility: typeof APP_ARTIFACT_COMPATIBILITY_KEY;
123
102
  readonly cacheEntryReuseProof: typeof APP_CACHE_ENTRY_REUSE_PROOF_KEY;
@@ -125,7 +104,6 @@ type AppElementsWireKeys = {
125
104
  readonly interception: typeof APP_INTERCEPTION_KEY;
126
105
  readonly interceptionContext: typeof APP_INTERCEPTION_CONTEXT_KEY;
127
106
  readonly layoutIds: typeof APP_LAYOUT_IDS_KEY;
128
- readonly layoutFlags: typeof APP_LAYOUT_FLAGS_KEY;
129
107
  readonly rootLayout: typeof APP_ROOT_LAYOUT_KEY;
130
108
  readonly route: typeof APP_ROUTE_KEY;
131
109
  readonly bfcacheSegmentIdentities: typeof APP_BFCACHE_SEGMENT_IDENTITIES_KEY;
@@ -145,8 +123,6 @@ type AppElementsWireCodec = {
145
123
  artifactCompatibility?: ArtifactCompatibilityEnvelope;
146
124
  cacheEntryReuseProof?: CacheEntryReuseProof;
147
125
  dynamicStaleTimeSeconds?: number;
148
- layoutFlags: LayoutFlags;
149
- skipDisposition?: ClientReuseManifestSkipDisposition;
150
126
  }): ReactNode | AppOutgoingElements;
151
127
  encodePageId(routePath: string, interceptionContext: string | null): string;
152
128
  encodeRouteId(routePath: string, interceptionContext: string | null): string;
@@ -155,9 +131,6 @@ type AppElementsWireCodec = {
155
131
  isSlotId(key: string): boolean;
156
132
  parseElementKey(key: string): AppElementsWireElementKey | null;
157
133
  readMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;
158
- withLayoutFlags<T extends Record<string, unknown>>(elements: T, layoutFlags: LayoutFlags): T & {
159
- [APP_LAYOUT_FLAGS_KEY]: LayoutFlags;
160
- };
161
134
  };
162
135
  export declare function normalizeAppElements(elements: AppWireElements): AppElements;
163
136
  /**
@@ -165,21 +138,16 @@ export declare function normalizeAppElements(elements: AppWireElements): AppElem
165
138
  * Used to distinguish the App Router payload object from bare React elements at
166
139
  * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because
167
140
  * the outgoing payload carries heterogeneous values (ReactNodes for the rendered
168
- * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates
141
+ * tree, plus metadata like `__artifactCompatibility`, a plain object). Delegates
169
142
  * to React's canonical `isValidElement` so we don't depend on React's internal
170
143
  * `$$typeof` marker scheme.
171
144
  */
172
145
  export declare function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>>;
173
- export declare function withLayoutFlags<T extends Record<string, unknown>>(elements: T, layoutFlags: LayoutFlags): T & {
174
- [APP_LAYOUT_FLAGS_KEY]: LayoutFlags;
175
- };
176
146
  export declare function buildOutgoingAppPayload(input: {
177
147
  element: ReactNode | AppElements;
178
148
  artifactCompatibility?: ArtifactCompatibilityEnvelope;
179
149
  cacheEntryReuseProof?: CacheEntryReuseProof;
180
150
  dynamicStaleTimeSeconds?: number;
181
- layoutFlags: LayoutFlags;
182
- skipDisposition?: ClientReuseManifestSkipDisposition;
183
151
  }): ReactNode | AppOutgoingElements;
184
152
  export declare function readAppElementsMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;
185
153
  export declare const AppElementsWire: AppElementsWireCodec;