vinext 0.1.7 → 0.2.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 (279) hide show
  1. package/README.md +51 -30
  2. package/dist/build/inject-pregenerated-paths.d.ts +4 -0
  3. package/dist/build/inject-pregenerated-paths.js +18 -0
  4. package/dist/build/layout-classification.js +1 -1
  5. package/dist/build/nitro-route-rules.js +1 -1
  6. package/dist/build/pages-client-assets-module.d.ts +11 -0
  7. package/dist/build/pages-client-assets-module.js +27 -0
  8. package/dist/build/prerender.d.ts +2 -1
  9. package/dist/build/prerender.js +13 -6
  10. package/dist/build/report.d.ts +13 -2
  11. package/dist/build/report.js +99 -2
  12. package/dist/build/run-prerender.d.ts +7 -0
  13. package/dist/build/run-prerender.js +10 -1
  14. package/dist/build/standalone.js +2 -0
  15. package/dist/cache/cache-adapters-virtual.js +3 -3
  16. package/dist/check.d.ts +18 -0
  17. package/dist/check.js +77 -19
  18. package/dist/cli-args.d.ts +1 -2
  19. package/dist/cli-args.js +1 -1
  20. package/dist/cli-dev-config.d.ts +12 -0
  21. package/dist/cli-dev-config.js +23 -0
  22. package/dist/cli.js +113 -97
  23. package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
  24. package/dist/{server → client}/dev-error-overlay-store.js +1 -1
  25. package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
  26. package/dist/{server → client}/dev-error-overlay.js +2 -2
  27. package/dist/client/navigation-runtime.d.ts +2 -0
  28. package/dist/client/navigation-runtime.js +3 -1
  29. package/dist/client/window-next.d.ts +2 -1
  30. package/dist/cloudflare/index.d.ts +2 -2
  31. package/dist/cloudflare/index.js +2 -2
  32. package/dist/config/config-matchers.js +14 -10
  33. package/dist/config/next-config.d.ts +6 -3
  34. package/dist/config/next-config.js +47 -1
  35. package/dist/config/prerender.d.ts +34 -0
  36. package/dist/config/prerender.js +55 -0
  37. package/dist/config/server-external-packages.d.ts +4 -0
  38. package/dist/config/server-external-packages.js +91 -0
  39. package/dist/entries/app-rsc-entry.d.ts +2 -1
  40. package/dist/entries/app-rsc-entry.js +89 -15
  41. package/dist/entries/app-rsc-manifest.js +10 -0
  42. package/dist/entries/pages-client-entry.d.ts +3 -0
  43. package/dist/entries/pages-client-entry.js +16 -1
  44. package/dist/entries/pages-server-entry.js +6 -2
  45. package/dist/image/image-adapters-virtual.d.ts +59 -0
  46. package/dist/image/image-adapters-virtual.js +59 -0
  47. package/dist/index.d.ts +33 -0
  48. package/dist/index.js +211 -118
  49. package/dist/init-cloudflare.d.ts +43 -0
  50. package/dist/init-cloudflare.js +839 -0
  51. package/dist/init-platform.d.ts +40 -0
  52. package/dist/init-platform.js +195 -0
  53. package/dist/init.d.ts +16 -38
  54. package/dist/init.js +208 -97
  55. package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
  56. package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
  57. package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
  58. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
  59. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +1 -1
  60. package/dist/packages/cloudflare/src/deploy-config.js +150 -0
  61. package/dist/packages/cloudflare/src/deploy-help.js +55 -0
  62. package/dist/packages/cloudflare/src/deploy.js +276 -0
  63. package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
  64. package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +18 -15
  65. package/dist/plugins/ast-scope.d.ts +16 -0
  66. package/dist/plugins/ast-scope.js +62 -0
  67. package/dist/plugins/ast-utils.d.ts +27 -1
  68. package/dist/plugins/ast-utils.js +32 -1
  69. package/dist/plugins/css-module-imports.d.ts +14 -0
  70. package/dist/plugins/css-module-imports.js +59 -0
  71. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  72. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  73. package/dist/plugins/ignore-dynamic-requests.js +530 -0
  74. package/dist/plugins/middleware-server-only.d.ts +8 -6
  75. package/dist/plugins/middleware-server-only.js +8 -7
  76. package/dist/plugins/optimize-imports.js +1 -1
  77. package/dist/plugins/typeof-window.d.ts +1 -1
  78. package/dist/plugins/typeof-window.js +28 -56
  79. package/dist/routing/app-route-graph.d.ts +29 -4
  80. package/dist/routing/app-route-graph.js +182 -40
  81. package/dist/routing/app-router.d.ts +5 -0
  82. package/dist/routing/app-router.js +5 -0
  83. package/dist/routing/file-matcher.d.ts +8 -0
  84. package/dist/routing/file-matcher.js +10 -1
  85. package/dist/routing/pages-router.js +2 -2
  86. package/dist/server/api-handler.js +9 -14
  87. package/dist/server/app-browser-action-result.d.ts +4 -1
  88. package/dist/server/app-browser-action-result.js +8 -1
  89. package/dist/server/app-browser-entry.js +194 -190
  90. package/dist/server/app-browser-history-controller.d.ts +2 -1
  91. package/dist/server/app-browser-history-controller.js +6 -2
  92. package/dist/server/app-browser-interception-context.d.ts +1 -0
  93. package/dist/server/app-browser-interception-context.js +4 -2
  94. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  95. package/dist/server/app-browser-navigation-controller.js +60 -31
  96. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  97. package/dist/server/app-browser-server-action-client.js +127 -0
  98. package/dist/server/app-browser-state.d.ts +11 -1
  99. package/dist/server/app-browser-state.js +25 -8
  100. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  101. package/dist/server/app-browser-visible-commit.js +43 -25
  102. package/dist/server/app-elements-wire.d.ts +9 -2
  103. package/dist/server/app-elements-wire.js +8 -1
  104. package/dist/server/app-elements.d.ts +2 -2
  105. package/dist/server/app-elements.js +4 -3
  106. package/dist/server/app-fallback-renderer.d.ts +5 -2
  107. package/dist/server/app-fallback-renderer.js +15 -7
  108. package/dist/server/app-hydration-cache-publication.d.ts +11 -0
  109. package/dist/server/app-hydration-cache-publication.js +43 -0
  110. package/dist/server/app-middleware.d.ts +4 -3
  111. package/dist/server/app-middleware.js +8 -3
  112. package/dist/server/app-optimistic-routing.js +11 -4
  113. package/dist/server/app-page-boundary-render.d.ts +3 -0
  114. package/dist/server/app-page-boundary-render.js +14 -3
  115. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  116. package/dist/server/app-page-cache-finalizer.js +10 -3
  117. package/dist/server/app-page-cache-render.d.ts +1 -0
  118. package/dist/server/app-page-cache-render.js +8 -4
  119. package/dist/server/app-page-cache.d.ts +1 -0
  120. package/dist/server/app-page-cache.js +5 -2
  121. package/dist/server/app-page-dispatch.d.ts +33 -4
  122. package/dist/server/app-page-dispatch.js +63 -90
  123. package/dist/server/app-page-element-builder.d.ts +9 -2
  124. package/dist/server/app-page-element-builder.js +114 -23
  125. package/dist/server/app-page-head.d.ts +16 -1
  126. package/dist/server/app-page-head.js +44 -22
  127. package/dist/server/app-page-params.d.ts +2 -1
  128. package/dist/server/app-page-params.js +8 -1
  129. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  130. package/dist/server/app-page-ppr-runtime.js +70 -0
  131. package/dist/server/app-page-probe.d.ts +1 -0
  132. package/dist/server/app-page-probe.js +6 -1
  133. package/dist/server/app-page-render-identity.d.ts +1 -0
  134. package/dist/server/app-page-render-identity.js +1 -1
  135. package/dist/server/app-page-render.d.ts +4 -1
  136. package/dist/server/app-page-render.js +26 -3
  137. package/dist/server/app-page-request.d.ts +22 -1
  138. package/dist/server/app-page-request.js +92 -15
  139. package/dist/server/app-page-route-wiring.d.ts +14 -2
  140. package/dist/server/app-page-route-wiring.js +61 -25
  141. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  142. package/dist/server/app-page-search-params-observation.js +11 -7
  143. package/dist/server/app-page-segment-state.d.ts +2 -1
  144. package/dist/server/app-page-segment-state.js +3 -1
  145. package/dist/server/app-page-stream.d.ts +5 -0
  146. package/dist/server/app-page-stream.js +3 -1
  147. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  148. package/dist/server/app-route-handler-dispatch.js +1 -0
  149. package/dist/server/app-route-handler-execution.js +7 -2
  150. package/dist/server/app-route-handler-response.js +1 -0
  151. package/dist/server/app-route-handler-runtime.js +1 -1
  152. package/dist/server/app-route-module-loader.d.ts +2 -0
  153. package/dist/server/app-route-module-loader.js +1 -0
  154. package/dist/server/app-router-entry.js +16 -8
  155. package/dist/server/app-rsc-errors.js +7 -1
  156. package/dist/server/app-rsc-handler.d.ts +3 -1
  157. package/dist/server/app-rsc-handler.js +67 -39
  158. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  159. package/dist/server/app-rsc-request-normalization.js +6 -3
  160. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  161. package/dist/server/app-rsc-route-matching.js +36 -3
  162. package/dist/server/app-segment-config.d.ts +12 -0
  163. package/dist/server/app-segment-config.js +91 -5
  164. package/dist/server/app-server-action-execution.d.ts +5 -0
  165. package/dist/server/app-server-action-execution.js +94 -33
  166. package/dist/server/app-ssr-entry.d.ts +3 -0
  167. package/dist/server/app-ssr-entry.js +19 -8
  168. package/dist/server/app-ssr-stream.d.ts +7 -3
  169. package/dist/server/app-ssr-stream.js +10 -6
  170. package/dist/server/app-static-generation.d.ts +1 -0
  171. package/dist/server/app-static-generation.js +1 -0
  172. package/dist/server/app-visited-response-cache.d.ts +6 -0
  173. package/dist/server/app-visited-response-cache.js +3 -1
  174. package/dist/server/client-trace-metadata.js +26 -0
  175. package/dist/server/default-global-not-found-module.d.ts +14 -0
  176. package/dist/server/default-global-not-found-module.js +14 -0
  177. package/dist/server/dev-route-files.js +4 -0
  178. package/dist/server/dev-server.js +19 -18
  179. package/dist/server/dev-stack-sourcemap.d.ts +1 -1
  180. package/dist/server/dev-stack-sourcemap.js +1 -1
  181. package/dist/server/fetch-handler.d.ts +2 -0
  182. package/dist/server/fetch-handler.js +18 -0
  183. package/dist/server/headers.d.ts +5 -15
  184. package/dist/server/headers.js +4 -15
  185. package/dist/server/image-optimization.d.ts +51 -1
  186. package/dist/server/image-optimization.js +52 -2
  187. package/dist/server/implicit-tags.js +1 -1
  188. package/dist/server/isr-cache.d.ts +1 -1
  189. package/dist/server/isr-cache.js +2 -2
  190. package/dist/server/metadata-routes.d.ts +3 -1
  191. package/dist/server/metadata-routes.js +12 -2
  192. package/dist/server/middleware-runtime.js +6 -1
  193. package/dist/server/navigation-planner.d.ts +1 -0
  194. package/dist/server/navigation-planner.js +14 -3
  195. package/dist/server/pages-api-route.js +2 -2
  196. package/dist/server/pages-asset-tags.d.ts +4 -6
  197. package/dist/server/pages-asset-tags.js +12 -12
  198. package/dist/server/pages-client-assets.d.ts +12 -0
  199. package/dist/server/pages-client-assets.js +10 -0
  200. package/dist/server/pages-node-compat.d.ts +8 -1
  201. package/dist/server/pages-node-compat.js +32 -4
  202. package/dist/server/pages-page-data.d.ts +24 -1
  203. package/dist/server/pages-page-data.js +45 -24
  204. package/dist/server/pages-page-handler.d.ts +2 -1
  205. package/dist/server/pages-page-handler.js +19 -12
  206. package/dist/server/pages-page-response.d.ts +7 -0
  207. package/dist/server/pages-page-response.js +4 -1
  208. package/dist/server/pages-request-pipeline.d.ts +2 -0
  209. package/dist/server/pages-request-pipeline.js +25 -1
  210. package/dist/server/pages-router-entry.d.ts +30 -0
  211. package/dist/server/pages-router-entry.js +108 -0
  212. package/dist/server/prerender-manifest.d.ts +3 -1
  213. package/dist/server/prerender-route-params.js +1 -1
  214. package/dist/server/prod-server.d.ts +1 -1
  215. package/dist/server/prod-server.js +48 -26
  216. package/dist/server/request-pipeline.js +1 -0
  217. package/dist/server/seed-cache.js +4 -4
  218. package/dist/server/worker-utils.d.ts +2 -1
  219. package/dist/server/worker-utils.js +7 -1
  220. package/dist/shims/app-router-scroll-state.d.ts +1 -0
  221. package/dist/shims/app-router-scroll-state.js +1 -0
  222. package/dist/shims/app-router-scroll.js +2 -1
  223. package/dist/shims/cache.js +19 -15
  224. package/dist/shims/cdn-cache.js +1 -1
  225. package/dist/shims/dynamic-preload-chunks.js +2 -1
  226. package/dist/shims/error-boundary.d.ts +19 -1
  227. package/dist/shims/error-boundary.js +11 -1
  228. package/dist/shims/form.d.ts +3 -1
  229. package/dist/shims/form.js +37 -43
  230. package/dist/shims/headers.d.ts +9 -1
  231. package/dist/shims/headers.js +31 -6
  232. package/dist/shims/image.js +75 -14
  233. package/dist/shims/internal/app-route-detection.d.ts +2 -17
  234. package/dist/shims/internal/app-route-detection.js +4 -17
  235. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
  236. package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
  237. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -15
  238. package/dist/shims/internal/hybrid-client-route-owner.js +9 -60
  239. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +9 -5
  240. package/dist/shims/internal/pages-data-fetch-dedup.js +73 -14
  241. package/dist/shims/internal/pages-data-target.d.ts +10 -9
  242. package/dist/shims/internal/pages-data-target.js +91 -12
  243. package/dist/shims/internal/pages-router-components.d.ts +7 -0
  244. package/dist/shims/internal/pages-router-components.js +13 -0
  245. package/dist/shims/layout-segment-context.d.ts +4 -1
  246. package/dist/shims/layout-segment-context.js +18 -4
  247. package/dist/shims/link.js +70 -37
  248. package/dist/shims/metadata.d.ts +3 -2
  249. package/dist/shims/metadata.js +8 -4
  250. package/dist/shims/navigation.d.ts +5 -1
  251. package/dist/shims/navigation.js +45 -10
  252. package/dist/shims/navigation.react-server.js +1 -1
  253. package/dist/shims/root-params.d.ts +15 -1
  254. package/dist/shims/root-params.js +21 -1
  255. package/dist/shims/router.d.ts +5 -7
  256. package/dist/shims/router.js +374 -94
  257. package/dist/shims/server.js +3 -2
  258. package/dist/shims/slot.js +3 -6
  259. package/dist/typegen.js +6 -5
  260. package/dist/utils/client-runtime-metadata.d.ts +2 -18
  261. package/dist/utils/client-runtime-metadata.js +31 -22
  262. package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
  263. package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
  264. package/dist/utils/domain-locale.d.ts +6 -3
  265. package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
  266. package/dist/{server → utils}/middleware-request-headers.js +2 -2
  267. package/dist/utils/path.d.ts +2 -1
  268. package/dist/utils/path.js +1 -1
  269. package/dist/utils/project.d.ts +52 -2
  270. package/dist/utils/project.js +230 -5
  271. package/dist/utils/protocol-headers.d.ts +17 -0
  272. package/dist/utils/protocol-headers.js +17 -0
  273. package/dist/utils/react-version.d.ts +4 -0
  274. package/dist/utils/react-version.js +44 -0
  275. package/package.json +53 -4
  276. package/dist/deploy.d.ts +0 -190
  277. package/dist/deploy.js +0 -1033
  278. package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
  279. /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
