vinext 0.0.51 → 0.0.52

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 (307) hide show
  1. package/dist/build/precompress.d.ts +7 -7
  2. package/dist/build/precompress.js +18 -17
  3. package/dist/build/precompress.js.map +1 -1
  4. package/dist/build/prerender.d.ts +3 -14
  5. package/dist/build/prerender.js +40 -40
  6. package/dist/build/prerender.js.map +1 -1
  7. package/dist/check.js +4 -0
  8. package/dist/check.js.map +1 -1
  9. package/dist/cli-args.d.ts +1 -0
  10. package/dist/cli-args.js +5 -0
  11. package/dist/cli-args.js.map +1 -1
  12. package/dist/cli.js +39 -0
  13. package/dist/cli.js.map +1 -1
  14. package/dist/client/navigation-runtime.d.ts +47 -0
  15. package/dist/client/navigation-runtime.js +156 -0
  16. package/dist/client/navigation-runtime.js.map +1 -0
  17. package/dist/client/pages-router-link-navigation.d.ts +26 -0
  18. package/dist/client/pages-router-link-navigation.js +14 -0
  19. package/dist/client/pages-router-link-navigation.js.map +1 -0
  20. package/dist/client/vinext-next-data.d.ts +12 -2
  21. package/dist/client/vinext-next-data.js +50 -1
  22. package/dist/client/vinext-next-data.js.map +1 -0
  23. package/dist/cloudflare/kv-cache-handler.js +2 -1
  24. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  25. package/dist/config/config-matchers.d.ts +63 -16
  26. package/dist/config/config-matchers.js +143 -8
  27. package/dist/config/config-matchers.js.map +1 -1
  28. package/dist/config/next-config.d.ts +20 -2
  29. package/dist/config/next-config.js +11 -1
  30. package/dist/config/next-config.js.map +1 -1
  31. package/dist/deploy.js +101 -39
  32. package/dist/deploy.js.map +1 -1
  33. package/dist/entries/app-browser-entry.js +9 -3
  34. package/dist/entries/app-browser-entry.js.map +1 -1
  35. package/dist/entries/app-rsc-entry.js +53 -13
  36. package/dist/entries/app-rsc-entry.js.map +1 -1
  37. package/dist/entries/app-rsc-manifest.d.ts +1 -0
  38. package/dist/entries/app-rsc-manifest.js +53 -6
  39. package/dist/entries/app-rsc-manifest.js.map +1 -1
  40. package/dist/entries/app-ssr-entry.d.ts +3 -3
  41. package/dist/entries/app-ssr-entry.js +4 -4
  42. package/dist/entries/app-ssr-entry.js.map +1 -1
  43. package/dist/entries/pages-client-entry.js +18 -2
  44. package/dist/entries/pages-client-entry.js.map +1 -1
  45. package/dist/entries/pages-server-entry.js +58 -8
  46. package/dist/entries/pages-server-entry.js.map +1 -1
  47. package/dist/entries/runtime-entry-module.d.ts +2 -1
  48. package/dist/entries/runtime-entry-module.js +9 -3
  49. package/dist/entries/runtime-entry-module.js.map +1 -1
  50. package/dist/index.js +132 -40
  51. package/dist/index.js.map +1 -1
  52. package/dist/plugins/css-data-url.d.ts +7 -0
  53. package/dist/plugins/css-data-url.js +81 -0
  54. package/dist/plugins/css-data-url.js.map +1 -0
  55. package/dist/plugins/fonts.js +5 -3
  56. package/dist/plugins/fonts.js.map +1 -1
  57. package/dist/plugins/middleware-server-only.d.ts +54 -0
  58. package/dist/plugins/middleware-server-only.js +91 -0
  59. package/dist/plugins/middleware-server-only.js.map +1 -0
  60. package/dist/plugins/optimize-imports.js +4 -4
  61. package/dist/plugins/optimize-imports.js.map +1 -1
  62. package/dist/plugins/strip-server-exports.js +5 -8
  63. package/dist/plugins/strip-server-exports.js.map +1 -1
  64. package/dist/routing/app-route-graph.d.ts +20 -1
  65. package/dist/routing/app-route-graph.js +58 -6
  66. package/dist/routing/app-route-graph.js.map +1 -1
  67. package/dist/routing/app-router.d.ts +2 -2
  68. package/dist/routing/app-router.js +2 -2
  69. package/dist/routing/app-router.js.map +1 -1
  70. package/dist/routing/utils.d.ts +2 -1
  71. package/dist/routing/utils.js +4 -1
  72. package/dist/routing/utils.js.map +1 -1
  73. package/dist/server/api-handler.js +139 -37
  74. package/dist/server/api-handler.js.map +1 -1
  75. package/dist/server/app-browser-entry.js +293 -149
  76. package/dist/server/app-browser-entry.js.map +1 -1
  77. package/dist/server/app-browser-interception-context.d.ts +24 -0
  78. package/dist/server/app-browser-interception-context.js +32 -0
  79. package/dist/server/app-browser-interception-context.js.map +1 -0
  80. package/dist/server/app-browser-navigation-controller.d.ts +3 -1
  81. package/dist/server/app-browser-navigation-controller.js +5 -1
  82. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  83. package/dist/server/app-browser-rsc-redirect.d.ts +2 -1
  84. package/dist/server/app-browser-rsc-redirect.js +2 -2
  85. package/dist/server/app-browser-rsc-redirect.js.map +1 -1
  86. package/dist/server/app-browser-state.d.ts +18 -1
  87. package/dist/server/app-browser-state.js +19 -1
  88. package/dist/server/app-browser-state.js.map +1 -1
  89. package/dist/server/app-browser-stream.d.ts +5 -14
  90. package/dist/server/app-browser-stream.js +13 -7
  91. package/dist/server/app-browser-stream.js.map +1 -1
  92. package/dist/server/app-browser-visible-commit.d.ts +2 -1
  93. package/dist/server/app-browser-visible-commit.js +1 -0
  94. package/dist/server/app-browser-visible-commit.js.map +1 -1
  95. package/dist/server/app-elements-wire.d.ts +10 -5
  96. package/dist/server/app-elements-wire.js +84 -2
  97. package/dist/server/app-elements-wire.js.map +1 -1
  98. package/dist/server/app-elements.d.ts +3 -2
  99. package/dist/server/app-elements.js +3 -2
  100. package/dist/server/app-elements.js.map +1 -1
  101. package/dist/server/app-fallback-renderer.js +5 -3
  102. package/dist/server/app-fallback-renderer.js.map +1 -1
  103. package/dist/server/app-middleware.d.ts +13 -0
  104. package/dist/server/app-middleware.js +3 -1
  105. package/dist/server/app-middleware.js.map +1 -1
  106. package/dist/server/app-optimistic-routing.d.ts +54 -0
  107. package/dist/server/app-optimistic-routing.js +200 -0
  108. package/dist/server/app-optimistic-routing.js.map +1 -0
  109. package/dist/server/app-page-cache.d.ts +13 -1
  110. package/dist/server/app-page-cache.js +61 -6
  111. package/dist/server/app-page-cache.js.map +1 -1
  112. package/dist/server/app-page-dispatch.d.ts +2 -0
  113. package/dist/server/app-page-dispatch.js +28 -1
  114. package/dist/server/app-page-dispatch.js.map +1 -1
  115. package/dist/server/app-page-element-builder.js +2 -1
  116. package/dist/server/app-page-element-builder.js.map +1 -1
  117. package/dist/server/app-page-execution.d.ts +28 -1
  118. package/dist/server/app-page-execution.js +89 -4
  119. package/dist/server/app-page-execution.js.map +1 -1
  120. package/dist/server/app-page-head.js +21 -2
  121. package/dist/server/app-page-head.js.map +1 -1
  122. package/dist/server/app-page-probe.js +1 -1
  123. package/dist/server/app-page-render.d.ts +2 -0
  124. package/dist/server/app-page-render.js +2 -1
  125. package/dist/server/app-page-render.js.map +1 -1
  126. package/dist/server/app-page-response.js +4 -3
  127. package/dist/server/app-page-response.js.map +1 -1
  128. package/dist/server/app-page-route-wiring.js +17 -10
  129. package/dist/server/app-page-route-wiring.js.map +1 -1
  130. package/dist/server/app-page-stream.d.ts +3 -0
  131. package/dist/server/app-page-stream.js +1 -0
  132. package/dist/server/app-page-stream.js.map +1 -1
  133. package/dist/server/app-prerender-static-params.d.ts +2 -1
  134. package/dist/server/app-prerender-static-params.js +44 -8
  135. package/dist/server/app-prerender-static-params.js.map +1 -1
  136. package/dist/server/app-route-handler-cache.d.ts +2 -2
  137. package/dist/server/app-route-handler-cache.js +3 -2
  138. package/dist/server/app-route-handler-cache.js.map +1 -1
  139. package/dist/server/app-route-handler-dispatch.d.ts +6 -1
  140. package/dist/server/app-route-handler-dispatch.js +1 -1
  141. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  142. package/dist/server/app-route-handler-execution.d.ts +17 -2
  143. package/dist/server/app-route-handler-execution.js.map +1 -1
  144. package/dist/server/app-route-handler-response.js +5 -4
  145. package/dist/server/app-route-handler-response.js.map +1 -1
  146. package/dist/server/app-router-entry.js +6 -2
  147. package/dist/server/app-router-entry.js.map +1 -1
  148. package/dist/server/app-rsc-handler.d.ts +9 -1
  149. package/dist/server/app-rsc-handler.js +32 -14
  150. package/dist/server/app-rsc-handler.js.map +1 -1
  151. package/dist/server/app-rsc-render-mode.d.ts +4 -3
  152. package/dist/server/app-rsc-render-mode.js +7 -1
  153. package/dist/server/app-rsc-render-mode.js.map +1 -1
  154. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  155. package/dist/server/app-rsc-request-normalization.js +4 -1
  156. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  157. package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
  158. package/dist/server/app-rsc-response-finalizer.js +10 -3
  159. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  160. package/dist/server/app-rsc-route-matching.js +2 -2
  161. package/dist/server/app-rsc-route-matching.js.map +1 -1
  162. package/dist/server/app-server-action-execution.js +1 -1
  163. package/dist/server/app-ssr-entry.d.ts +2 -0
  164. package/dist/server/app-ssr-entry.js +56 -55
  165. package/dist/server/app-ssr-entry.js.map +1 -1
  166. package/dist/server/app-ssr-stream.d.ts +6 -1
  167. package/dist/server/app-ssr-stream.js +17 -3
  168. package/dist/server/app-ssr-stream.js.map +1 -1
  169. package/dist/server/artifact-compatibility.d.ts +1 -1
  170. package/dist/server/artifact-compatibility.js.map +1 -1
  171. package/dist/server/cache-headers.d.ts +7 -0
  172. package/dist/server/cache-headers.js +19 -0
  173. package/dist/server/cache-headers.js.map +1 -0
  174. package/dist/server/cache-proof.d.ts +49 -3
  175. package/dist/server/cache-proof.js +78 -22
  176. package/dist/server/cache-proof.js.map +1 -1
  177. package/dist/server/client-reuse-manifest.d.ts +99 -0
  178. package/dist/server/client-reuse-manifest.js +212 -0
  179. package/dist/server/client-reuse-manifest.js.map +1 -0
  180. package/dist/server/default-global-error-module.d.ts +20 -0
  181. package/dist/server/default-global-error-module.js +20 -0
  182. package/dist/server/default-global-error-module.js.map +1 -0
  183. package/dist/server/dev-server.d.ts +9 -1
  184. package/dist/server/dev-server.js +76 -29
  185. package/dist/server/dev-server.js.map +1 -1
  186. package/dist/server/edge-api-runtime.d.ts +5 -0
  187. package/dist/server/edge-api-runtime.js +8 -0
  188. package/dist/server/edge-api-runtime.js.map +1 -0
  189. package/dist/server/headers.d.ts +18 -1
  190. package/dist/server/headers.js +18 -1
  191. package/dist/server/headers.js.map +1 -1
  192. package/dist/server/http-error-responses.d.ts +16 -1
  193. package/dist/server/http-error-responses.js +21 -1
  194. package/dist/server/http-error-responses.js.map +1 -1
  195. package/dist/server/isr-cache.d.ts +6 -2
  196. package/dist/server/isr-cache.js +20 -4
  197. package/dist/server/isr-cache.js.map +1 -1
  198. package/dist/server/middleware-runtime.d.ts +15 -0
  199. package/dist/server/middleware-runtime.js +59 -7
  200. package/dist/server/middleware-runtime.js.map +1 -1
  201. package/dist/server/middleware.d.ts +1 -1
  202. package/dist/server/middleware.js +4 -2
  203. package/dist/server/middleware.js.map +1 -1
  204. package/dist/server/navigation-planner.d.ts +9 -3
  205. package/dist/server/navigation-planner.js +98 -25
  206. package/dist/server/navigation-planner.js.map +1 -1
  207. package/dist/server/navigation-trace.d.ts +2 -1
  208. package/dist/server/navigation-trace.js +1 -0
  209. package/dist/server/navigation-trace.js.map +1 -1
  210. package/dist/server/pages-api-route.d.ts +27 -1
  211. package/dist/server/pages-api-route.js +24 -3
  212. package/dist/server/pages-api-route.js.map +1 -1
  213. package/dist/server/pages-data-route.d.ts +77 -0
  214. package/dist/server/pages-data-route.js +97 -0
  215. package/dist/server/pages-data-route.js.map +1 -0
  216. package/dist/server/pages-i18n.d.ts +51 -1
  217. package/dist/server/pages-i18n.js +61 -1
  218. package/dist/server/pages-i18n.js.map +1 -1
  219. package/dist/server/pages-page-data.d.ts +29 -2
  220. package/dist/server/pages-page-data.js +31 -17
  221. package/dist/server/pages-page-data.js.map +1 -1
  222. package/dist/server/pages-page-response.d.ts +11 -1
  223. package/dist/server/pages-page-response.js +5 -3
  224. package/dist/server/pages-page-response.js.map +1 -1
  225. package/dist/server/prod-server.d.ts +13 -15
  226. package/dist/server/prod-server.js +109 -56
  227. package/dist/server/prod-server.js.map +1 -1
  228. package/dist/server/request-pipeline.d.ts +11 -2
  229. package/dist/server/request-pipeline.js +28 -11
  230. package/dist/server/request-pipeline.js.map +1 -1
  231. package/dist/server/seed-cache.d.ts +12 -31
  232. package/dist/server/seed-cache.js +22 -35
  233. package/dist/server/seed-cache.js.map +1 -1
  234. package/dist/server/server-action-not-found.js +8 -3
  235. package/dist/server/server-action-not-found.js.map +1 -1
  236. package/dist/server/skip-cache-proof.d.ts +41 -0
  237. package/dist/server/skip-cache-proof.js +101 -0
  238. package/dist/server/skip-cache-proof.js.map +1 -0
  239. package/dist/server/static-file-cache.d.ts +1 -1
  240. package/dist/server/static-file-cache.js +7 -6
  241. package/dist/server/static-file-cache.js.map +1 -1
  242. package/dist/shims/client-locale.d.ts +15 -0
  243. package/dist/shims/client-locale.js +13 -0
  244. package/dist/shims/client-locale.js.map +1 -0
  245. package/dist/shims/default-global-error.d.ts +32 -0
  246. package/dist/shims/default-global-error.js +181 -0
  247. package/dist/shims/default-global-error.js.map +1 -0
  248. package/dist/shims/document.d.ts +59 -3
  249. package/dist/shims/document.js +36 -5
  250. package/dist/shims/document.js.map +1 -1
  251. package/dist/shims/error-boundary.d.ts +2 -2
  252. package/dist/shims/form.js +13 -6
  253. package/dist/shims/form.js.map +1 -1
  254. package/dist/shims/link.d.ts +21 -3
  255. package/dist/shims/link.js +131 -22
  256. package/dist/shims/link.js.map +1 -1
  257. package/dist/shims/metadata.js +4 -4
  258. package/dist/shims/metadata.js.map +1 -1
  259. package/dist/shims/navigation.d.ts +8 -2
  260. package/dist/shims/navigation.js +36 -15
  261. package/dist/shims/navigation.js.map +1 -1
  262. package/dist/shims/og.d.ts +18 -2
  263. package/dist/shims/og.js +49 -1
  264. package/dist/shims/og.js.map +1 -0
  265. package/dist/shims/request-state-types.d.ts +1 -1
  266. package/dist/shims/root-params.d.ts +3 -1
  267. package/dist/shims/root-params.js +11 -3
  268. package/dist/shims/root-params.js.map +1 -1
  269. package/dist/shims/router-state.d.ts +1 -0
  270. package/dist/shims/router-state.js.map +1 -1
  271. package/dist/shims/router.d.ts +12 -5
  272. package/dist/shims/router.js +172 -22
  273. package/dist/shims/router.js.map +1 -1
  274. package/dist/shims/server.d.ts +21 -4
  275. package/dist/shims/server.js +29 -9
  276. package/dist/shims/server.js.map +1 -1
  277. package/dist/shims/slot.js +5 -1
  278. package/dist/shims/slot.js.map +1 -1
  279. package/dist/shims/unified-request-context.d.ts +1 -1
  280. package/dist/shims/url-safety.d.ts +23 -1
  281. package/dist/shims/url-safety.js +29 -2
  282. package/dist/shims/url-safety.js.map +1 -1
  283. package/dist/typegen.d.ts +10 -0
  284. package/dist/typegen.js +242 -0
  285. package/dist/typegen.js.map +1 -0
  286. package/dist/utils/asset-prefix.d.ts +33 -5
  287. package/dist/utils/asset-prefix.js +39 -6
  288. package/dist/utils/asset-prefix.js.map +1 -1
  289. package/dist/utils/cache-control-metadata.d.ts +2 -1
  290. package/dist/utils/cache-control-metadata.js +1 -3
  291. package/dist/utils/cache-control-metadata.js.map +1 -1
  292. package/dist/utils/domain-locale.d.ts +2 -1
  293. package/dist/utils/domain-locale.js +9 -1
  294. package/dist/utils/domain-locale.js.map +1 -1
  295. package/dist/utils/lazy-chunks.d.ts +1 -1
  296. package/dist/utils/lazy-chunks.js +1 -1
  297. package/dist/utils/lazy-chunks.js.map +1 -1
  298. package/dist/utils/prerender-output-paths.d.ts +15 -0
  299. package/dist/utils/prerender-output-paths.js +24 -0
  300. package/dist/utils/prerender-output-paths.js.map +1 -0
  301. package/dist/utils/query.d.ts +17 -1
  302. package/dist/utils/query.js +36 -1
  303. package/dist/utils/query.js.map +1 -1
  304. package/dist/utils/record.d.ts +5 -0
  305. package/dist/utils/record.js +8 -0
  306. package/dist/utils/record.js.map +1 -0
  307. package/package.json +11 -3
@@ -1,10 +1,11 @@
1
- import { normalizePathnameForRouteMatch } from "../routing/utils.js";
1
+ import { splitPathnameForRouteMatch } from "../routing/utils.js";
2
2
  import { matchRoutePattern, matchRoutePatternPrefix } from "../routing/route-pattern.js";
3
3
  import { compareAppElementsSlotIds } from "./app-elements-wire.js";
4
4
  import "./app-elements.js";
5
5
  import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
6
6
  //#region src/server/navigation-planner.ts
7
7
  const ROUTE_INTERCEPTION_CONTEXT_SEPARATOR = "\0";
8
+ const CACHE_ENTRY_PROOF_MISSING_CODE = "CP_CACHE_ENTRY_PROOF_MISSING";
8
9
  function createRequestWorkDecision(options) {
9
10
  const traverseFields = options.work.kind === "traverseFlight" ? { traverseDirection: options.work.direction } : {};
10
11
  return {
@@ -48,7 +49,7 @@ function getMatchedUrlPathname(matchedUrl) {
48
49
  }
49
50
  }
50
51
  function splitMatchedUrlIntoRouteParts(matchedUrl) {
51
- return normalizePathnameForRouteMatch(getMatchedUrlPathname(matchedUrl)).split("/").filter((part) => part.length > 0);
52
+ return splitPathnameForRouteMatch(getMatchedUrlPathname(matchedUrl));
52
53
  }
53
54
  function findRouteManifestRouteByMatchedUrl(routeManifest, matchedUrl) {
54
55
  const urlParts = splitMatchedUrlIntoRouteParts(matchedUrl);
@@ -95,13 +96,16 @@ function resolveRouteManifestRootLayoutTreePath(routeManifest, route) {
95
96
  }
96
97
  function resolveRouteTopologySnapshot(options) {
97
98
  const route = options.routeManifest === null ? null : findRouteManifestRouteForSnapshot(options.routeManifest, options.snapshot);
98
- if (route === null || options.routeManifest === null) return createSnapshotRouteTopology(options.snapshot);
99
+ if (route === null || options.routeManifest === null) return { kind: "unknown" };
99
100
  const shouldUseManifestSlotBindings = options.slotBindingSource === "manifestTarget" && options.snapshot.interception === null;
100
101
  return {
101
- layoutIds: route.layoutIds,
102
- rootBoundaryId: route.rootBoundaryId,
103
- rootLayoutTreePath: resolveRouteManifestRootLayoutTreePath(options.routeManifest, route),
104
- slotBindings: shouldUseManifestSlotBindings ? resolveRouteManifestSlotBindings(options.routeManifest, route) : options.snapshot.slotBindings
102
+ kind: "known",
103
+ topology: {
104
+ layoutIds: route.layoutIds,
105
+ rootBoundaryId: route.rootBoundaryId,
106
+ rootLayoutTreePath: resolveRouteManifestRootLayoutTreePath(options.routeManifest, route),
107
+ slotBindings: shouldUseManifestSlotBindings ? resolveRouteManifestSlotBindings(options.routeManifest, route) : options.snapshot.slotBindings
108
+ }
105
109
  };
106
110
  }
107
111
  function findRouteManifestInterceptionForProof(routeManifest, proof) {
@@ -135,7 +139,7 @@ function createRootBoundaryTraceFields(options) {
135
139
  });
136
140
  }
137
141
  function classifyRootBoundaryTransition(currentRootBoundaryId, nextRootBoundaryId) {
138
- if (currentRootBoundaryId === null || nextRootBoundaryId === null) return "rootBoundaryUnknownFallback";
142
+ if (currentRootBoundaryId === null || nextRootBoundaryId === null) return "rootBoundaryUnknown";
139
143
  return currentRootBoundaryId === nextRootBoundaryId ? "currentRootBoundary" : "rootBoundaryChanged";
140
144
  }
141
145
  function resolveSameLayoutAncestorPersistence(currentSnapshot, targetSnapshot) {
@@ -235,6 +239,57 @@ function createInterceptionProofRejectedDecision(options) {
235
239
  url: options.event.result.href
236
240
  };
237
241
  }
242
+ function evaluateCacheEntryReuseProof(proof) {
243
+ if (proof === void 0) return {
244
+ kind: "accepted",
245
+ decision: null
246
+ };
247
+ if (proof.decision === null) return {
248
+ kind: "rejected",
249
+ decision: null
250
+ };
251
+ if (proof.decision.canReuse) return {
252
+ kind: "accepted",
253
+ decision: proof.decision
254
+ };
255
+ return {
256
+ kind: "rejected",
257
+ decision: proof.decision
258
+ };
259
+ }
260
+ function createCacheProofRejectedTraceFields(traceFields, decision) {
261
+ if (decision === null) return {
262
+ ...traceFields,
263
+ cacheProofCode: CACHE_ENTRY_PROOF_MISSING_CODE
264
+ };
265
+ return {
266
+ ...traceFields,
267
+ cacheProofCode: decision.code,
268
+ cacheProofMode: decision.mode,
269
+ cacheProofScope: decision.scope
270
+ };
271
+ }
272
+ function createCacheProofRejectedDecision(options) {
273
+ return {
274
+ kind: "hardNavigate",
275
+ reason: "cacheProofRejected",
276
+ token: options.event.token,
277
+ trace: createNavigationTrace(NavigationTraceReasonCodes.cacheProofRejected, createCacheProofRejectedTraceFields(options.traceFields, options.rejection.decision)),
278
+ url: options.event.result.href
279
+ };
280
+ }
281
+ function createAcceptedCacheProofTraceFields(traceFields, decision) {
282
+ if (decision === null) return traceFields;
283
+ return {
284
+ ...traceFields,
285
+ cacheProofCode: decision.code,
286
+ cacheProofReuseClass: decision.reuseClass
287
+ };
288
+ }
289
+ function createCacheEntryProposalFields(decision) {
290
+ if (decision === null) return {};
291
+ return { cacheEntryReuseDecision: decision };
292
+ }
238
293
  function validateInterceptedPreservation(options) {
239
294
  const proof = options.targetSnapshot.interception;
240
295
  if (!proof) return {
@@ -293,9 +348,9 @@ function planFlightResponseArrived(options) {
293
348
  snapshot: targetSnapshot
294
349
  });
295
350
  const traceFields = createRootBoundaryTraceFields({
296
- currentRootLayoutTreePath: currentTopology.rootLayoutTreePath,
351
+ currentRootLayoutTreePath: currentTopology.kind === "known" ? currentTopology.topology.rootLayoutTreePath : null,
297
352
  event: options.event,
298
- nextRootLayoutTreePath: targetTopology.rootLayoutTreePath,
353
+ nextRootLayoutTreePath: targetTopology.kind === "known" ? targetTopology.topology.rootLayoutTreePath : null,
299
354
  state: options.state
300
355
  });
301
356
  if (options.event.token.lane === "prefetch") return {
@@ -304,22 +359,37 @@ function planFlightResponseArrived(options) {
304
359
  token: options.event.token,
305
360
  trace: createNavigationTrace(NavigationTraceReasonCodes.prefetchOnly, traceFields)
306
361
  };
362
+ const cacheEntryProofEvaluation = evaluateCacheEntryReuseProof(options.event.result.cacheEntryReuseProof);
363
+ if (cacheEntryProofEvaluation.kind === "rejected") return createCacheProofRejectedDecision({
364
+ event: options.event,
365
+ rejection: cacheEntryProofEvaluation,
366
+ traceFields
367
+ });
368
+ const acceptedCacheEntryDecision = cacheEntryProofEvaluation.decision;
369
+ const commitTraceFields = createAcceptedCacheProofTraceFields(traceFields, acceptedCacheEntryDecision);
370
+ const cacheEntryProposalFields = createCacheEntryProposalFields(acceptedCacheEntryDecision);
307
371
  if (targetSnapshot.interception !== null) {
372
+ if (currentTopology.kind === "unknown" || targetTopology.kind === "unknown") return createInterceptionProofRejectedDecision({
373
+ event: options.event,
374
+ reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,
375
+ traceFields: commitTraceFields
376
+ });
308
377
  const validation = validateInterceptedPreservation({
309
378
  currentSnapshot: options.state.visibleSnapshot,
310
- currentTopology,
379
+ currentTopology: currentTopology.topology,
311
380
  routeManifest: options.routeManifest,
312
381
  targetSnapshot,
313
- targetTopology
382
+ targetTopology: targetTopology.topology
314
383
  });
315
384
  if (validation.kind === "rejected") return createInterceptionProofRejectedDecision({
316
385
  event: options.event,
317
386
  reasonCode: validation.reasonCode,
318
- traceFields
387
+ traceFields: commitTraceFields
319
388
  });
320
389
  return {
321
390
  kind: "proposeCommit",
322
391
  proposal: {
392
+ ...cacheEntryProposalFields,
323
393
  preserveAbsentSlots: false,
324
394
  preserveElementIds: validation.preserveElementIds,
325
395
  preservePreviousSlotIds: validation.preservePreviousSlotIds,
@@ -327,48 +397,51 @@ function planFlightResponseArrived(options) {
327
397
  targetSnapshot
328
398
  },
329
399
  token: options.event.token,
330
- trace: createNavigationTrace(NavigationTraceReasonCodes.interceptedCommitCurrent, traceFields)
400
+ trace: createNavigationTrace(NavigationTraceReasonCodes.interceptedCommitCurrent, commitTraceFields)
331
401
  };
332
402
  }
333
- const transition = classifyRootBoundaryTransition(currentTopology.rootBoundaryId, targetTopology.rootBoundaryId);
403
+ const transition = currentTopology.kind === "unknown" || targetTopology.kind === "unknown" ? "rootBoundaryUnknown" : classifyRootBoundaryTransition(currentTopology.topology.rootBoundaryId, targetTopology.topology.rootBoundaryId);
334
404
  if (transition === "rootBoundaryChanged") return {
335
405
  kind: "hardNavigate",
336
406
  reason: "rootBoundaryChanged",
337
407
  token: options.event.token,
338
- trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryChanged, traceFields),
408
+ trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryChanged, commitTraceFields),
339
409
  url: options.event.result.href
340
410
  };
341
- if (transition === "rootBoundaryUnknownFallback") return {
411
+ if (transition === "rootBoundaryUnknown") return {
342
412
  kind: "proposeCommit",
343
413
  proposal: {
344
- preserveAbsentSlots: true,
414
+ ...cacheEntryProposalFields,
415
+ preserveAbsentSlots: false,
345
416
  preserveElementIds: [],
346
417
  preservePreviousSlotIds: [],
347
- reason: "rootBoundaryUnknownFallback",
418
+ reason: "unprovenTopologyFallback",
348
419
  targetSnapshot
349
420
  },
350
421
  token: options.event.token,
351
- trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryUnknown, traceFields)
422
+ trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryUnknown, commitTraceFields)
352
423
  };
424
+ if (currentTopology.kind !== "known" || targetTopology.kind !== "known") throw new Error("[vinext] Current-root navigation planning requires manifest topology");
353
425
  return {
354
426
  kind: "proposeCommit",
355
427
  proposal: {
428
+ ...cacheEntryProposalFields,
356
429
  preserveAbsentSlots: false,
357
430
  preserveElementIds: resolveCurrentRootBoundaryCommitElementPersistence({
358
- currentTopology,
431
+ currentTopology: currentTopology.topology,
359
432
  lane: options.event.token.lane,
360
- targetTopology
433
+ targetTopology: targetTopology.topology
361
434
  }),
362
435
  preservePreviousSlotIds: resolveCurrentRootBoundaryCommitSlotPersistence({
363
- currentTopology,
436
+ currentTopology: currentTopology.topology,
364
437
  lane: options.event.token.lane,
365
- targetTopology
438
+ targetTopology: targetTopology.topology
366
439
  }),
367
440
  reason: "currentRootBoundary",
368
441
  targetSnapshot
369
442
  },
370
443
  token: options.event.token,
371
- trace: createNavigationTrace(NavigationTraceReasonCodes.commitCurrent, traceFields)
444
+ trace: createNavigationTrace(NavigationTraceReasonCodes.commitCurrent, commitTraceFields)
372
445
  };
373
446
  }