@@ -1,5 +1,9 @@
1
1
  import { RestorableClientStateController, createHistoryStateWithNavigationMetadata, readHistoryStateBfcacheIds, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
2
2
  //#region src/server/app-browser-history-controller.ts
3
+ function createCanonicalBrowserHistoryHref(href) {
4
+ const url = new URL(href);
5
+ return `${url.pathname}${url.search}${url.hash}`;
6
+ }
3
7
  function stripVinextScrollState(state) {
4
8
  if (!state || typeof state !== "object") return state;
5
9
  const nextState = {};
@@ -166,7 +170,7 @@ var AppBrowserHistoryController = class {
166
170
  this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
167
171
  previousNextUrl: null,
168
172
  traversalIndex: this.#currentHistoryTraversalIndex
169
- }), this.#readCurrentHref());
173
+ }), createCanonicalBrowserHistoryHref(this.#readCurrentHref()));
170
174
  }
171
175
  /** History write performed on the first committed (hydrated) render. */
172
176
  writeHydratedHistoryMetadata(options) {
@@ -207,4 +211,4 @@ function areBfcacheIdMapsEqual(a, b) {
207
211
  return aEntries.every(([key, value]) => b[key] === value);
208
212
  }
209
213
  //#endregion
210
- export { AppBrowserHistoryController };
214
+ export { AppBrowserHistoryController, createCanonicalBrowserHistoryHref };
@@ -3,6 +3,7 @@ import { RouteManifest } from "../routing/app-route-graph.js";
3
3
  //#region src/server/app-browser-interception-context.d.ts
4
4
  type ResolveManifestNavigationInterceptionContextOptions = {
5
5
  basePath: string;
6
+ currentMatchedPathname?: string | null;
6
7
  currentPathname: string;
7
8
  routeManifest: RouteManifest | null;
8
9
  targetPathname: string;
@@ -29,13 +29,15 @@ function resolveManifestNavigationInterceptionContext(options) {
29
29
  function resolveMiddlewareRewriteNavigationInterceptionContext(options) {
30
30
  if (options.routeManifest === null) return null;
31
31
  const currentPathname = stripBasePath(options.currentPathname, options.basePath);
32
+ const currentMatchedPathname = options.currentMatchedPathname ? stripBasePath(options.currentMatchedPathname, options.basePath) : null;
32
33
  const targetPathname = stripBasePath(options.targetPathname, options.basePath);
33
34
  const sourceParts = splitPathnameForRouteMatch(currentPathname);
35
+ const matchedSourceParts = currentMatchedPathname ? splitPathnameForRouteMatch(currentMatchedPathname) : null;
34
36
  const targetParts = splitPathnameForRouteMatch(targetPathname);
35
37
  for (const interception of options.routeManifest.segmentGraph.interceptions.values()) {
36
- if (!matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) continue;
37
38
  if (!matchRoutePatternWithOptionalDynamicSegments(targetParts, interception.targetPatternParts)) continue;
38
- return currentPathname;
39
+ if (matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) return currentPathname;
40
+ if (currentMatchedPathname !== null && matchedSourceParts !== null && matchRoutePatternPrefix(matchedSourceParts, interception.sourcePatternParts)) return currentMatchedPathname;
39
41
  }
40
42
  return null;
41
43
  }
@@ -77,7 +77,9 @@ type BrowserNavigationController = {
77
77
  targetHistoryIndex?: number | null;
78
78
  targetHref: string;
79
79
  navId: number;
80
+ navigationCommitKind?: "authoritative" | "detached";
80
81
  visibleCommitMode?: NavigationRuntimeVisibleCommitMode;
82
+ onCommittedState?: (state: AppRouterState) => void;
81
83
  }): Promise<NavigationPayloadOutcome>;
82
84
  commitSameUrlNavigatePayload(nextElements: Promise<AppElements>, navigationSnapshot: ClientNavigationRenderSnapshot, returnValue?: {
83
85
  ok: boolean;
@@ -1,8 +1,8 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
3
3
  import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
4
+ import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
4
5
  import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
5
- import { shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
6
6
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit } from "./app-browser-state.js";
7
7
  import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
8
8
  import { startTransition, useInsertionEffect, useLayoutEffect } from "react";
@@ -73,6 +73,9 @@ function createAppBrowserNavigationController(deps = {}) {
73
73
  const syncHistoryStatePreviousNextUrl = deps.syncHistoryStatePreviousNextUrl ?? (() => {});
74
74
  let nextNavigationRenderId = 0;
75
75
  let activeNavigationId = 0;
76
+ let pendingUserNavigationId = null;
77
+ let pendingUserNavigationLane = null;
78
+ let latestHmrUpdateId = 0;
76
79
  const pendingNavigationCommits = /* @__PURE__ */ new Map();
77
80
  const pendingNavigationFailureTargets = /* @__PURE__ */ new Map();
78
81
  const pendingNavigationPrePaintEffects = /* @__PURE__ */ new Map();
@@ -105,7 +108,10 @@ function createAppBrowserNavigationController(deps = {}) {
105
108
  resolveReady?.();
106
109
  }
107
110
  function beginNavigation() {
111
+ latestHmrUpdateId += 1;
108
112
  activeNavigationId += 1;
113
+ pendingUserNavigationId = activeNavigationId;
114
+ pendingUserNavigationLane = null;
109
115
  return activeNavigationId;
110
116
  }
111
117
  function getActiveNavigationId() {
@@ -149,13 +155,11 @@ function createAppBrowserNavigationController(deps = {}) {
149
155
  }
150
156
  function finalizeNavigation(navId, pending) {
151
157
  settlePendingBrowserRouterState(pending);
152
- if (isCurrentNavigation(navId)) clearPendingPathname(navId);
153
- }
154
- function resolvePendingBrowserRouterState(pending, commit) {
155
- if (!pending || pending.settled) return;
156
- pending.settled = true;
157
- pending.resolve(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
158
- if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
158
+ if (isCurrentNavigation(navId)) {
159
+ pendingUserNavigationId = null;
160
+ pendingUserNavigationLane = null;
161
+ clearPendingPathname(navId);
162
+ }
159
163
  }
160
164
  function queuePrePaintNavigationEffect(renderId, effect) {
161
165
  if (!effect) return;
@@ -181,16 +185,17 @@ function createAppBrowserNavigationController(deps = {}) {
181
185
  }
182
186
  }
183
187
  /**
184
- * Resolve all pending navigation commits with renderId <= the committed renderId.
185
- * Note: Map iteration handles concurrent deletion safely entries are visited in
186
- * insertion order and deletion doesn't affect the iterator's view of remaining entries.
187
- * This pattern is also used in drainPrePaintEffects with the same semantics.
188
+ * Settle all pending navigation renders through the supplied renderId. Only
189
+ * the exact render whose layout effect ran is a successful commit; older
190
+ * superseded renders and cleanup-only settlements resolve as no-commit.
188
191
  */
189
- function resolveCommittedNavigations(renderId) {
190
- for (const [pendingId, resolve] of pendingNavigationCommits) {
192
+ function settleNavigationCommits(renderId, committed) {
193
+ for (const [pendingId, pendingCommit] of pendingNavigationCommits) {
191
194
  if (pendingId > renderId) continue;
192
195
  pendingNavigationCommits.delete(pendingId);
193
- resolve();
196
+ const didCommit = committed && pendingId === renderId;
197
+ if (didCommit && pendingCommit.committedState !== null) pendingCommit.onCommittedState?.(pendingCommit.committedState);
198
+ pendingCommit.resolve(didCommit);
194
199
  }
195
200
  }
196
201
  function clearCommittedNavigationFailureTargets(renderId) {
@@ -201,6 +206,8 @@ function createAppBrowserNavigationController(deps = {}) {
201
206
  }
202
207
  }
203
208
  async function hmrReplaceTree(nextElements, navigationSnapshot) {
209
+ const hmrUpdateId = ++latestHmrUpdateId;
210
+ const startedDuringUserNavigation = pendingUserNavigationLane === "navigation";
204
211
  if (!hasBrowserRouterState()) return;
205
212
  const pending = await createPendingNavigationCommit({
206
213
  currentState: getBrowserRouterState(),
@@ -211,8 +218,16 @@ function createAppBrowserNavigationController(deps = {}) {
211
218
  renderId: allocateRenderId(),
212
219
  type: "replace"
213
220
  });
221
+ if (hmrUpdateId !== latestHmrUpdateId || startedDuringUserNavigation) return;
214
222
  if (!hasBrowserRouterState()) return;
215
- dispatchSynchronousVisibleCommit(approveHmrVisibleCommit(pending));
223
+ const approval = approveHmrVisibleCommit({
224
+ currentState: getBrowserRouterState(),
225
+ pending,
226
+ routeManifest: deps.getRouteManifest?.() ?? null,
227
+ targetHref: createSnapshotPathAndSearch(navigationSnapshot)
228
+ });
229
+ if (approval.approvedCommit) dispatchSynchronousVisibleCommit(approval.approvedCommit);
230
+ else if (approval.decision.disposition === "hard-navigate") performHardNavigation(createSnapshotPathAndSearch(navigationSnapshot));
216
231
  }
217
232
  function NavigationCommitSignal({ renderId, children }) {
218
233
  useInsertionEffect(() => {
@@ -220,30 +235,36 @@ function createAppBrowserNavigationController(deps = {}) {
220
235
  }, [renderId]);
221
236
  useLayoutEffect(() => {
222
237
  drainPrePaintEffects(renderId);
223
- const frame = requestAnimationFrame(() => {
224
- resolveCommittedNavigations(renderId);
225
- });
238
+ settleNavigationCommits(renderId, true);
226
239
  return () => {
227
- cancelAnimationFrame(frame);
228
- resolveCommittedNavigations(renderId);
240
+ settleNavigationCommits(renderId, false);
229
241
  };
230
242
  }, [renderId]);
231
243
  return children;
232
244
  }
233
- function dispatchApprovedVisibleCommit(commit, pendingRouterState, visibleCommitMode) {
245
+ function dispatchApprovedVisibleCommit(renderId, commit, pendingRouterState, visibleCommitMode) {
234
246
  const setter = getBrowserRouterStateSetter();
247
+ const pendingCommit = pendingNavigationCommits.get(renderId);
248
+ const captureCandidateState = (state) => {
249
+ if (pendingCommit) pendingCommit.committedState = state;
250
+ return state;
251
+ };
235
252
  if (pendingRouterState) {
236
- resolvePendingBrowserRouterState(pendingRouterState, commit);
253
+ if (pendingRouterState.settled) return;
254
+ const committedState = captureCandidateState(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
255
+ pendingRouterState.settled = true;
256
+ pendingRouterState.resolve(committedState);
257
+ if (activePendingBrowserRouterState === pendingRouterState) activePendingBrowserRouterState = null;
237
258
  return;
238
259
  }
239
260
  if (visibleCommitMode === "synchronous") {
240
261
  flushSync(() => {
241
- setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
262
+ setter(captureCandidateState(applyApprovedVisibleCommit(getBrowserRouterState(), commit)));
242
263
  });
243
264
  return;
244
265
  }
245
266
  startTransition(() => {
246
- setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
267
+ setter(captureCandidateState(applyApprovedVisibleCommit(getBrowserRouterState(), commit)));
247
268
  });
248
269
  }
249
270
  function dispatchSynchronousVisibleCommit(commit) {
@@ -280,6 +301,7 @@ function createAppBrowserNavigationController(deps = {}) {
280
301
  previousNextUrl: options.restoredState.previousNextUrl,
281
302
  rootLayoutTreePath: options.restoredState.rootLayoutTreePath,
282
303
  routeId: options.restoredState.routeId,
304
+ restoredHistorySnapshot: true,
283
305
  skippedLayoutIds: []
284
306
  };
285
307
  }
@@ -309,18 +331,25 @@ function createAppBrowserNavigationController(deps = {}) {
309
331
  lifecycleOptions?.onDiscardedRevalidation?.();
310
332
  }
311
333
  async function renderNavigationPayload(options) {
334
+ if (options.navId === pendingUserNavigationId) pendingUserNavigationLane = options.operationLane;
312
335
  const renderId = allocateRenderId();
313
336
  const failureTarget = getAppNavigationFailureTarget(options.targetHref);
314
337
  if (failureTarget) pendingNavigationFailureTargets.set(renderId, failureTarget);
315
338
  let resolveCommitted;
316
339
  const committed = new Promise((resolve) => {
317
340
  resolveCommitted = resolve;
318
- pendingNavigationCommits.set(renderId, resolve);
341
+ pendingNavigationCommits.set(renderId, {
342
+ committedState: null,
343
+ onCommittedState: options.onCommittedState,
344
+ resolve
345
+ });
319
346
  });
320
347
  let snapshotActivated = false;
321
348
  try {
322
349
  const pending = await createPendingNavigationCommit({
323
350
  currentState: getBrowserRouterState(),
351
+ navigationCommitKind: options.navigationCommitKind,
352
+ navigationId: options.navId,
324
353
  nextElements: options.nextElements,
325
354
  navigationSnapshot: options.navigationSnapshot,
326
355
  operationLane: options.operationLane,
@@ -344,7 +373,7 @@ function createAppBrowserNavigationController(deps = {}) {
344
373
  pendingNavigationFailureTargets.delete(renderId);
345
374
  if (failureTarget) clearAppNavigationFailureTarget(failureTarget);
346
375
  pendingNavigationCommits.delete(renderId);
347
- resolveCommitted?.();
376
+ resolveCommitted?.(false);
348
377
  consumeAppRouterScrollIntent(options.scrollIntent ?? null);
349
378
  return "no-commit";
350
379
  }
@@ -371,17 +400,17 @@ function createAppBrowserNavigationController(deps = {}) {
371
400
  claimAppRouterScrollIntentForCommit(options.scrollIntent, renderId);
372
401
  activateNavigationSnapshot();
373
402
  snapshotActivated = true;
374
- dispatchApprovedVisibleCommit(approvedCommit, options.pendingRouterState, options.visibleCommitMode ?? "transition");
403
+ dispatchApprovedVisibleCommit(renderId, approvedCommit, options.pendingRouterState, options.visibleCommitMode ?? "transition");
375
404
  } catch (error) {
376
405
  pendingNavigationFailureTargets.delete(renderId);
377
406
  pendingNavigationPrePaintEffects.delete(renderId);
378
407
  pendingNavigationCommits.delete(renderId);
379
408
  if (snapshotActivated) commitClientNavigationStateImpl(options.navId);
380
409
  settlePendingBrowserRouterState(options.pendingRouterState);
381
- resolveCommitted?.();
410
+ resolveCommitted?.(false);
382
411
  throw error;
383
412
  }
384
- return committed.then(() => "committed");
413
+ return committed.then((didCommit) => didCommit ? "committed" : "no-commit");
385
414
  }
386
415
  async function commitSameUrlNavigatePayload(nextElements, navigationSnapshot, returnValue, actionInitiationState, lifecycleOptions) {
387
416
  const currentState = actionInitiationState ?? getBrowserRouterState();
@@ -395,7 +424,7 @@ function createAppBrowserNavigationController(deps = {}) {
395
424
  navigationSnapshot,
396
425
  nextElements,
397
426
  renderId: allocateRenderId(),
398
- operationLane: "server-action",
427
+ operationLane: resolveServerActionOperationLane(lifecycleOptions?.revalidation ?? "none"),
399
428
  payloadOrigin: FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN,
400
429
  startedNavigationId,
401
430
  routeManifest: getRouteManifest(),
@@ -0,0 +1,32 @@
1
+ import { AppElements, AppWireElements } from "./app-elements-wire.js";
2
+ import { navigationPlanner } from "./navigation-planner.js";
3
+ import { AppBrowserServerActionResult, ServerActionRevalidationKind } from "./app-browser-action-result.js";
4
+ import { AppRouterState } from "./app-browser-state.js";
5
+
6
+ //#region src/server/app-browser-server-action-client.d.ts
7
+ type ServerActionResult = AppBrowserServerActionResult<AppWireElements>;
8
+ type ClientServerActionInitiation = {
9
+ href: string;
10
+ navigationId: number;
11
+ path: string;
12
+ routerState: AppRouterState;
13
+ };
14
+ type ActionRedirectTarget = {
15
+ href: string;
16
+ type: string;
17
+ status: number;
18
+ };
19
+ type ClientServerActionDeps = {
20
+ basePath: string;
21
+ clearClientNavigationCaches(): void;
22
+ clientRscCompatibilityId: string | null;
23
+ commitSameUrlNavigatePayload(elements: Promise<AppElements>, actionInitiation: ClientServerActionInitiation, returnValue: ServerActionResult["returnValue"] | undefined, revalidation: ServerActionRevalidationKind): Promise<unknown>;
24
+ navigationPlanner: typeof navigationPlanner;
25
+ performHardNavigation(url: string, historyMode?: "assign" | "replace"): void;
26
+ renderRedirectPayload(elements: AppElements, target: ActionRedirectTarget, actionInitiation: ClientServerActionInitiation, revalidation: ServerActionRevalidationKind): void;
27
+ syncCurrentHistoryState(previousNextUrl: string | null, bfcacheIds: Readonly<Record<string, string>>): void;
28
+ syncServerActionHttpFallbackHead(status: number | null): void;
29
+ };
30
+ declare function invokeClientServerAction(id: string, args: unknown[], actionInitiation: ClientServerActionInitiation, deps: ClientServerActionDeps): Promise<unknown>;
31
+ //#endregion
32
+ export { ClientServerActionDeps, ClientServerActionInitiation, invokeClientServerAction };
@@ -0,0 +1,127 @@
1
+ import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER } from "./headers.js";
2
+ import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
3
+ import { AppElementsWire } from "./app-elements-wire.js";
4
+ import "./app-elements.js";
5
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl } from "./app-rsc-cache-busting.js";
6
+ import { createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldSyncServerActionHttpFallbackHead } from "./app-browser-action-result.js";
7
+ import { resolveServerActionRequestState } from "./app-browser-state.js";
8
+ import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
9
+ import { throwOnServerActionNotFound } from "./server-action-not-found.js";
10
+ import { createFromFetch, createTemporaryReferenceSet, encodeReply } from "@vitejs/plugin-rsc/browser";
11
+ //#region src/server/app-browser-server-action-client.ts
12
+ function resolveActionRedirectTarget(response, performHardNavigation) {
13
+ const actionRedirect = response.headers.get(ACTION_REDIRECT_HEADER);
14
+ if (!actionRedirect) return null;
15
+ if (isDangerousScheme(actionRedirect)) {
16
+ console.error(DANGEROUS_URL_BLOCK_MESSAGE);
17
+ return null;
18
+ }
19
+ try {
20
+ let redirectUrl;
21
+ if (actionRedirect.startsWith("/") || /^[a-z]+:/i.test(actionRedirect)) redirectUrl = new URL(actionRedirect, window.location.href);
22
+ else {
23
+ const baseParsed = new URL(window.location.href);
24
+ let baseDir = baseParsed.pathname;
25
+ if (!baseDir.endsWith("/")) baseDir += "/";
26
+ redirectUrl = new URL(actionRedirect, `${baseParsed.origin}${baseDir}${baseParsed.search}`);
27
+ }
28
+ if (redirectUrl.origin !== window.location.origin) {
29
+ performHardNavigation(actionRedirect);
30
+ return null;
31
+ }
32
+ const statusHeader = response.headers.get(ACTION_REDIRECT_STATUS_HEADER);
33
+ return {
34
+ href: redirectUrl.href,
35
+ type: response.headers.get("x-action-redirect-type") ?? "push",
36
+ status: statusHeader ? parseInt(statusHeader, 10) : 307
37
+ };
38
+ } catch {
39
+ performHardNavigation(actionRedirect);
40
+ return null;
41
+ }
42
+ }
43
+ var ServerActionRedirectError = class extends Error {
44
+ digest;
45
+ handled = true;
46
+ constructor(target) {
47
+ super("NEXT_REDIRECT");
48
+ const redirectUrl = new URL(target.href, window.location.href);
49
+ const redirectHref = redirectUrl.pathname + redirectUrl.search + redirectUrl.hash;
50
+ const redirectType = target.type === "push" ? "push" : "replace";
51
+ this.digest = `NEXT_REDIRECT;${redirectType};${encodeURIComponent(redirectHref)};${target.status};`;
52
+ }
53
+ };
54
+ async function invokeClientServerAction(id, args, actionInitiation, deps) {
55
+ deps.syncServerActionHttpFallbackHead(null);
56
+ const temporaryReferences = createTemporaryReferenceSet();
57
+ deps.syncCurrentHistoryState(actionInitiation.routerState.previousNextUrl, actionInitiation.routerState.bfcacheIds);
58
+ const body = await encodeReply(args, { temporaryReferences });
59
+ const headers = resolveServerActionRequestState({
60
+ actionId: id,
61
+ basePath: deps.basePath,
62
+ elements: actionInitiation.routerState.elements,
63
+ previousNextUrl: actionInitiation.routerState.previousNextUrl
64
+ }).headers;
65
+ const fetchResponse = await fetch(createServerActionRequestUrl(actionInitiation.path), {
66
+ method: "POST",
67
+ headers,
68
+ body
69
+ });
70
+ throwOnServerActionNotFound(fetchResponse, id);
71
+ const hasActionRedirect = fetchResponse.headers.has(ACTION_REDIRECT_HEADER);
72
+ const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse, (url, historyMode) => deps.performHardNavigation(url, historyMode));
73
+ if (hasActionRedirect && !actionRedirectTarget) return void 0;
74
+ const actionResultFacts = createServerActionResultFacts({
75
+ actionRedirectHref: actionRedirectTarget?.href ?? null,
76
+ actionRedirectType: actionRedirectTarget?.type ?? null,
77
+ clientCompatibilityId: deps.clientRscCompatibilityId,
78
+ compatibilityIdHeader: fetchResponse.headers.get(VINEXT_RSC_COMPATIBILITY_ID_HEADER),
79
+ contentTypeHeader: fetchResponse.headers.get("content-type"),
80
+ currentHref: actionInitiation.href,
81
+ origin: window.location.origin,
82
+ responseUrl: fetchResponse.url
83
+ });
84
+ const fetchResponseIsRsc = actionResultFacts.isRscContentType;
85
+ if (applyServerActionResultDecision(deps.navigationPlanner.classifyServerActionResult(actionResultFacts), () => deps.clearClientNavigationCaches(), (url, historyMode) => deps.performHardNavigation(url, historyMode))) return;
86
+ const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
87
+ if (revalidation !== "none") deps.clearClientNavigationCaches();
88
+ const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
89
+ if (invalidResponseError) throw invalidResponseError;
90
+ if (actionRedirectTarget && !fetchResponseIsRsc) {
91
+ deps.performHardNavigation(actionRedirectTarget.href);
92
+ return;
93
+ }
94
+ const flightResponse = fetchResponse.status === 303 ? new Response(fetchResponse.body, {
95
+ headers: fetchResponse.headers,
96
+ status: 200,
97
+ statusText: "OK"
98
+ }) : fetchResponse;
99
+ const result = await createFromFetch(Promise.resolve(flightResponse), { temporaryReferences });
100
+ if (revalidation === "none" && shouldClearClientNavigationCachesForServerActionResult(result, revalidation)) deps.clearClientNavigationCaches();
101
+ if (actionRedirectTarget) {
102
+ if (isServerActionResult(result) && result.root !== void 0) {
103
+ deps.renderRedirectPayload(AppElementsWire.decode(result.root), actionRedirectTarget, actionInitiation, revalidation);
104
+ throw new ServerActionRedirectError(actionRedirectTarget);
105
+ }
106
+ deps.performHardNavigation(actionRedirectTarget.href);
107
+ return;
108
+ }
109
+ deps.syncServerActionHttpFallbackHead(shouldSyncServerActionHttpFallbackHead(result) ? fetchResponse.status : null);
110
+ if (isServerActionResult(result)) {
111
+ if (result.root !== void 0) {
112
+ const returnValue = result.returnValue && !result.returnValue.ok ? {
113
+ ok: false,
114
+ data: normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status)
115
+ } : result.returnValue;
116
+ return deps.commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result.root)), actionInitiation, returnValue, revalidation);
117
+ }
118
+ if (result.returnValue) {
119
+ if (!result.returnValue.ok) throw normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status);
120
+ return result.returnValue.data;
121
+ }
122
+ return;
123
+ }
124
+ return deps.commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result)), actionInitiation, void 0, revalidation);
125
+ }
126
+ //#endregion
127
+ export { invokeClientServerAction };
@@ -11,6 +11,8 @@ import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
11
11
  type OperationRecordBase = {
12
12
  id: number;
13
13
  lane: OperationLane;
14
+ navigationCommitKind?: "authoritative" | "detached";
15
+ navigationId?: number;
14
16
  startedVisibleCommitVersion: number;
15
17
  };
16
18
  type PendingOperationRecord = OperationRecordBase & {
@@ -64,18 +66,23 @@ type PendingNavigationCommit = {
64
66
  previousNextUrl: string | null;
65
67
  rootLayoutTreePath: string | null;
66
68
  routeId: string;
69
+ restoredHistorySnapshot?: boolean;
67
70
  skippedLayoutIds: readonly string[];
68
71
  };
69
72
  type AppNavigationPayloadOrigin = Readonly<{
73
+ origin: "committed-cache";
74
+ } | {
70
75
  origin: "fresh";
71
76
  } | {
72
77
  origin: "visited-cache";
73
78
  }>;
79
+ declare const COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN: AppNavigationPayloadOrigin;
74
80
  declare const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN: AppNavigationPayloadOrigin;
75
81
  declare const VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN: AppNavigationPayloadOrigin;
76
82
  type PendingNavigationCommitDisposition = "dispatch" | "hard-navigate" | "skip";
77
83
  type CacheRestorableAppPayloadMetadata = Readonly<{
78
84
  cacheEntryReuseProof?: CacheEntryReuseProof;
85
+ dynamicStaleTimeSeconds?: number;
79
86
  skippedLayoutIds: readonly string[];
80
87
  }>;
81
88
  type DispatchPendingNavigationCommitDispositionDecision = {
@@ -91,6 +98,7 @@ type NonDispatchPendingNavigationCommitDispositionDecision = {
91
98
  trace: NavigationTrace;
92
99
  };
93
100
  type PendingNavigationCommitDispositionDecision = DispatchPendingNavigationCommitDispositionDecision | NonDispatchPendingNavigationCommitDispositionDecision;
101
+ declare function isCompleteAppPayloadMetadata(metadata: CacheRestorableAppPayloadMetadata): boolean;
94
102
  declare function isCacheRestorableAppPayloadMetadata(metadata: CacheRestorableAppPayloadMetadata): metadata is CacheRestorableAppPayloadMetadata & {
95
103
  cacheEntryReuseProof: CacheEntryReuseProof;
96
104
  };
@@ -126,6 +134,8 @@ declare function resolvePendingNavigationCommitDispositionDecision(options: {
126
134
  }): PendingNavigationCommitDispositionDecision;
127
135
  declare function createPendingNavigationCommit(options: {
128
136
  currentState: AppRouterState;
137
+ navigationCommitKind?: "authoritative" | "detached";
138
+ navigationId?: number;
129
139
  nextElements: Promise<AppElements>;
130
140
  navigationSnapshot: ClientNavigationRenderSnapshot;
131
141
  operationLane: OperationLane;
@@ -137,4 +147,4 @@ declare function createPendingNavigationCommit(options: {
137
147
  type: "navigate" | "replace" | "traverse";
138
148
  }): Promise<PendingNavigationCommit>;
139
149
  //#endregion
140
- export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, type BfcacheIdMap, CommittedOperationRecord, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, type HistoryTraversalIntent, type OperationLane, PendingNavigationCommit, PendingOperationRecord, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
150
+ export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, type BfcacheIdMap, COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, CommittedOperationRecord, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, type HistoryTraversalIntent, type OperationLane, PendingNavigationCommit, PendingOperationRecord, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
@@ -6,28 +6,35 @@ import { AppElementsWire } from "./app-elements-wire.js";
6
6
  import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
7
7
  import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
8
8
  import { createCacheEntryReuseProof } from "./cache-proof.js";
9
+ import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
9
10
  import { createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
10
11
  import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
11
12
  import { verifyOperationTokenForCommit } from "./operation-token.js";
12
13
  import { navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts } from "./navigation-planner.js";
13
14
  import { createSnapshotPathAndSearch } from "../shims/navigation.js";
14
- import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements } from "./app-bfcache-identity.js";
15
15
  //#region src/server/app-browser-state.ts
16
+ const COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "committed-cache" };
16
17
  const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "fresh" };
17
18
  const VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "visited-cache" };
18
19
  function createOperationRecord(options) {
19
20
  return {
20
21
  id: options.id,
21
22
  lane: options.lane,
23
+ ...options.navigationCommitKind !== void 0 ? { navigationCommitKind: options.navigationCommitKind } : {},
24
+ ...options.navigationId !== void 0 ? { navigationId: options.navigationId } : {},
22
25
  startedVisibleCommitVersion: options.startedVisibleCommitVersion,
23
26
  state: "pending"
24
27
  };
25
28
  }
29
+ function isCompleteAppPayloadMetadata(metadata) {
30
+ return metadata.skippedLayoutIds.length === 0;
31
+ }
26
32
  function isCacheRestorableAppPayloadMetadata(metadata) {
27
- return metadata.cacheEntryReuseProof !== void 0 && metadata.skippedLayoutIds.length === 0;
33
+ return metadata.cacheEntryReuseProof !== void 0 && isCompleteAppPayloadMetadata(metadata);
28
34
  }
29
35
  function requiresCacheEntryReuseProof(origin) {
30
36
  switch (origin.origin) {
37
+ case "committed-cache":
31
38
  case "fresh": return false;
32
39
  case "visited-cache": return true;
33
40
  default: throw new Error("[vinext] Unknown App Router payload origin: " + String(origin));
@@ -70,14 +77,21 @@ function resolveServerActionRequestState(options) {
70
77
  function resolvePendingNavigationCommitDispositionDecision(options) {
71
78
  const traceFields = createPendingNavigationTraceFields(options);
72
79
  const targetSnapshot = createPendingRouteSnapshot(options.pending);
73
- const verdict = verifyOperationTokenForCommit(createPendingNavigationOperationToken({
80
+ const token = createPendingNavigationOperationToken({
74
81
  pending: options.pending,
75
82
  routeManifest: options.routeManifest ?? null,
76
83
  startedNavigationId: options.startedNavigationId,
77
84
  targetSnapshot
78
- }), {
85
+ });
86
+ if (options.pending.action.operation.navigationCommitKind === "detached" && options.currentState.activeOperation?.navigationId === options.startedNavigationId && options.currentState.activeOperation.navigationCommitKind === "authoritative") return {
87
+ disposition: "skip",
88
+ preserveElementIds: [],
89
+ trace: createNavigationTrace(NavigationTraceReasonCodes.staleOperation, traceFields)
90
+ };
91
+ const visibleCommitVersion = options.currentState.activeOperation?.navigationId === options.startedNavigationId && options.currentState.activeOperation.navigationCommitKind === "detached" && options.pending.action.operation.navigationCommitKind === "authoritative" ? options.pending.action.operation.startedVisibleCommitVersion : options.currentState.visibleCommitVersion;
92
+ const verdict = verifyOperationTokenForCommit(token, {
79
93
  activeNavigationId: options.activeNavigationId,
80
- visibleCommitVersion: options.currentState.visibleCommitVersion
94
+ visibleCommitVersion
81
95
  });
82
96
  if (!verdict.authorized) return {
83
97
  disposition: "skip",
@@ -126,7 +140,7 @@ function createMountedParallelSlotSnapshots(elements) {
126
140
  }
127
141
  function createVisibleRouteSnapshot(state) {
128
142
  const displayUrl = createSnapshotPathAndSearch(state.navigationSnapshot);
129
- const matchedUrl = normalizeNavigationSnapshotMatchedUrl(state.navigationSnapshot.pathname);
143
+ const matchedUrl = state.interception?.targetMatchedUrl ?? normalizeNavigationSnapshotMatchedUrl(state.navigationSnapshot.pathname);
130
144
  return {
131
145
  displayUrl,
132
146
  interception: state.interception,
@@ -144,7 +158,7 @@ function createVisibleRouteSnapshot(state) {
144
158
  }
145
159
  function createPendingRouteSnapshot(pending) {
146
160
  const displayUrl = createSnapshotPathAndSearch(pending.action.navigationSnapshot);
147
- const matchedUrl = normalizeNavigationSnapshotMatchedUrl(pending.action.navigationSnapshot.pathname);
161
+ const matchedUrl = pending.action.interception?.targetMatchedUrl ?? normalizeNavigationSnapshotMatchedUrl(pending.action.navigationSnapshot.pathname);
148
162
  return {
149
163
  displayUrl,
150
164
  interception: pending.action.interception,
@@ -188,6 +202,7 @@ function planPendingRootBoundaryFlightResponse(options) {
188
202
  kind: "flightResponseArrived",
189
203
  result: {
190
204
  ...cacheEntryReuseProof ? { cacheEntryReuseProof } : {},
205
+ ...options.pending.restoredHistorySnapshot ? { restoredHistorySnapshot: true } : {},
191
206
  href: options.targetHref ?? options.targetSnapshot.displayUrl,
192
207
  targetSnapshot: options.targetSnapshot
193
208
  },
@@ -292,6 +307,8 @@ async function createPendingNavigationCommit(options) {
292
307
  operation: createOperationRecord({
293
308
  id: options.renderId,
294
309
  lane: options.operationLane,
310
+ navigationCommitKind: options.navigationCommitKind,
311
+ navigationId: options.navigationId,
295
312
  startedVisibleCommitVersion: options.currentState.visibleCommitVersion
296
313
  }),
297
314
  previousNextUrl,
@@ -312,4 +329,4 @@ async function createPendingNavigationCommit(options) {
312
329
  };
313
330
  }
314
331
  //#endregion
315
- export { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
332
+ export { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
@@ -49,7 +49,12 @@ type ClassifiedPendingNavigationCommit = {
49
49
  trace: NavigationTrace;
50
50
  };
51
51
  declare function applyApprovedVisibleCommit(state: AppRouterState, commit: ApprovedVisibleCommit): AppRouterState;
52
- declare function approveHmrVisibleCommit(pending: PendingNavigationCommit): ApprovedVisibleCommit;
52
+ declare function approveHmrVisibleCommit(options: {
53
+ currentState: AppRouterState;
54
+ pending: PendingNavigationCommit;
55
+ routeManifest?: RouteManifest | null;
56
+ targetHref: string;
57
+ }): CommitApproval;
53
58
  declare function approvePendingNavigationCommit(options: {
54
59
  activeNavigationId: number;
55
60
  currentState: AppRouterState;