374
447
  function planNavigation(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-planner.js","names":["_exhaustive"],"sources":["../../src/server/navigation-planner.ts"],"sourcesContent":["import { matchRoutePattern, matchRoutePatternPrefix } from \"../routing/route-pattern.js\";\nimport { normalizePathnameForRouteMatch } from \"../routing/utils.js\";\nimport type {\n RouteManifest,\n RouteManifestInterception,\n RouteManifestRoute,\n} from \"../routing/app-route-graph.js\";\nimport { compareAppElementsSlotIds, type AppElementsSlotBinding } from \"./app-elements.js\";\nimport {\n NavigationTraceReasonCodes,\n createNavigationLifecycleTraceFields,\n createNavigationTrace,\n type NavigationTrace,\n type NavigationTraceFields,\n type NavigationTraceReasonCode,\n} from \"./navigation-trace.js\";\n\nexport type OperationLane =\n | \"hmr\"\n | \"navigation\"\n | \"prefetch\"\n | \"refresh\"\n | \"server-action\"\n | \"traverse\";\n\nexport type OperationToken = {\n operationId: number;\n lane: OperationLane;\n baseVisibleCommitVersion: number;\n graphVersion: string | null;\n deploymentVersion: string | null;\n targetSnapshotFingerprint: string;\n cacheVariantFingerprint?: string;\n};\n\nexport type RouteSnapshotV0 = {\n interception: InterceptionSnapshotV0 | null;\n interceptionContext: string | null;\n routeId: string;\n // Ordered ancestor-first, with the root layout at index 0. Same-layout\n // persistence uses prefix comparison, so callers must preserve this order.\n layoutIds: readonly string[];\n mountedParallelSlots: readonly MountedParallelSlotSnapshotV0[];\n rootBoundaryId: string | null;\n displayUrl: string;\n matchedUrl: string;\n slotBindings: readonly ParallelSlotBindingSnapshotV0[];\n};\n\nexport type InterceptionSnapshotV0 = {\n sourceMatchedUrl: string;\n sourceRouteId: string;\n slotId: string;\n targetMatchedUrl: string;\n targetRouteId: string;\n};\n\nexport type MountedParallelSlotSnapshotV0 = {\n slotId: string;\n ownerLayoutId: string | null;\n};\n\n// Planner snapshots consume the same canonical slot-binding facts decoded from\n// AppElements metadata. Keep the alias explicit so route-state and transport\n// readers cannot drift into structurally identical but semantically separate\n// shapes.\nexport type ParallelSlotBindingSnapshotV0 = AppElementsSlotBinding;\n\nexport type NavigationPlannerStateV0 = {\n // V0 keeps a single state shape so intent events and result events can move\n // through one planner surface. flightResponseArrived uses event.token; later\n // #726 slices can split this by event kind once more result paths are routed\n // through the planner.\n nextOperationToken: OperationToken;\n // Callers that have lifecycle authority should pass the complete trace\n // context. When absent, the planner emits the stable root-boundary facts it\n // can derive from the event and visible snapshot.\n traceFields?: NavigationTraceFields;\n visibleCommitVersion: number;\n visibleSnapshot: RouteSnapshotV0;\n};\n\nexport type RefreshScope = \"visible\";\nexport type TraverseDirection = \"back\" | \"forward\" | \"unknown\";\n\nexport type NavigationEvent =\n | { kind: \"navigate\"; href: string; mode: \"push\" | \"replace\" }\n | { kind: \"refresh\"; scope: RefreshScope }\n | { kind: \"traverse\"; direction: TraverseDirection; historyState: unknown }\n | { kind: \"prefetch\"; href: string }\n | { kind: \"flightResponseArrived\"; token: OperationToken; result: FlightResultV0 };\n\nexport type RequestedWork =\n | { kind: \"flight\"; href: string; mode: \"push\" | \"replace\" | \"refresh\" }\n | { direction: TraverseDirection; historyState: unknown; kind: \"traverseFlight\" }\n | { kind: \"prefetch\"; href: string };\n\nexport type CommitProposal = {\n preserveAbsentSlots: boolean;\n preserveElementIds: readonly string[];\n preservePreviousSlotIds: readonly string[];\n reason: \"currentRootBoundary\" | \"interceptedCurrentRootBoundary\" | \"rootBoundaryUnknownFallback\";\n targetSnapshot: RouteSnapshotV0;\n};\n\nexport type NoCommitReason = \"prefetchOnly\";\nexport type HardNavigationReason = \"interceptionProofRejected\" | \"rootBoundaryChanged\";\nexport type RootBoundaryTransition =\n | \"currentRootBoundary\"\n | \"rootBoundaryChanged\"\n | \"rootBoundaryUnknownFallback\";\n\nexport type NavigationDecisionV0 =\n | {\n kind: \"requestWork\";\n token: OperationToken;\n work: RequestedWork;\n trace: NavigationTrace;\n }\n | {\n kind: \"proposeCommit\";\n token: OperationToken;\n proposal: CommitProposal;\n trace: NavigationTrace;\n }\n | {\n kind: \"noCommit\";\n token: OperationToken;\n reason: NoCommitReason;\n trace: NavigationTrace;\n }\n | {\n kind: \"hardNavigate\";\n token: OperationToken;\n url: string;\n reason: HardNavigationReason;\n trace: NavigationTrace;\n };\n\nexport type FlightResultV0 = {\n href: string;\n targetSnapshot: RouteSnapshotV0;\n};\n\nexport type NavigationPlannerInput = {\n // Graph-owned route topology is the semantic authority for root/layout/slot\n // decisions whenever the caller can supply it. Null keeps the legacy\n // snapshot-only path for low-level tests and unknown route shapes.\n routeManifest: RouteManifest | null;\n state: NavigationPlannerStateV0;\n event: NavigationEvent;\n};\n\ntype RouteTopologySnapshot = {\n layoutIds: readonly string[];\n rootBoundaryId: string | null;\n rootLayoutTreePath: string | null;\n slotBindings: readonly ParallelSlotBindingSnapshotV0[];\n};\n\ntype RouteTopologySlotBindingSource = \"snapshot\" | \"manifestTarget\";\n\nconst ROUTE_INTERCEPTION_CONTEXT_SEPARATOR = \"\\0\";\n\nfunction createRequestWorkDecision(options: {\n eventKind: NavigationEvent[\"kind\"];\n state: NavigationPlannerStateV0;\n work: RequestedWork;\n}): NavigationDecisionV0 {\n const traverseFields =\n options.work.kind === \"traverseFlight\" ? { traverseDirection: options.work.direction } : {};\n return {\n kind: \"requestWork\",\n token: options.state.nextOperationToken,\n work: options.work,\n trace: createNavigationTrace(NavigationTraceReasonCodes.requestWork, {\n eventKind: options.eventKind,\n targetHref: getRequestedWorkTargetHref(options.work),\n ...traverseFields,\n }),\n };\n}\n\nfunction getRequestedWorkTargetHref(work: RequestedWork): string | null {\n switch (work.kind) {\n case \"flight\":\n case \"prefetch\":\n return work.href;\n case \"traverseFlight\":\n return null;\n default: {\n const _exhaustive: never = work;\n throw new Error(\"[vinext] Unknown requested navigation work: \" + String(_exhaustive));\n }\n }\n}\n\nfunction createSnapshotRouteTopology(snapshot: RouteSnapshotV0): RouteTopologySnapshot {\n return {\n layoutIds: snapshot.layoutIds,\n rootBoundaryId: snapshot.rootBoundaryId,\n rootLayoutTreePath: snapshot.rootBoundaryId,\n slotBindings: snapshot.slotBindings,\n };\n}\n\nfunction stripInterceptionContextFromRouteId(routeId: string): string {\n const separatorIndex = routeId.indexOf(ROUTE_INTERCEPTION_CONTEXT_SEPARATOR);\n return separatorIndex === -1 ? routeId : routeId.slice(0, separatorIndex);\n}\n\nfunction getMatchedUrlPathname(matchedUrl: string): string {\n try {\n return new URL(matchedUrl, \"https://vinext.local\").pathname;\n } catch {\n const [withoutHash = \"\"] = matchedUrl.split(\"#\");\n const [pathname = \"\"] = withoutHash.split(\"?\");\n return pathname === \"\" ? \"/\" : pathname;\n }\n}\n\nfunction splitMatchedUrlIntoRouteParts(matchedUrl: string): string[] {\n return normalizePathnameForRouteMatch(getMatchedUrlPathname(matchedUrl))\n .split(\"/\")\n .filter((part) => part.length > 0);\n}\n\nfunction findRouteManifestRouteByMatchedUrl(\n routeManifest: RouteManifest,\n matchedUrl: string,\n): RouteManifestRoute | null {\n const urlParts = splitMatchedUrlIntoRouteParts(matchedUrl);\n\n // RouteManifest preserves buildAppRouteGraph's compareRoutes() order, so the\n // first pattern match follows the same static/dynamic/catch-all precedence as\n // request-time route matching instead of raw filesystem scan order.\n for (const route of routeManifest.segmentGraph.routes.values()) {\n if (matchRoutePattern(urlParts, route.patternParts) !== null) {\n return route;\n }\n }\n\n return null;\n}\n\nfunction routeManifestRouteMatchesUrl(route: RouteManifestRoute, matchedUrl: string): boolean {\n return matchRoutePattern(splitMatchedUrlIntoRouteParts(matchedUrl), route.patternParts) !== null;\n}\n\nfunction findRouteManifestRouteByIdOrMatchedUrl(options: {\n matchedUrl: string;\n routeId: string;\n routeManifest: RouteManifest;\n}): RouteManifestRoute | null {\n const routeId = stripInterceptionContextFromRouteId(options.routeId);\n const route = options.routeManifest.segmentGraph.routes.get(routeId);\n if (route && routeManifestRouteMatchesUrl(route, options.matchedUrl)) {\n return route;\n }\n\n return findRouteManifestRouteByMatchedUrl(options.routeManifest, options.matchedUrl);\n}\n\nfunction findRouteManifestRouteForSnapshot(\n routeManifest: RouteManifest,\n snapshot: RouteSnapshotV0,\n): RouteManifestRoute | null {\n if (snapshot.interception !== null) {\n return findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: snapshot.interception.sourceMatchedUrl,\n routeId: snapshot.interception.sourceRouteId,\n routeManifest,\n });\n }\n\n return findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: snapshot.matchedUrl,\n routeId: snapshot.routeId,\n routeManifest,\n });\n}\n\nfunction resolveRouteManifestSlotBindings(\n routeManifest: RouteManifest,\n route: RouteManifestRoute,\n): readonly ParallelSlotBindingSnapshotV0[] {\n const bindings: ParallelSlotBindingSnapshotV0[] = [];\n for (const slotId of route.slotIds) {\n const binding = routeManifest.segmentGraph.slotBindings.get(`${route.id}::${slotId}`);\n if (!binding) continue;\n bindings.push({\n ownerLayoutId: binding.ownerLayoutId,\n slotId: binding.slotId,\n state: binding.state,\n });\n }\n\n return bindings.sort((left, right) => compareAppElementsSlotIds(left.slotId, right.slotId));\n}\n\nfunction resolveRouteManifestRootLayoutTreePath(\n routeManifest: RouteManifest,\n route: RouteManifestRoute,\n): string | null {\n if (route.rootBoundaryId === null) return null;\n return routeManifest.segmentGraph.rootBoundaries.get(route.rootBoundaryId)?.treePath ?? null;\n}\n\nfunction resolveRouteTopologySnapshot(options: {\n routeManifest: RouteManifest | null;\n slotBindingSource: RouteTopologySlotBindingSource;\n snapshot: RouteSnapshotV0;\n}): RouteTopologySnapshot {\n const route =\n options.routeManifest === null\n ? null\n : findRouteManifestRouteForSnapshot(options.routeManifest, options.snapshot);\n if (route === null || options.routeManifest === null) {\n return createSnapshotRouteTopology(options.snapshot);\n }\n\n // Intercepted targets carry the source route's tree topology, not the direct\n // target route's, so direct-target manifest slot bindings do not apply.\n const shouldUseManifestSlotBindings =\n options.slotBindingSource === \"manifestTarget\" && options.snapshot.interception === null;\n\n return {\n layoutIds: route.layoutIds,\n rootBoundaryId: route.rootBoundaryId,\n rootLayoutTreePath: resolveRouteManifestRootLayoutTreePath(options.routeManifest, route),\n slotBindings: shouldUseManifestSlotBindings\n ? resolveRouteManifestSlotBindings(options.routeManifest, route)\n : options.snapshot.slotBindings,\n };\n}\n\nfunction findRouteManifestInterceptionForProof(\n routeManifest: RouteManifest,\n proof: InterceptionSnapshotV0,\n): RouteManifestInterception | null {\n const sourceParts = splitMatchedUrlIntoRouteParts(proof.sourceMatchedUrl);\n const targetParts = splitMatchedUrlIntoRouteParts(proof.targetMatchedUrl);\n const targetRoute = findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: proof.targetMatchedUrl,\n routeId: proof.targetRouteId,\n routeManifest,\n });\n const candidateInterceptions =\n routeManifest.segmentGraph.interceptionsBySlotId.get(proof.slotId) ?? [];\n\n for (const interception of candidateInterceptions) {\n if (!matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) {\n continue;\n }\n if (matchRoutePattern(targetParts, interception.targetPatternParts) === null) continue;\n if (interception.targetRouteId !== null && targetRoute?.id !== interception.targetRouteId) {\n continue;\n }\n return interception;\n }\n\n return null;\n}\n\nfunction createRootBoundaryTraceFields(options: {\n currentRootLayoutTreePath: string | null;\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n nextRootLayoutTreePath: string | null;\n state: NavigationPlannerStateV0;\n}): NavigationTraceFields {\n // Browser commit approval supplies lifecycle trace context before calling\n // the planner. This fallback exists for pure planner callers and tests; it\n // intentionally cannot invent lifecycle-only fields such as active nav id.\n if (options.state.traceFields) {\n return {\n ...options.state.traceFields,\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n };\n }\n\n return createNavigationLifecycleTraceFields({\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.state.visibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n startedVisibleCommitVersion: options.event.token.baseVisibleCommitVersion,\n });\n}\n\nfunction classifyRootBoundaryTransition(\n currentRootBoundaryId: string | null,\n nextRootBoundaryId: string | null,\n): RootBoundaryTransition {\n if (currentRootBoundaryId === null || nextRootBoundaryId === null) {\n // Both null directions intentionally share the fallback because unresolved\n // routes or legacy callers cannot prove either same-root reuse or root\n // changes from semantic topology.\n return \"rootBoundaryUnknownFallback\";\n }\n\n return currentRootBoundaryId === nextRootBoundaryId\n ? \"currentRootBoundary\"\n : \"rootBoundaryChanged\";\n}\n\nfunction resolveSameLayoutAncestorPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n return resolveSameLayoutAncestorPersistenceForTopologies(\n createSnapshotRouteTopology(currentSnapshot),\n createSnapshotRouteTopology(targetSnapshot),\n );\n}\n\nfunction resolveSameLayoutAncestorPersistenceForTopologies(\n currentTopology: RouteTopologySnapshot,\n targetTopology: RouteTopologySnapshot,\n): readonly string[] {\n if (\n classifyRootBoundaryTransition(\n currentTopology.rootBoundaryId,\n targetTopology.rootBoundaryId,\n ) !== \"currentRootBoundary\"\n ) {\n return [];\n }\n\n const commonLayoutIds: string[] = [];\n const maxLength = Math.min(currentTopology.layoutIds.length, targetTopology.layoutIds.length);\n for (let index = 0; index < maxLength; index++) {\n const layoutId = currentTopology.layoutIds[index];\n if (layoutId !== targetTopology.layoutIds[index]) break;\n commonLayoutIds.push(layoutId);\n }\n return commonLayoutIds;\n}\n\nfunction resolveMountedParallelSlotPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n const preservedLayoutIds = resolveSameLayoutAncestorPersistence(currentSnapshot, targetSnapshot);\n return resolveMountedParallelSlotPersistenceForLayouts(currentSnapshot, preservedLayoutIds);\n}\n\nfunction resolveMountedParallelSlotPersistenceForLayouts(\n currentSnapshot: RouteSnapshotV0,\n preservedLayoutIds: readonly string[],\n): readonly string[] {\n if (preservedLayoutIds.length === 0) return [];\n const preservedLayoutIdSet = new Set(preservedLayoutIds);\n\n const preservedSlotIds: string[] = [];\n const seenSlotIds = new Set<string>();\n for (const slot of currentSnapshot.mountedParallelSlots) {\n if (slot.ownerLayoutId === null) continue;\n if (!preservedLayoutIdSet.has(slot.ownerLayoutId)) continue;\n if (seenSlotIds.has(slot.slotId)) continue;\n\n preservedSlotIds.push(slot.slotId);\n seenSlotIds.add(slot.slotId);\n }\n return preservedSlotIds;\n}\n\nfunction resolveCurrentRootBoundaryElementPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n const preservedLayoutIds = resolveSameLayoutAncestorPersistence(currentSnapshot, targetSnapshot);\n // Non-commit consumers still receive the legacy mounted-slot element list.\n // Commit promotion uses preservePreviousSlotIds instead so default/unmatched\n // slot reuse requires route-state proof.\n return [\n ...preservedLayoutIds,\n ...resolveMountedParallelSlotPersistenceForLayouts(currentSnapshot, preservedLayoutIds),\n ];\n}\n\nfunction resolveCurrentRootBoundaryCommitElementPersistence(options: {\n currentTopology: RouteTopologySnapshot;\n lane: OperationLane;\n targetTopology: RouteTopologySnapshot;\n}): readonly string[] {\n // Commit element persistence only keeps layout IDs. Default/unmatched slot\n // reuse is handled separately by preservePreviousSlotIds, using slot-binding\n // metadata as proof; payloads without __slotBindings get no semantic reuse.\n // resolveCurrentRootBoundaryCommitSlotPersistence recomputes this same\n // ancestor set; planner correctness relies on both calls agreeing so any\n // preserved slot's owner layout is also present in preserveElementIds.\n return resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n}\n\nfunction resolveCurrentRootBoundaryCommitSlotPersistence(options: {\n currentTopology: RouteTopologySnapshot;\n lane: OperationLane;\n targetTopology: RouteTopologySnapshot;\n}): readonly string[] {\n if (options.lane === \"traverse\") return [];\n\n const preservedLayoutIds = resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n if (preservedLayoutIds.length === 0) return [];\n\n return resolveDefaultOrUnmatchedSlotPersistenceForLayouts({\n currentSlotBindings: options.currentTopology.slotBindings,\n preservedLayoutIds,\n targetSlotBindings: options.targetTopology.slotBindings,\n });\n}\n\n/**\n * Default/unmatched slot preservation law:\n *\n * A target default/unmatched slot may reuse previous content only when:\n * - the slot's owner layout is part of the preserved layout ancestor set;\n * - the current visible snapshot proves the same slot had renderable content;\n * - the navigation is not a traversal.\n *\n * Wire absence and UNMATCHED_SLOT markers are not semantic proof.\n */\nfunction resolveDefaultOrUnmatchedSlotPersistenceForLayouts(options: {\n currentSlotBindings: readonly ParallelSlotBindingSnapshotV0[];\n preservedLayoutIds: readonly string[];\n targetSlotBindings: readonly ParallelSlotBindingSnapshotV0[];\n}): readonly string[] {\n const preservedLayoutIdSet = new Set(options.preservedLayoutIds);\n const slotIdsWithContent = new Set<string>();\n for (const binding of options.currentSlotBindings) {\n if (binding.state === \"unmatched\") continue;\n slotIdsWithContent.add(binding.slotId);\n }\n\n const preservedSlotIds: string[] = [];\n const seenSlotIds = new Set<string>();\n for (const binding of options.targetSlotBindings) {\n if (binding.ownerLayoutId === null) continue;\n if (!preservedLayoutIdSet.has(binding.ownerLayoutId)) continue;\n if (binding.state === \"active\") continue;\n if (!slotIdsWithContent.has(binding.slotId)) continue;\n if (seenSlotIds.has(binding.slotId)) continue;\n\n preservedSlotIds.push(binding.slotId);\n seenSlotIds.add(binding.slotId);\n }\n return preservedSlotIds.sort(compareAppElementsSlotIds);\n}\n\ntype VisibleInterceptionSourceIdentity = {\n matchedUrl: string;\n routeId: string;\n};\n\ntype InterceptedPreservationValidation =\n | {\n kind: \"approved\";\n preserveElementIds: readonly string[];\n preservePreviousSlotIds: readonly string[];\n }\n | {\n kind: \"rejected\";\n reasonCode: NavigationTraceReasonCode;\n };\n\nfunction getVisibleInterceptionSourceIdentity(\n snapshot: RouteSnapshotV0,\n): VisibleInterceptionSourceIdentity {\n if (snapshot.interception) {\n return {\n matchedUrl: snapshot.interception.sourceMatchedUrl,\n routeId: snapshot.interception.sourceRouteId,\n };\n }\n return {\n matchedUrl: snapshot.matchedUrl,\n routeId: snapshot.routeId,\n };\n}\n\nfunction createInterceptionProofRejectedDecision(options: {\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n reasonCode: NavigationTraceReasonCode;\n traceFields: NavigationTraceFields;\n}): NavigationDecisionV0 {\n return {\n kind: \"hardNavigate\",\n reason: \"interceptionProofRejected\",\n token: options.event.token,\n trace: createNavigationTrace(options.reasonCode, options.traceFields),\n url: options.event.result.href,\n };\n}\n\nfunction validateInterceptedPreservation(options: {\n currentSnapshot: RouteSnapshotV0;\n currentTopology: RouteTopologySnapshot;\n routeManifest: RouteManifest | null;\n targetSnapshot: RouteSnapshotV0;\n targetTopology: RouteTopologySnapshot;\n}): InterceptedPreservationValidation {\n const proof = options.targetSnapshot.interception;\n if (!proof) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedMissingProof,\n };\n }\n\n if (proof.targetMatchedUrl !== options.targetSnapshot.matchedUrl) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedTargetMismatch,\n };\n }\n\n const sourceIdentity = getVisibleInterceptionSourceIdentity(options.currentSnapshot);\n if (\n proof.sourceMatchedUrl !== sourceIdentity.matchedUrl ||\n proof.sourceRouteId !== sourceIdentity.routeId\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUnknownSource,\n };\n }\n\n const declaredInterception =\n options.routeManifest === null\n ? null\n : findRouteManifestInterceptionForProof(options.routeManifest, proof);\n if (options.routeManifest !== null && declaredInterception === null) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,\n };\n }\n\n const preservedLayoutIds = resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n if (preservedLayoutIds.length === 0) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedIncompatibleRoot,\n };\n }\n\n const preservedLayoutIdSet = new Set(preservedLayoutIds);\n const targetSlotBinding = options.targetTopology.slotBindings.find(\n (binding) => binding.slotId === proof.slotId,\n );\n if (\n !targetSlotBinding ||\n targetSlotBinding.state !== \"active\" ||\n targetSlotBinding.ownerLayoutId === null ||\n !preservedLayoutIdSet.has(targetSlotBinding.ownerLayoutId)\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedMissingSlotProof,\n };\n }\n if (\n declaredInterception !== null &&\n targetSlotBinding.ownerLayoutId !== declaredInterception.ownerLayoutId\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,\n };\n }\n\n const preservePreviousSlotIds = resolveDefaultOrUnmatchedSlotPersistenceForLayouts({\n currentSlotBindings: options.currentTopology.slotBindings,\n preservedLayoutIds,\n targetSlotBindings: options.targetTopology.slotBindings,\n }).filter((slotId) => slotId !== proof.slotId);\n\n return {\n kind: \"approved\",\n preserveElementIds: preservedLayoutIds,\n preservePreviousSlotIds,\n };\n}\n\nfunction planFlightResponseArrived(options: {\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n routeManifest: RouteManifest | null;\n state: NavigationPlannerStateV0;\n}): NavigationDecisionV0 {\n const targetSnapshot = options.event.result.targetSnapshot;\n const currentTopology = resolveRouteTopologySnapshot({\n routeManifest: options.routeManifest,\n slotBindingSource: \"snapshot\",\n snapshot: options.state.visibleSnapshot,\n });\n const targetTopology = resolveRouteTopologySnapshot({\n routeManifest: options.routeManifest,\n slotBindingSource: \"manifestTarget\",\n snapshot: targetSnapshot,\n });\n const traceFields = createRootBoundaryTraceFields({\n currentRootLayoutTreePath: currentTopology.rootLayoutTreePath,\n event: options.event,\n nextRootLayoutTreePath: targetTopology.rootLayoutTreePath,\n state: options.state,\n });\n\n if (options.event.token.lane === \"prefetch\") {\n return {\n kind: \"noCommit\",\n reason: \"prefetchOnly\",\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.prefetchOnly, traceFields),\n };\n }\n\n // interceptionContext is transport evidence, not authority. Normal payloads\n // can carry it when a request was sent from an intercepted visible world, so\n // only explicit __interception proof enters the preservation branch.\n const hasInterceptedPayload = targetSnapshot.interception !== null;\n if (hasInterceptedPayload) {\n const validation = validateInterceptedPreservation({\n currentSnapshot: options.state.visibleSnapshot,\n currentTopology,\n routeManifest: options.routeManifest,\n targetSnapshot,\n targetTopology,\n });\n if (validation.kind === \"rejected\") {\n return createInterceptionProofRejectedDecision({\n event: options.event,\n reasonCode: validation.reasonCode,\n traceFields,\n });\n }\n\n return {\n kind: \"proposeCommit\",\n proposal: {\n preserveAbsentSlots: false,\n preserveElementIds: validation.preserveElementIds,\n preservePreviousSlotIds: validation.preservePreviousSlotIds,\n reason: \"interceptedCurrentRootBoundary\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(\n NavigationTraceReasonCodes.interceptedCommitCurrent,\n traceFields,\n ),\n };\n }\n\n const transition = classifyRootBoundaryTransition(\n currentTopology.rootBoundaryId,\n targetTopology.rootBoundaryId,\n );\n\n if (transition === \"rootBoundaryChanged\") {\n return {\n kind: \"hardNavigate\",\n reason: \"rootBoundaryChanged\",\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryChanged, traceFields),\n url: options.event.result.href,\n };\n }\n\n if (transition === \"rootBoundaryUnknownFallback\") {\n // Unknown root identity is an uncertainty fallback, not evidence that\n // reuse is safe. It remains only for callers without a manifest or routes\n // that cannot be matched back to RouteManifest topology.\n return {\n kind: \"proposeCommit\",\n proposal: {\n preserveAbsentSlots: true,\n preserveElementIds: [],\n preservePreviousSlotIds: [],\n reason: \"rootBoundaryUnknownFallback\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.rootBoundaryUnknown, traceFields),\n };\n }\n\n return {\n kind: \"proposeCommit\",\n proposal: {\n preserveAbsentSlots: false,\n preserveElementIds: resolveCurrentRootBoundaryCommitElementPersistence({\n currentTopology,\n lane: options.event.token.lane,\n targetTopology,\n }),\n preservePreviousSlotIds: resolveCurrentRootBoundaryCommitSlotPersistence({\n currentTopology,\n lane: options.event.token.lane,\n targetTopology,\n }),\n reason: \"currentRootBoundary\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.commitCurrent, traceFields),\n };\n}\n\nfunction planNavigation(input: NavigationPlannerInput): NavigationDecisionV0 {\n switch (input.event.kind) {\n case \"navigate\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.event.href,\n kind: \"flight\",\n mode: input.event.mode,\n },\n });\n case \"refresh\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.state.visibleSnapshot.displayUrl,\n kind: \"flight\",\n mode: \"refresh\",\n },\n });\n case \"traverse\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n direction: input.event.direction,\n historyState: input.event.historyState,\n kind: \"traverseFlight\",\n },\n });\n case \"prefetch\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.event.href,\n kind: \"prefetch\",\n },\n });\n case \"flightResponseArrived\":\n return planFlightResponseArrived({\n event: input.event,\n routeManifest: input.routeManifest,\n state: input.state,\n });\n default: {\n const _exhaustive: never = input.event;\n throw new Error(\"[vinext] Unknown navigation event: \" + String(_exhaustive));\n }\n }\n}\n\nexport const navigationPlanner = {\n classifyRootBoundaryTransition,\n plan: planNavigation,\n resolveCurrentRootBoundaryElementPersistence,\n resolveMountedParallelSlotPersistence,\n resolveSameLayoutAncestorPersistence,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"navigation-planner.js","names":["_exhaustive"],"sources":["../../src/server/navigation-planner.ts"],"sourcesContent":["import { matchRoutePattern, matchRoutePatternPrefix } from \"../routing/route-pattern.js\";\nimport { splitPathnameForRouteMatch } from \"../routing/utils.js\";\nimport type {\n RouteManifest,\n RouteManifestInterception,\n RouteManifestRoute,\n} from \"../routing/app-route-graph.js\";\nimport { compareAppElementsSlotIds, type AppElementsSlotBinding } from \"./app-elements.js\";\nimport type {\n CacheEntryReuseDecision,\n CacheEntryReuseProof,\n CacheProofRejectionCode,\n} from \"./cache-proof.js\";\nimport {\n NavigationTraceReasonCodes,\n createNavigationLifecycleTraceFields,\n createNavigationTrace,\n type NavigationTrace,\n type NavigationTraceFields,\n type NavigationTraceReasonCode,\n} from \"./navigation-trace.js\";\n\nexport type OperationLane =\n | \"hmr\"\n | \"navigation\"\n | \"prefetch\"\n | \"refresh\"\n | \"server-action\"\n | \"traverse\";\n\nexport type OperationToken = {\n operationId: number;\n lane: OperationLane;\n baseVisibleCommitVersion: number;\n graphVersion: string | null;\n deploymentVersion: string | null;\n targetSnapshotFingerprint: string;\n cacheVariantFingerprint?: string;\n};\n\nexport type RouteSnapshotV0 = {\n interception: InterceptionSnapshotV0 | null;\n interceptionContext: string | null;\n routeId: string;\n // Ordered ancestor-first, with the root layout at index 0. Same-layout\n // persistence uses prefix comparison, so callers must preserve this order.\n layoutIds: readonly string[];\n mountedParallelSlots: readonly MountedParallelSlotSnapshotV0[];\n rootBoundaryId: string | null;\n displayUrl: string;\n matchedUrl: string;\n slotBindings: readonly ParallelSlotBindingSnapshotV0[];\n};\n\nexport type InterceptionSnapshotV0 = {\n sourceMatchedUrl: string;\n sourceRouteId: string;\n slotId: string;\n targetMatchedUrl: string;\n targetRouteId: string;\n};\n\nexport type MountedParallelSlotSnapshotV0 = {\n slotId: string;\n ownerLayoutId: string | null;\n};\n\n// Planner snapshots consume the same canonical slot-binding facts decoded from\n// AppElements metadata. Keep the alias explicit so route-state and transport\n// readers cannot drift into structurally identical but semantically separate\n// shapes.\nexport type ParallelSlotBindingSnapshotV0 = AppElementsSlotBinding;\n\nexport type NavigationPlannerStateV0 = {\n // V0 keeps a single state shape so intent events and result events can move\n // through one planner surface. flightResponseArrived uses event.token; later\n // #726 slices can split this by event kind once more result paths are routed\n // through the planner.\n nextOperationToken: OperationToken;\n // Callers that have lifecycle authority should pass the complete trace\n // context. When absent, the planner emits the stable root-boundary facts it\n // can derive from the event and visible snapshot.\n traceFields?: NavigationTraceFields;\n visibleCommitVersion: number;\n visibleSnapshot: RouteSnapshotV0;\n};\n\nexport type RefreshScope = \"visible\";\nexport type TraverseDirection = \"back\" | \"forward\" | \"unknown\";\n\nexport type NavigationEvent =\n | { kind: \"navigate\"; href: string; mode: \"push\" | \"replace\" }\n | { kind: \"refresh\"; scope: RefreshScope }\n | { kind: \"traverse\"; direction: TraverseDirection; historyState: unknown }\n | { kind: \"prefetch\"; href: string }\n | { kind: \"flightResponseArrived\"; token: OperationToken; result: FlightResultV0 };\n\nexport type RequestedWork =\n | { kind: \"flight\"; href: string; mode: \"push\" | \"replace\" | \"refresh\" }\n | { direction: TraverseDirection; historyState: unknown; kind: \"traverseFlight\" }\n | { kind: \"prefetch\"; href: string };\n\nexport type CommitProposal = {\n cacheEntryReuseDecision?: AcceptedCacheEntryReuseDecision;\n preserveAbsentSlots: boolean;\n preserveElementIds: readonly string[];\n preservePreviousSlotIds: readonly string[];\n reason: \"currentRootBoundary\" | \"interceptedCurrentRootBoundary\" | \"unprovenTopologyFallback\";\n targetSnapshot: RouteSnapshotV0;\n};\n\nexport type NoCommitReason = \"prefetchOnly\";\nexport type HardNavigationReason =\n | \"cacheProofRejected\"\n | \"interceptionProofRejected\"\n | \"rootBoundaryChanged\";\nexport type RootBoundaryTransition =\n | \"currentRootBoundary\"\n | \"rootBoundaryChanged\"\n | \"rootBoundaryUnknown\";\n\nexport type NavigationDecisionV0 =\n | {\n kind: \"requestWork\";\n token: OperationToken;\n work: RequestedWork;\n trace: NavigationTrace;\n }\n | {\n kind: \"proposeCommit\";\n token: OperationToken;\n proposal: CommitProposal;\n trace: NavigationTrace;\n }\n | {\n kind: \"noCommit\";\n token: OperationToken;\n reason: NoCommitReason;\n trace: NavigationTrace;\n }\n | {\n kind: \"hardNavigate\";\n token: OperationToken;\n url: string;\n reason: HardNavigationReason;\n trace: NavigationTrace;\n };\n\nexport type FlightResultV0 = {\n cacheEntryReuseProof?: CacheEntryReuseProof;\n href: string;\n targetSnapshot: RouteSnapshotV0;\n};\n\nexport type NavigationPlannerInput = {\n // Graph-owned route topology is the semantic authority for root/layout/slot\n // decisions whenever the caller can supply it. Null keeps the legacy\n // snapshot-only path for low-level tests and unknown route shapes.\n routeManifest: RouteManifest | null;\n state: NavigationPlannerStateV0;\n event: NavigationEvent;\n};\n\ntype RouteTopologySnapshot = {\n layoutIds: readonly string[];\n rootBoundaryId: string | null;\n rootLayoutTreePath: string | null;\n slotBindings: readonly ParallelSlotBindingSnapshotV0[];\n};\n\ntype RouteTopologyResolution =\n | {\n kind: \"known\";\n topology: RouteTopologySnapshot;\n }\n | {\n kind: \"unknown\";\n };\n\ntype RouteTopologySlotBindingSource = \"snapshot\" | \"manifestTarget\";\ntype AcceptedCacheEntryReuseDecision = Extract<CacheEntryReuseDecision, { canReuse: true }>;\ntype RejectedCacheEntryReuseDecision = Extract<CacheEntryReuseDecision, { canReuse: false }>;\ntype CacheEntryProofEvaluation =\n | Readonly<{\n decision: AcceptedCacheEntryReuseDecision | null;\n kind: \"accepted\";\n }>\n | Readonly<{\n decision: RejectedCacheEntryReuseDecision | null;\n kind: \"rejected\";\n }>;\n\nconst ROUTE_INTERCEPTION_CONTEXT_SEPARATOR = \"\\0\";\nconst CACHE_ENTRY_PROOF_MISSING_CODE =\n \"CP_CACHE_ENTRY_PROOF_MISSING\" satisfies CacheProofRejectionCode;\n\nfunction createRequestWorkDecision(options: {\n eventKind: NavigationEvent[\"kind\"];\n state: NavigationPlannerStateV0;\n work: RequestedWork;\n}): NavigationDecisionV0 {\n const traverseFields =\n options.work.kind === \"traverseFlight\" ? { traverseDirection: options.work.direction } : {};\n return {\n kind: \"requestWork\",\n token: options.state.nextOperationToken,\n work: options.work,\n trace: createNavigationTrace(NavigationTraceReasonCodes.requestWork, {\n eventKind: options.eventKind,\n targetHref: getRequestedWorkTargetHref(options.work),\n ...traverseFields,\n }),\n };\n}\n\nfunction getRequestedWorkTargetHref(work: RequestedWork): string | null {\n switch (work.kind) {\n case \"flight\":\n case \"prefetch\":\n return work.href;\n case \"traverseFlight\":\n return null;\n default: {\n const _exhaustive: never = work;\n throw new Error(\"[vinext] Unknown requested navigation work: \" + String(_exhaustive));\n }\n }\n}\n\nfunction createSnapshotRouteTopology(snapshot: RouteSnapshotV0): RouteTopologySnapshot {\n return {\n layoutIds: snapshot.layoutIds,\n rootBoundaryId: snapshot.rootBoundaryId,\n rootLayoutTreePath: snapshot.rootBoundaryId,\n slotBindings: snapshot.slotBindings,\n };\n}\n\nfunction stripInterceptionContextFromRouteId(routeId: string): string {\n const separatorIndex = routeId.indexOf(ROUTE_INTERCEPTION_CONTEXT_SEPARATOR);\n return separatorIndex === -1 ? routeId : routeId.slice(0, separatorIndex);\n}\n\nfunction getMatchedUrlPathname(matchedUrl: string): string {\n try {\n return new URL(matchedUrl, \"https://vinext.local\").pathname;\n } catch {\n const [withoutHash = \"\"] = matchedUrl.split(\"#\");\n const [pathname = \"\"] = withoutHash.split(\"?\");\n return pathname === \"\" ? \"/\" : pathname;\n }\n}\n\nfunction splitMatchedUrlIntoRouteParts(matchedUrl: string): string[] {\n return splitPathnameForRouteMatch(getMatchedUrlPathname(matchedUrl));\n}\n\nfunction findRouteManifestRouteByMatchedUrl(\n routeManifest: RouteManifest,\n matchedUrl: string,\n): RouteManifestRoute | null {\n const urlParts = splitMatchedUrlIntoRouteParts(matchedUrl);\n\n // RouteManifest preserves buildAppRouteGraph's compareRoutes() order, so the\n // first pattern match follows the same static/dynamic/catch-all precedence as\n // request-time route matching instead of raw filesystem scan order.\n for (const route of routeManifest.segmentGraph.routes.values()) {\n if (matchRoutePattern(urlParts, route.patternParts) !== null) {\n return route;\n }\n }\n\n return null;\n}\n\nfunction routeManifestRouteMatchesUrl(route: RouteManifestRoute, matchedUrl: string): boolean {\n return matchRoutePattern(splitMatchedUrlIntoRouteParts(matchedUrl), route.patternParts) !== null;\n}\n\nfunction findRouteManifestRouteByIdOrMatchedUrl(options: {\n matchedUrl: string;\n routeId: string;\n routeManifest: RouteManifest;\n}): RouteManifestRoute | null {\n const routeId = stripInterceptionContextFromRouteId(options.routeId);\n const route = options.routeManifest.segmentGraph.routes.get(routeId);\n if (route && routeManifestRouteMatchesUrl(route, options.matchedUrl)) {\n return route;\n }\n\n return findRouteManifestRouteByMatchedUrl(options.routeManifest, options.matchedUrl);\n}\n\nfunction findRouteManifestRouteForSnapshot(\n routeManifest: RouteManifest,\n snapshot: RouteSnapshotV0,\n): RouteManifestRoute | null {\n if (snapshot.interception !== null) {\n return findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: snapshot.interception.sourceMatchedUrl,\n routeId: snapshot.interception.sourceRouteId,\n routeManifest,\n });\n }\n\n return findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: snapshot.matchedUrl,\n routeId: snapshot.routeId,\n routeManifest,\n });\n}\n\nfunction resolveRouteManifestSlotBindings(\n routeManifest: RouteManifest,\n route: RouteManifestRoute,\n): readonly ParallelSlotBindingSnapshotV0[] {\n const bindings: ParallelSlotBindingSnapshotV0[] = [];\n for (const slotId of route.slotIds) {\n const binding = routeManifest.segmentGraph.slotBindings.get(`${route.id}::${slotId}`);\n if (!binding) continue;\n bindings.push({\n ownerLayoutId: binding.ownerLayoutId,\n slotId: binding.slotId,\n state: binding.state,\n });\n }\n\n return bindings.sort((left, right) => compareAppElementsSlotIds(left.slotId, right.slotId));\n}\n\nfunction resolveRouteManifestRootLayoutTreePath(\n routeManifest: RouteManifest,\n route: RouteManifestRoute,\n): string | null {\n if (route.rootBoundaryId === null) return null;\n return routeManifest.segmentGraph.rootBoundaries.get(route.rootBoundaryId)?.treePath ?? null;\n}\n\nfunction resolveRouteTopologySnapshot(options: {\n routeManifest: RouteManifest | null;\n slotBindingSource: RouteTopologySlotBindingSource;\n snapshot: RouteSnapshotV0;\n}): RouteTopologyResolution {\n const route =\n options.routeManifest === null\n ? null\n : findRouteManifestRouteForSnapshot(options.routeManifest, options.snapshot);\n if (route === null || options.routeManifest === null) {\n return { kind: \"unknown\" };\n }\n\n // Intercepted targets carry the source route's tree topology, not the direct\n // target route's, so direct-target manifest slot bindings do not apply.\n const shouldUseManifestSlotBindings =\n options.slotBindingSource === \"manifestTarget\" && options.snapshot.interception === null;\n\n return {\n kind: \"known\",\n topology: {\n layoutIds: route.layoutIds,\n rootBoundaryId: route.rootBoundaryId,\n rootLayoutTreePath: resolveRouteManifestRootLayoutTreePath(options.routeManifest, route),\n slotBindings: shouldUseManifestSlotBindings\n ? resolveRouteManifestSlotBindings(options.routeManifest, route)\n : options.snapshot.slotBindings,\n },\n };\n}\n\nfunction findRouteManifestInterceptionForProof(\n routeManifest: RouteManifest,\n proof: InterceptionSnapshotV0,\n): RouteManifestInterception | null {\n const sourceParts = splitMatchedUrlIntoRouteParts(proof.sourceMatchedUrl);\n const targetParts = splitMatchedUrlIntoRouteParts(proof.targetMatchedUrl);\n const targetRoute = findRouteManifestRouteByIdOrMatchedUrl({\n matchedUrl: proof.targetMatchedUrl,\n routeId: proof.targetRouteId,\n routeManifest,\n });\n const candidateInterceptions =\n routeManifest.segmentGraph.interceptionsBySlotId.get(proof.slotId) ?? [];\n\n for (const interception of candidateInterceptions) {\n if (!matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) {\n continue;\n }\n if (matchRoutePattern(targetParts, interception.targetPatternParts) === null) continue;\n if (interception.targetRouteId !== null && targetRoute?.id !== interception.targetRouteId) {\n continue;\n }\n return interception;\n }\n\n return null;\n}\n\nfunction createRootBoundaryTraceFields(options: {\n currentRootLayoutTreePath: string | null;\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n nextRootLayoutTreePath: string | null;\n state: NavigationPlannerStateV0;\n}): NavigationTraceFields {\n // Browser commit approval supplies lifecycle trace context before calling\n // the planner. This fallback exists for pure planner callers and tests; it\n // intentionally cannot invent lifecycle-only fields such as active nav id.\n if (options.state.traceFields) {\n return {\n ...options.state.traceFields,\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n };\n }\n\n return createNavigationLifecycleTraceFields({\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.state.visibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n startedVisibleCommitVersion: options.event.token.baseVisibleCommitVersion,\n });\n}\n\nfunction classifyRootBoundaryTransition(\n currentRootBoundaryId: string | null,\n nextRootBoundaryId: string | null,\n): RootBoundaryTransition {\n if (currentRootBoundaryId === null || nextRootBoundaryId === null) {\n return \"rootBoundaryUnknown\";\n }\n\n return currentRootBoundaryId === nextRootBoundaryId\n ? \"currentRootBoundary\"\n : \"rootBoundaryChanged\";\n}\n\nfunction resolveSameLayoutAncestorPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n return resolveSameLayoutAncestorPersistenceForTopologies(\n createSnapshotRouteTopology(currentSnapshot),\n createSnapshotRouteTopology(targetSnapshot),\n );\n}\n\nfunction resolveSameLayoutAncestorPersistenceForTopologies(\n currentTopology: RouteTopologySnapshot,\n targetTopology: RouteTopologySnapshot,\n): readonly string[] {\n if (\n classifyRootBoundaryTransition(\n currentTopology.rootBoundaryId,\n targetTopology.rootBoundaryId,\n ) !== \"currentRootBoundary\"\n ) {\n return [];\n }\n\n const commonLayoutIds: string[] = [];\n const maxLength = Math.min(currentTopology.layoutIds.length, targetTopology.layoutIds.length);\n for (let index = 0; index < maxLength; index++) {\n const layoutId = currentTopology.layoutIds[index];\n if (layoutId !== targetTopology.layoutIds[index]) break;\n commonLayoutIds.push(layoutId);\n }\n return commonLayoutIds;\n}\n\nfunction resolveMountedParallelSlotPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n const preservedLayoutIds = resolveSameLayoutAncestorPersistence(currentSnapshot, targetSnapshot);\n return resolveMountedParallelSlotPersistenceForLayouts(currentSnapshot, preservedLayoutIds);\n}\n\nfunction resolveMountedParallelSlotPersistenceForLayouts(\n currentSnapshot: RouteSnapshotV0,\n preservedLayoutIds: readonly string[],\n): readonly string[] {\n if (preservedLayoutIds.length === 0) return [];\n const preservedLayoutIdSet = new Set(preservedLayoutIds);\n\n const preservedSlotIds: string[] = [];\n const seenSlotIds = new Set<string>();\n for (const slot of currentSnapshot.mountedParallelSlots) {\n if (slot.ownerLayoutId === null) continue;\n if (!preservedLayoutIdSet.has(slot.ownerLayoutId)) continue;\n if (seenSlotIds.has(slot.slotId)) continue;\n\n preservedSlotIds.push(slot.slotId);\n seenSlotIds.add(slot.slotId);\n }\n return preservedSlotIds;\n}\n\nfunction resolveCurrentRootBoundaryElementPersistence(\n currentSnapshot: RouteSnapshotV0,\n targetSnapshot: RouteSnapshotV0,\n): readonly string[] {\n const preservedLayoutIds = resolveSameLayoutAncestorPersistence(currentSnapshot, targetSnapshot);\n // Non-commit consumers still receive the legacy mounted-slot element list.\n // Commit promotion uses preservePreviousSlotIds instead so default/unmatched\n // slot reuse requires route-state proof.\n return [\n ...preservedLayoutIds,\n ...resolveMountedParallelSlotPersistenceForLayouts(currentSnapshot, preservedLayoutIds),\n ];\n}\n\nfunction resolveCurrentRootBoundaryCommitElementPersistence(options: {\n currentTopology: RouteTopologySnapshot;\n lane: OperationLane;\n targetTopology: RouteTopologySnapshot;\n}): readonly string[] {\n // Commit element persistence only keeps layout IDs. Default/unmatched slot\n // reuse is handled separately by preservePreviousSlotIds, using slot-binding\n // metadata as proof; payloads without __slotBindings get no semantic reuse.\n // resolveCurrentRootBoundaryCommitSlotPersistence recomputes this same\n // ancestor set; planner correctness relies on both calls agreeing so any\n // preserved slot's owner layout is also present in preserveElementIds.\n return resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n}\n\nfunction resolveCurrentRootBoundaryCommitSlotPersistence(options: {\n currentTopology: RouteTopologySnapshot;\n lane: OperationLane;\n targetTopology: RouteTopologySnapshot;\n}): readonly string[] {\n if (options.lane === \"traverse\") return [];\n\n const preservedLayoutIds = resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n if (preservedLayoutIds.length === 0) return [];\n\n return resolveDefaultOrUnmatchedSlotPersistenceForLayouts({\n currentSlotBindings: options.currentTopology.slotBindings,\n preservedLayoutIds,\n targetSlotBindings: options.targetTopology.slotBindings,\n });\n}\n\n/**\n * Default/unmatched slot preservation law:\n *\n * A target default/unmatched slot may reuse previous content only when:\n * - the slot's owner layout is part of the preserved layout ancestor set;\n * - the current visible snapshot proves the same slot had renderable content;\n * - the navigation is not a traversal.\n *\n * Wire absence and UNMATCHED_SLOT markers are not semantic proof.\n */\nfunction resolveDefaultOrUnmatchedSlotPersistenceForLayouts(options: {\n currentSlotBindings: readonly ParallelSlotBindingSnapshotV0[];\n preservedLayoutIds: readonly string[];\n targetSlotBindings: readonly ParallelSlotBindingSnapshotV0[];\n}): readonly string[] {\n const preservedLayoutIdSet = new Set(options.preservedLayoutIds);\n const slotIdsWithContent = new Set<string>();\n for (const binding of options.currentSlotBindings) {\n if (binding.state === \"unmatched\") continue;\n slotIdsWithContent.add(binding.slotId);\n }\n\n const preservedSlotIds: string[] = [];\n const seenSlotIds = new Set<string>();\n for (const binding of options.targetSlotBindings) {\n if (binding.ownerLayoutId === null) continue;\n if (!preservedLayoutIdSet.has(binding.ownerLayoutId)) continue;\n if (binding.state === \"active\") continue;\n if (!slotIdsWithContent.has(binding.slotId)) continue;\n if (seenSlotIds.has(binding.slotId)) continue;\n\n preservedSlotIds.push(binding.slotId);\n seenSlotIds.add(binding.slotId);\n }\n return preservedSlotIds.sort(compareAppElementsSlotIds);\n}\n\ntype VisibleInterceptionSourceIdentity = {\n matchedUrl: string;\n routeId: string;\n};\n\ntype InterceptedPreservationValidation =\n | {\n kind: \"approved\";\n preserveElementIds: readonly string[];\n preservePreviousSlotIds: readonly string[];\n }\n | {\n kind: \"rejected\";\n reasonCode: NavigationTraceReasonCode;\n };\n\nfunction getVisibleInterceptionSourceIdentity(\n snapshot: RouteSnapshotV0,\n): VisibleInterceptionSourceIdentity {\n if (snapshot.interception) {\n return {\n matchedUrl: snapshot.interception.sourceMatchedUrl,\n routeId: snapshot.interception.sourceRouteId,\n };\n }\n return {\n matchedUrl: snapshot.matchedUrl,\n routeId: snapshot.routeId,\n };\n}\n\nfunction createInterceptionProofRejectedDecision(options: {\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n reasonCode: NavigationTraceReasonCode;\n traceFields: NavigationTraceFields;\n}): NavigationDecisionV0 {\n return {\n kind: \"hardNavigate\",\n reason: \"interceptionProofRejected\",\n token: options.event.token,\n trace: createNavigationTrace(options.reasonCode, options.traceFields),\n url: options.event.result.href,\n };\n}\n\nfunction evaluateCacheEntryReuseProof(\n proof: CacheEntryReuseProof | undefined,\n): CacheEntryProofEvaluation {\n if (proof === undefined) {\n return {\n kind: \"accepted\",\n decision: null,\n };\n }\n\n if (proof.decision === null) {\n return {\n kind: \"rejected\",\n decision: null,\n };\n }\n\n if (proof.decision.canReuse) {\n return {\n kind: \"accepted\",\n decision: proof.decision,\n };\n }\n\n return {\n kind: \"rejected\",\n decision: proof.decision,\n };\n}\n\nfunction createCacheProofRejectedTraceFields(\n traceFields: NavigationTraceFields,\n decision: RejectedCacheEntryReuseDecision | null,\n): NavigationTraceFields {\n if (decision === null) {\n return {\n ...traceFields,\n cacheProofCode: CACHE_ENTRY_PROOF_MISSING_CODE,\n };\n }\n\n return {\n ...traceFields,\n cacheProofCode: decision.code,\n cacheProofMode: decision.mode,\n cacheProofScope: decision.scope,\n };\n}\n\nfunction createCacheProofRejectedDecision(options: {\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n rejection: Extract<CacheEntryProofEvaluation, { kind: \"rejected\" }>;\n traceFields: NavigationTraceFields;\n}): NavigationDecisionV0 {\n return {\n kind: \"hardNavigate\",\n reason: \"cacheProofRejected\",\n token: options.event.token,\n trace: createNavigationTrace(\n NavigationTraceReasonCodes.cacheProofRejected,\n createCacheProofRejectedTraceFields(options.traceFields, options.rejection.decision),\n ),\n url: options.event.result.href,\n };\n}\n\nfunction createAcceptedCacheProofTraceFields(\n traceFields: NavigationTraceFields,\n decision: AcceptedCacheEntryReuseDecision | null,\n): NavigationTraceFields {\n if (decision === null) return traceFields;\n return {\n ...traceFields,\n cacheProofCode: decision.code,\n cacheProofReuseClass: decision.reuseClass,\n };\n}\n\nfunction createCacheEntryProposalFields(\n decision: AcceptedCacheEntryReuseDecision | null,\n): Pick<CommitProposal, \"cacheEntryReuseDecision\"> {\n if (decision === null) return {};\n return {\n cacheEntryReuseDecision: decision,\n };\n}\n\nfunction validateInterceptedPreservation(options: {\n currentSnapshot: RouteSnapshotV0;\n currentTopology: RouteTopologySnapshot;\n routeManifest: RouteManifest | null;\n targetSnapshot: RouteSnapshotV0;\n targetTopology: RouteTopologySnapshot;\n}): InterceptedPreservationValidation {\n const proof = options.targetSnapshot.interception;\n if (!proof) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedMissingProof,\n };\n }\n\n if (proof.targetMatchedUrl !== options.targetSnapshot.matchedUrl) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedTargetMismatch,\n };\n }\n\n const sourceIdentity = getVisibleInterceptionSourceIdentity(options.currentSnapshot);\n if (\n proof.sourceMatchedUrl !== sourceIdentity.matchedUrl ||\n proof.sourceRouteId !== sourceIdentity.routeId\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUnknownSource,\n };\n }\n\n const declaredInterception =\n options.routeManifest === null\n ? null\n : findRouteManifestInterceptionForProof(options.routeManifest, proof);\n if (options.routeManifest !== null && declaredInterception === null) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,\n };\n }\n\n const preservedLayoutIds = resolveSameLayoutAncestorPersistenceForTopologies(\n options.currentTopology,\n options.targetTopology,\n );\n if (preservedLayoutIds.length === 0) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedIncompatibleRoot,\n };\n }\n\n const preservedLayoutIdSet = new Set(preservedLayoutIds);\n const targetSlotBinding = options.targetTopology.slotBindings.find(\n (binding) => binding.slotId === proof.slotId,\n );\n if (\n !targetSlotBinding ||\n targetSlotBinding.state !== \"active\" ||\n targetSlotBinding.ownerLayoutId === null ||\n !preservedLayoutIdSet.has(targetSlotBinding.ownerLayoutId)\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedMissingSlotProof,\n };\n }\n if (\n declaredInterception !== null &&\n targetSlotBinding.ownerLayoutId !== declaredInterception.ownerLayoutId\n ) {\n return {\n kind: \"rejected\",\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,\n };\n }\n\n const preservePreviousSlotIds = resolveDefaultOrUnmatchedSlotPersistenceForLayouts({\n currentSlotBindings: options.currentTopology.slotBindings,\n preservedLayoutIds,\n targetSlotBindings: options.targetTopology.slotBindings,\n }).filter((slotId) => slotId !== proof.slotId);\n\n return {\n kind: \"approved\",\n preserveElementIds: preservedLayoutIds,\n preservePreviousSlotIds,\n };\n}\n\nfunction planFlightResponseArrived(options: {\n event: Extract<NavigationEvent, { kind: \"flightResponseArrived\" }>;\n routeManifest: RouteManifest | null;\n state: NavigationPlannerStateV0;\n}): NavigationDecisionV0 {\n const targetSnapshot = options.event.result.targetSnapshot;\n const currentTopology = resolveRouteTopologySnapshot({\n routeManifest: options.routeManifest,\n slotBindingSource: \"snapshot\",\n snapshot: options.state.visibleSnapshot,\n });\n const targetTopology = resolveRouteTopologySnapshot({\n routeManifest: options.routeManifest,\n slotBindingSource: \"manifestTarget\",\n snapshot: targetSnapshot,\n });\n const traceFields = createRootBoundaryTraceFields({\n currentRootLayoutTreePath:\n currentTopology.kind === \"known\" ? currentTopology.topology.rootLayoutTreePath : null,\n event: options.event,\n nextRootLayoutTreePath:\n targetTopology.kind === \"known\" ? targetTopology.topology.rootLayoutTreePath : null,\n state: options.state,\n });\n\n if (options.event.token.lane === \"prefetch\") {\n return {\n kind: \"noCommit\",\n reason: \"prefetchOnly\",\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.prefetchOnly, traceFields),\n };\n }\n\n const cacheEntryProofEvaluation = evaluateCacheEntryReuseProof(\n options.event.result.cacheEntryReuseProof,\n );\n if (cacheEntryProofEvaluation.kind === \"rejected\") {\n return createCacheProofRejectedDecision({\n event: options.event,\n rejection: cacheEntryProofEvaluation,\n traceFields,\n });\n }\n const acceptedCacheEntryDecision = cacheEntryProofEvaluation.decision;\n const commitTraceFields = createAcceptedCacheProofTraceFields(\n traceFields,\n acceptedCacheEntryDecision,\n );\n const cacheEntryProposalFields = createCacheEntryProposalFields(acceptedCacheEntryDecision);\n\n // interceptionContext is transport evidence, not authority. Normal payloads\n // can carry it when a request was sent from an intercepted visible world, so\n // only explicit __interception proof enters the preservation branch.\n const hasInterceptedPayload = targetSnapshot.interception !== null;\n if (hasInterceptedPayload) {\n if (currentTopology.kind === \"unknown\" || targetTopology.kind === \"unknown\") {\n return createInterceptionProofRejectedDecision({\n event: options.event,\n reasonCode: NavigationTraceReasonCodes.interceptedRejectedUndeclaredTopology,\n traceFields: commitTraceFields,\n });\n }\n\n const validation = validateInterceptedPreservation({\n currentSnapshot: options.state.visibleSnapshot,\n currentTopology: currentTopology.topology,\n routeManifest: options.routeManifest,\n targetSnapshot,\n targetTopology: targetTopology.topology,\n });\n if (validation.kind === \"rejected\") {\n return createInterceptionProofRejectedDecision({\n event: options.event,\n reasonCode: validation.reasonCode,\n traceFields: commitTraceFields,\n });\n }\n\n return {\n kind: \"proposeCommit\",\n proposal: {\n ...cacheEntryProposalFields,\n preserveAbsentSlots: false,\n preserveElementIds: validation.preserveElementIds,\n preservePreviousSlotIds: validation.preservePreviousSlotIds,\n reason: \"interceptedCurrentRootBoundary\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(\n NavigationTraceReasonCodes.interceptedCommitCurrent,\n commitTraceFields,\n ),\n };\n }\n\n const transition =\n currentTopology.kind === \"unknown\" || targetTopology.kind === \"unknown\"\n ? \"rootBoundaryUnknown\"\n : classifyRootBoundaryTransition(\n currentTopology.topology.rootBoundaryId,\n targetTopology.topology.rootBoundaryId,\n );\n\n if (transition === \"rootBoundaryChanged\") {\n return {\n kind: \"hardNavigate\",\n reason: \"rootBoundaryChanged\",\n token: options.event.token,\n trace: createNavigationTrace(\n NavigationTraceReasonCodes.rootBoundaryChanged,\n commitTraceFields,\n ),\n url: options.event.result.href,\n };\n }\n\n if (transition === \"rootBoundaryUnknown\") {\n // Unknown topology is not semantic proof. The event may still commit its\n // fully supplied payload, but it must not preserve absent slots, layouts,\n // or previous slot content from snapshot-derived route shape.\n return {\n kind: \"proposeCommit\",\n proposal: {\n ...cacheEntryProposalFields,\n preserveAbsentSlots: false,\n preserveElementIds: [],\n preservePreviousSlotIds: [],\n reason: \"unprovenTopologyFallback\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(\n NavigationTraceReasonCodes.rootBoundaryUnknown,\n commitTraceFields,\n ),\n };\n }\n\n if (currentTopology.kind !== \"known\" || targetTopology.kind !== \"known\") {\n throw new Error(\"[vinext] Current-root navigation planning requires manifest topology\");\n }\n\n return {\n kind: \"proposeCommit\",\n proposal: {\n ...cacheEntryProposalFields,\n preserveAbsentSlots: false,\n preserveElementIds: resolveCurrentRootBoundaryCommitElementPersistence({\n currentTopology: currentTopology.topology,\n lane: options.event.token.lane,\n targetTopology: targetTopology.topology,\n }),\n preservePreviousSlotIds: resolveCurrentRootBoundaryCommitSlotPersistence({\n currentTopology: currentTopology.topology,\n lane: options.event.token.lane,\n targetTopology: targetTopology.topology,\n }),\n reason: \"currentRootBoundary\",\n targetSnapshot,\n },\n token: options.event.token,\n trace: createNavigationTrace(NavigationTraceReasonCodes.commitCurrent, commitTraceFields),\n };\n}\n\nfunction planNavigation(input: NavigationPlannerInput): NavigationDecisionV0 {\n switch (input.event.kind) {\n case \"navigate\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.event.href,\n kind: \"flight\",\n mode: input.event.mode,\n },\n });\n case \"refresh\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.state.visibleSnapshot.displayUrl,\n kind: \"flight\",\n mode: \"refresh\",\n },\n });\n case \"traverse\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n direction: input.event.direction,\n historyState: input.event.historyState,\n kind: \"traverseFlight\",\n },\n });\n case \"prefetch\":\n return createRequestWorkDecision({\n eventKind: input.event.kind,\n state: input.state,\n work: {\n href: input.event.href,\n kind: \"prefetch\",\n },\n });\n case \"flightResponseArrived\":\n return planFlightResponseArrived({\n event: input.event,\n routeManifest: input.routeManifest,\n state: input.state,\n });\n default: {\n const _exhaustive: never = input.event;\n throw new Error(\"[vinext] Unknown navigation event: \" + String(_exhaustive));\n }\n }\n}\n\nexport const navigationPlanner = {\n classifyRootBoundaryTransition,\n plan: planNavigation,\n resolveCurrentRootBoundaryElementPersistence,\n resolveMountedParallelSlotPersistence,\n resolveSameLayoutAncestorPersistence,\n};\n"],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  declare const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
3
  type NavigationTraceSchemaVersion = 0;
4
4
  declare const NavigationTraceReasonCodes: {
5
+ cacheProofRejected: "NC_CACHE_REJECT";
5
6
  commitCurrent: "NC_COMMIT";
6
7
  interceptedCommitCurrent: "NC_INTERCEPT_COMMIT";
7
8
  interceptedRejectedIncompatibleRoot: "NC_INTERCEPT_REJECT_ROOT";
@@ -24,7 +25,7 @@ declare const NavigationTraceTransactionCodes: {
24
25
  type NavigationTraceReasonCode = (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];
25
26
  type NavigationTraceTransactionCode = (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];
26
27
  type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;
27
- type NavigationTraceFieldName = "activeNavigationId" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "operationLane" | "pendingOperationId" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
28
+ type NavigationTraceFieldName = "activeNavigationId" | "cacheProofCode" | "cacheProofMode" | "cacheProofReuseClass" | "cacheProofScope" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "operationLane" | "pendingOperationId" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
28
29
  type NavigationTraceFieldValue = string | number | boolean | null;
29
30
  type NavigationTraceFields = Readonly<Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>>;
30
31
  type NavigationTraceEntry = Readonly<{
@@ -1,6 +1,7 @@
1
1
  //#region src/server/navigation-trace.ts
2
2
  const NAVIGATION_TRACE_SCHEMA_VERSION = 0;
3
3
  const NavigationTraceReasonCodes = {
4
+ cacheProofRejected: "NC_CACHE_REJECT",
4
5
  commitCurrent: "NC_COMMIT",
5
6
  interceptedCommitCurrent: "NC_INTERCEPT_COMMIT",
6
7
  interceptedRejectedIncompatibleRoot: "NC_INTERCEPT_REJECT_ROOT",
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n commitCurrent: \"NC_COMMIT\",\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\",\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\",\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\",\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\",\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\",\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\",\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n commitCurrent: \"NC_COMMIT\";\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\";\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\";\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\";\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\";\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\";\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\";\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\"\n | \"traverseDirection\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,eAAe;CACf,0BAA0B;CAC1B,qCAAqC;CACrC,iCAAiC;CACjC,qCAAqC;CACrC,mCAAmC;CACnC,uCAAuC;CACvC,kCAAkC;CAClC,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AAgBD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AA2CD,SAAgB,qCAAqC,SAO3B;CACxB,OAAO;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,2BAA2B,QAAQ;EACnC,6BAA6B,QAAQ;EACrC,wBAAwB,QAAQ;EAChC,GAAI,QAAQ,wBAAwB,KAAA,IAChC,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,6BAA6B,QAAQ;EACtC;;AAGH,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;CACtB,OAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
1
+ {"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n cacheProofRejected: \"NC_CACHE_REJECT\",\n commitCurrent: \"NC_COMMIT\",\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\",\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\",\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\",\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\",\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\",\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\",\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n cacheProofRejected: \"NC_CACHE_REJECT\";\n commitCurrent: \"NC_COMMIT\";\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\";\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\";\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\";\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\";\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\";\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\";\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"cacheProofCode\"\n | \"cacheProofMode\"\n | \"cacheProofReuseClass\"\n | \"cacheProofScope\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\"\n | \"traverseDirection\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,oBAAoB;CACpB,eAAe;CACf,0BAA0B;CAC1B,qCAAqC;CACrC,iCAAiC;CACjC,qCAAqC;CACrC,mCAAmC;CACnC,uCAAuC;CACvC,kCAAkC;CAClC,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AAiBD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AA+CD,SAAgB,qCAAqC,SAO3B;CACxB,OAAO;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,2BAA2B,QAAQ;EACnC,6BAA6B,QAAQ;EACrC,wBAAwB,QAAQ;EAChC,GAAI,QAAQ,wBAAwB,KAAA,IAChC,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,6BAA6B,QAAQ;EACtC;;AAGH,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;CACtB,OAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
@@ -1,9 +1,27 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
+ import { ExecutionContextLike } from "../shims/request-context.js";
2
3
  import { PagesReqResRequest, PagesReqResResponse, PagesRequestQuery } from "./pages-node-compat.js";
3
4
 
4
5
  //#region src/server/pages-api-route.d.ts
6
+ type PagesApiRouteConfig = {
7
+ runtime?: string;
8
+ };
9
+ type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;
10
+ type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
5
11
  type PagesApiRouteModule = {
6
- default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;
12
+ /**
13
+ * `export const config = { runtime: 'edge' }` — historical Pages Router form.
14
+ */
15
+ config?: PagesApiRouteConfig;
16
+ /**
17
+ * `export const runtime = 'edge'` — bare export form. Next.js resolves the
18
+ * effective runtime as `config.runtime ?? config.config?.runtime`, so a
19
+ * top-level `runtime` export takes precedence over the nested config form.
20
+ *
21
+ * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts
22
+ */
23
+ runtime?: string;
24
+ default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;
7
25
  };
8
26
  type PagesApiRouteMatch = {
9
27
  params: PagesRequestQuery;
@@ -12,6 +30,14 @@ type PagesApiRouteMatch = {
12
30
  };
13
31
  };
14
32
  type HandlePagesApiRouteOptions = {
33
+ /**
34
+ * Per-request Cloudflare Workers `ExecutionContext`. When provided, the
35
+ * API route runs inside `runWithExecutionContext(ctx, ...)` so any
36
+ * `after()` (or other shim) call inside the handler can reach
37
+ * `ctx.waitUntil()` via the ALS and keep the isolate alive past the
38
+ * response. Omit on Node.js dev where no Workers lifecycle exists.
39
+ */
40
+ ctx?: ExecutionContextLike;
15
41
  match: PagesApiRouteMatch | null;
16
42
  reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;
17
43
  request: Request;
@@ -1,18 +1,39 @@
1
1
  import "./server-globals.js";
2
+ import { runWithExecutionContext } from "../shims/request-context.js";
3
+ import { NextRequest } from "../shims/server.js";
2
4
  import { internalServerErrorResponse } from "./http-error-responses.js";
3
5
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
4
6
  import { PagesBodyParseError } from "./pages-media-type.js";
7
+ import { isEdgeApiRuntime } from "./edge-api-runtime.js";
5
8
  import { createPagesReqRes, parsePagesApiBody } from "./pages-node-compat.js";
6
9
  //#region src/server/pages-api-route.ts
10
+ function resolveModuleRuntime(module) {
11
+ return module.runtime ?? module.config?.runtime;
12
+ }
7
13
  function buildPagesApiQuery(url, params) {
8
14
  return mergeRouteParamsIntoQuery(parseQueryString(url), params);
9
15
  }
16
+ function isEdgeApiRouteModule(module) {
17
+ return typeof module.default === "function" && isEdgeApiRuntime(resolveModuleRuntime(module));
18
+ }
19
+ function isNodeApiRouteModule(module) {
20
+ return typeof module.default === "function" && !isEdgeApiRuntime(resolveModuleRuntime(module));
21
+ }
10
22
  async function handlePagesApiRoute(options) {
23
+ if (options.ctx) return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));
24
+ return _handlePagesApiRoute(options);
25
+ }
26
+ async function _handlePagesApiRoute(options) {
11
27
  if (!options.match) return new Response("404 - API route not found", { status: 404 });
12
28
  const { route, params } = options.match;
13
- const handler = route.module.default;
14
- if (typeof handler !== "function") return new Response("API route does not export a default function", { status: 500 });
15
29
  try {
30
+ if (isEdgeApiRouteModule(route.module)) {
31
+ const nextRequest = new NextRequest(options.request);
32
+ const response = await route.module.default(nextRequest);
33
+ if (response instanceof Response) return response;
34
+ throw new Error("Edge API route did not return a Response");
35
+ }
36
+ if (!isNodeApiRouteModule(route.module)) return new Response("API route does not export a default function", { status: 500 });
16
37
  const query = buildPagesApiQuery(options.url, params);
17
38
  const { req, res, responsePromise } = createPagesReqRes({
18
39
  body: await parsePagesApiBody(options.request),
@@ -20,7 +41,7 @@ async function handlePagesApiRoute(options) {
20
41
  request: options.request,
21
42
  url: options.url
22
43
  });
23
- await handler(req, res);
44
+ await route.module.default(req, res);
24
45
  res.end();
25
46
  return await responsePromise;
26
47
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import \"./server-globals.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\ntype PagesApiRouteModule = {\n default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;\n};\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n return mergeRouteParamsIntoQuery(parseQueryString(url), params);\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n const handler = route.module.default;\n if (typeof handler !== \"function\") {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n try {\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await handler(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;;AA+BA,SAAS,mBAAmB,KAAa,QAA8C;CACrF,OAAO,0BAA0B,iBAAiB,IAAI,EAAE,OAAO;;AAGjE,eAAsB,oBAAoB,SAAwD;CAChG,IAAI,CAAC,QAAQ,OACX,OAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAClC,MAAM,UAAU,MAAM,OAAO;CAC7B,IAAI,OAAO,YAAY,YACrB,OAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;CAGtF,IAAI;EACF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAAA,MAFiB,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;EAEF,MAAM,QAAQ,KAAK,IAAI;EACvB,IAAI,KAAK;EACT,OAAO,MAAM;UACN,OAAO;EACd,IAAI,iBAAiBA,qBACnB,OAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;EAGJ,QAAa,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;EACD,OAAO,6BAA6B"}
1
+ {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import \"./server-globals.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\nimport { runWithExecutionContext, type ExecutionContextLike } from \"vinext/shims/request-context\";\nimport { NextRequest } from \"vinext/shims/server\";\n\ntype PagesApiRouteConfig = {\n runtime?: string;\n};\n\ntype PagesNodeApiRouteHandler = (\n req: PagesReqResRequest,\n res: PagesReqResResponse,\n) => void | Promise<void>;\n\ntype PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;\n\ntype PagesApiRouteModule = {\n /**\n * `export const config = { runtime: 'edge' }` — historical Pages Router form.\n */\n config?: PagesApiRouteConfig;\n /**\n * `export const runtime = 'edge'` — bare export form. Next.js resolves the\n * effective runtime as `config.runtime ?? config.config?.runtime`, so a\n * top-level `runtime` export takes precedence over the nested config form.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts\n */\n runtime?: string;\n default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;\n};\n\nfunction resolveModuleRuntime(module: PagesApiRouteModule): string | undefined {\n return module.runtime ?? module.config?.runtime;\n}\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n /**\n * Per-request Cloudflare Workers `ExecutionContext`. When provided, the\n * API route runs inside `runWithExecutionContext(ctx, ...)` so any\n * `after()` (or other shim) call inside the handler can reach\n * `ctx.waitUntil()` via the ALS and keep the isolate alive past the\n * response. Omit on Node.js dev where no Workers lifecycle exists.\n */\n ctx?: ExecutionContextLike;\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n return mergeRouteParamsIntoQuery(parseQueryString(url), params);\n}\n\nfunction isEdgeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesEdgeApiRouteHandler } {\n return typeof module.default === \"function\" && isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nfunction isNodeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesNodeApiRouteHandler } {\n return typeof module.default === \"function\" && !isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (options.ctx) {\n return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));\n }\n return _handlePagesApiRoute(options);\n}\n\nasync function _handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n\n try {\n if (isEdgeApiRouteModule(route.module)) {\n // Next.js wraps the incoming Request in a NextRequest before invoking\n // edge API handlers, so handlers can use `req.nextUrl.searchParams`,\n // `req.cookies`, etc. (Cf. NextRequestHint in next/src/server/web/adapter.ts.)\n const nextRequest = new NextRequest(options.request);\n const response = await route.module.default(nextRequest);\n if (response instanceof Response) {\n return response;\n }\n\n throw new Error(\"Edge API route did not return a Response\");\n }\n\n // This is redundant at runtime after the edge branch for function exports, but it\n // keeps the Node handler ABI narrowed without a production type assertion.\n if (!isNodeApiRouteModule(route.module)) {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await route.module.default(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;;;;;AA2CA,SAAS,qBAAqB,QAAiD;CAC7E,OAAO,OAAO,WAAW,OAAO,QAAQ;;AAyB1C,SAAS,mBAAmB,KAAa,QAA8C;CACrF,OAAO,0BAA0B,iBAAiB,IAAI,EAAE,OAAO;;AAGjE,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,iBAAiB,qBAAqB,OAAO,CAAC;;AAG/F,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,CAAC,iBAAiB,qBAAqB,OAAO,CAAC;;AAGhG,eAAsB,oBAAoB,SAAwD;CAChG,IAAI,QAAQ,KACV,OAAO,wBAAwB,QAAQ,WAAW,qBAAqB,QAAQ,CAAC;CAElF,OAAO,qBAAqB,QAAQ;;AAGtC,eAAe,qBAAqB,SAAwD;CAC1F,IAAI,CAAC,QAAQ,OACX,OAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAElC,IAAI;EACF,IAAI,qBAAqB,MAAM,OAAO,EAAE;GAItC,MAAM,cAAc,IAAI,YAAY,QAAQ,QAAQ;GACpD,MAAM,WAAW,MAAM,MAAM,OAAO,QAAQ,YAAY;GACxD,IAAI,oBAAoB,UACtB,OAAO;GAGT,MAAM,IAAI,MAAM,2CAA2C;;EAK7D,IAAI,CAAC,qBAAqB,MAAM,OAAO,EACrC,OAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;EAGtF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAAA,MAFiB,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;EAEF,MAAM,MAAM,OAAO,QAAQ,KAAK,IAAI;EACpC,IAAI,KAAK;EACT,OAAO,MAAM;UACN,OAAO;EACd,IAAI,iBAAiBA,qBACnB,OAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;EAGJ,QAAa,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;EACD,OAAO,6BAA6B"}