vinext 0.0.50 → 0.0.51

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 (309) hide show
  1. package/dist/build/google-fonts/fallback-metrics-data.js +14031 -0
  2. package/dist/build/google-fonts/fallback-metrics-data.js.map +1 -0
  3. package/dist/build/google-fonts/fallback-metrics.d.ts +13 -0
  4. package/dist/build/google-fonts/fallback-metrics.js +46 -0
  5. package/dist/build/google-fonts/fallback-metrics.js.map +1 -0
  6. package/dist/build/precompress.d.ts +13 -2
  7. package/dist/build/precompress.js +12 -3
  8. package/dist/build/precompress.js.map +1 -1
  9. package/dist/build/prerender.d.ts +1 -1
  10. package/dist/build/prerender.js +44 -14
  11. package/dist/build/prerender.js.map +1 -1
  12. package/dist/build/report.d.ts +5 -4
  13. package/dist/build/report.js +196 -348
  14. package/dist/build/report.js.map +1 -1
  15. package/dist/check.js +1 -0
  16. package/dist/check.js.map +1 -1
  17. package/dist/cli.js +60 -3
  18. package/dist/cli.js.map +1 -1
  19. package/dist/client/window-next.d.ts +3 -1
  20. package/dist/client/window-next.js.map +1 -1
  21. package/dist/config/dotenv.d.ts +11 -1
  22. package/dist/config/dotenv.js.map +1 -1
  23. package/dist/config/next-config.d.ts +87 -3
  24. package/dist/config/next-config.js +222 -6
  25. package/dist/config/next-config.js.map +1 -1
  26. package/dist/config/tsconfig-paths.d.ts +13 -0
  27. package/dist/config/tsconfig-paths.js +117 -0
  28. package/dist/config/tsconfig-paths.js.map +1 -0
  29. package/dist/deploy.js +3 -2
  30. package/dist/deploy.js.map +1 -1
  31. package/dist/entries/app-browser-entry.d.ts +2 -2
  32. package/dist/entries/app-browser-entry.js +26 -1
  33. package/dist/entries/app-browser-entry.js.map +1 -1
  34. package/dist/entries/app-rsc-entry.d.ts +19 -1
  35. package/dist/entries/app-rsc-entry.js +38 -12
  36. package/dist/entries/app-rsc-entry.js.map +1 -1
  37. package/dist/entries/app-rsc-manifest.d.ts +9 -0
  38. package/dist/entries/app-rsc-manifest.js +4 -1
  39. package/dist/entries/app-rsc-manifest.js.map +1 -1
  40. package/dist/entries/pages-client-entry.js +3 -5
  41. package/dist/entries/pages-client-entry.js.map +1 -1
  42. package/dist/entries/pages-server-entry.js +19 -1
  43. package/dist/entries/pages-server-entry.js.map +1 -1
  44. package/dist/index.js +130 -37
  45. package/dist/index.js.map +1 -1
  46. package/dist/plugins/client-reference-dedup.d.ts +15 -2
  47. package/dist/plugins/client-reference-dedup.js +138 -16
  48. package/dist/plugins/client-reference-dedup.js.map +1 -1
  49. package/dist/plugins/fonts.d.ts +2 -2
  50. package/dist/plugins/fonts.js +15 -6
  51. package/dist/plugins/fonts.js.map +1 -1
  52. package/dist/plugins/sass.d.ts +34 -0
  53. package/dist/plugins/sass.js +22 -0
  54. package/dist/plugins/sass.js.map +1 -0
  55. package/dist/routing/app-route-graph.d.ts +31 -2
  56. package/dist/routing/app-route-graph.js +82 -10
  57. package/dist/routing/app-route-graph.js.map +1 -1
  58. package/dist/routing/route-pattern.d.ts +56 -1
  59. package/dist/routing/route-pattern.js +60 -1
  60. package/dist/routing/route-pattern.js.map +1 -1
  61. package/dist/server/app-browser-action-result.d.ts +27 -2
  62. package/dist/server/app-browser-action-result.js +63 -2
  63. package/dist/server/app-browser-action-result.js.map +1 -1
  64. package/dist/server/app-browser-entry.js +262 -108
  65. package/dist/server/app-browser-entry.js.map +1 -1
  66. package/dist/server/app-browser-hydration.d.ts +13 -1
  67. package/dist/server/app-browser-hydration.js +9 -1
  68. package/dist/server/app-browser-hydration.js.map +1 -1
  69. package/dist/server/app-browser-navigation-controller.d.ts +14 -1
  70. package/dist/server/app-browser-navigation-controller.js +28 -9
  71. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  72. package/dist/server/app-browser-popstate.d.ts +16 -0
  73. package/dist/server/app-browser-popstate.js +17 -0
  74. package/dist/server/app-browser-popstate.js.map +1 -0
  75. package/dist/server/app-browser-rsc-redirect.d.ts +28 -0
  76. package/dist/server/app-browser-rsc-redirect.js +37 -0
  77. package/dist/server/app-browser-rsc-redirect.js.map +1 -0
  78. package/dist/server/app-browser-state.d.ts +11 -7
  79. package/dist/server/app-browser-state.js +45 -27
  80. package/dist/server/app-browser-state.js.map +1 -1
  81. package/dist/server/app-browser-stream.d.ts +5 -4
  82. package/dist/server/app-browser-stream.js +5 -6
  83. package/dist/server/app-browser-stream.js.map +1 -1
  84. package/dist/server/app-browser-visible-commit.d.ts +5 -0
  85. package/dist/server/app-browser-visible-commit.js +38 -5
  86. package/dist/server/app-browser-visible-commit.js.map +1 -1
  87. package/dist/server/app-elements-wire.d.ts +38 -6
  88. package/dist/server/app-elements-wire.js +106 -6
  89. package/dist/server/app-elements-wire.js.map +1 -1
  90. package/dist/server/app-elements.d.ts +2 -2
  91. package/dist/server/app-elements.js +2 -2
  92. package/dist/server/app-elements.js.map +1 -1
  93. package/dist/server/app-fallback-renderer.d.ts +10 -1
  94. package/dist/server/app-fallback-renderer.js +37 -1
  95. package/dist/server/app-fallback-renderer.js.map +1 -1
  96. package/dist/server/app-history-state.d.ts +26 -0
  97. package/dist/server/app-history-state.js +53 -0
  98. package/dist/server/app-history-state.js.map +1 -0
  99. package/dist/server/app-page-boundary-render.d.ts +10 -1
  100. package/dist/server/app-page-boundary-render.js +13 -6
  101. package/dist/server/app-page-boundary-render.js.map +1 -1
  102. package/dist/server/app-page-boundary.js +3 -2
  103. package/dist/server/app-page-boundary.js.map +1 -1
  104. package/dist/server/app-page-cache.d.ts +13 -0
  105. package/dist/server/app-page-cache.js +25 -8
  106. package/dist/server/app-page-cache.js.map +1 -1
  107. package/dist/server/app-page-dispatch.d.ts +5 -0
  108. package/dist/server/app-page-dispatch.js +68 -11
  109. package/dist/server/app-page-dispatch.js.map +1 -1
  110. package/dist/server/app-page-element-builder.d.ts +7 -0
  111. package/dist/server/app-page-element-builder.js +32 -4
  112. package/dist/server/app-page-element-builder.js.map +1 -1
  113. package/dist/server/app-page-execution.js +2 -3
  114. package/dist/server/app-page-execution.js.map +1 -1
  115. package/dist/server/app-page-head.d.ts +7 -0
  116. package/dist/server/app-page-head.js +2 -1
  117. package/dist/server/app-page-head.js.map +1 -1
  118. package/dist/server/app-page-probe.d.ts +23 -1
  119. package/dist/server/app-page-probe.js +29 -1
  120. package/dist/server/app-page-probe.js.map +1 -1
  121. package/dist/server/app-page-render-observation.d.ts +35 -0
  122. package/dist/server/app-page-render-observation.js +68 -0
  123. package/dist/server/app-page-render-observation.js.map +1 -0
  124. package/dist/server/app-page-render.d.ts +5 -1
  125. package/dist/server/app-page-render.js +79 -3
  126. package/dist/server/app-page-render.js.map +1 -1
  127. package/dist/server/app-page-request.d.ts +1 -0
  128. package/dist/server/app-page-request.js.map +1 -1
  129. package/dist/server/app-page-response.js +3 -2
  130. package/dist/server/app-page-response.js.map +1 -1
  131. package/dist/server/app-page-route-wiring.d.ts +3 -1
  132. package/dist/server/app-page-route-wiring.js +42 -14
  133. package/dist/server/app-page-route-wiring.js.map +1 -1
  134. package/dist/server/app-page-stream.d.ts +2 -0
  135. package/dist/server/app-page-stream.js +1 -0
  136. package/dist/server/app-page-stream.js.map +1 -1
  137. package/dist/server/app-router-entry.js +1 -13
  138. package/dist/server/app-router-entry.js.map +1 -1
  139. package/dist/server/app-rsc-cache-busting.d.ts +19 -1
  140. package/dist/server/app-rsc-cache-busting.js +36 -1
  141. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  142. package/dist/server/app-rsc-embedded-chunks.d.ts +9 -0
  143. package/dist/server/app-rsc-embedded-chunks.js +34 -0
  144. package/dist/server/app-rsc-embedded-chunks.js.map +1 -0
  145. package/dist/server/app-rsc-errors.d.ts +4 -1
  146. package/dist/server/app-rsc-errors.js +1 -1
  147. package/dist/server/app-rsc-errors.js.map +1 -1
  148. package/dist/server/app-rsc-handler.d.ts +12 -4
  149. package/dist/server/app-rsc-handler.js +6 -1
  150. package/dist/server/app-rsc-handler.js.map +1 -1
  151. package/dist/server/app-rsc-route-matching.d.ts +23 -0
  152. package/dist/server/app-rsc-route-matching.js +45 -23
  153. package/dist/server/app-rsc-route-matching.js.map +1 -1
  154. package/dist/server/app-server-action-execution.d.ts +35 -3
  155. package/dist/server/app-server-action-execution.js +87 -33
  156. package/dist/server/app-server-action-execution.js.map +1 -1
  157. package/dist/server/app-ssr-entry.d.ts +1 -0
  158. package/dist/server/app-ssr-entry.js +37 -13
  159. package/dist/server/app-ssr-entry.js.map +1 -1
  160. package/dist/server/app-ssr-error-meta.d.ts +14 -0
  161. package/dist/server/app-ssr-error-meta.js +50 -0
  162. package/dist/server/app-ssr-error-meta.js.map +1 -0
  163. package/dist/server/app-ssr-stream.d.ts +1 -1
  164. package/dist/server/app-ssr-stream.js +9 -12
  165. package/dist/server/app-ssr-stream.js.map +1 -1
  166. package/dist/server/artifact-compatibility.d.ts +12 -2
  167. package/dist/server/artifact-compatibility.js +12 -8
  168. package/dist/server/artifact-compatibility.js.map +1 -1
  169. package/dist/server/cache-proof.d.ts +124 -5
  170. package/dist/server/cache-proof.js +416 -18
  171. package/dist/server/cache-proof.js.map +1 -1
  172. package/dist/server/dev-lockfile.d.ts +110 -0
  173. package/dist/server/dev-lockfile.js +180 -0
  174. package/dist/server/dev-lockfile.js.map +1 -0
  175. package/dist/server/dev-server.js +15 -5
  176. package/dist/server/dev-server.js.map +1 -1
  177. package/dist/server/file-based-metadata.d.ts +13 -0
  178. package/dist/server/file-based-metadata.js +49 -2
  179. package/dist/server/file-based-metadata.js.map +1 -1
  180. package/dist/server/headers.d.ts +3 -1
  181. package/dist/server/headers.js +5 -2
  182. package/dist/server/headers.js.map +1 -1
  183. package/dist/server/html.js +1 -1
  184. package/dist/server/html.js.map +1 -1
  185. package/dist/server/http-error-responses.d.ts +10 -0
  186. package/dist/server/http-error-responses.js +11 -1
  187. package/dist/server/http-error-responses.js.map +1 -1
  188. package/dist/server/isr-cache.d.ts +2 -1
  189. package/dist/server/isr-cache.js +4 -2
  190. package/dist/server/isr-cache.js.map +1 -1
  191. package/dist/server/metadata-route-response.js +22 -5
  192. package/dist/server/metadata-route-response.js.map +1 -1
  193. package/dist/server/metadata-routes.js +27 -8
  194. package/dist/server/metadata-routes.js.map +1 -1
  195. package/dist/server/middleware-runtime.js +1 -0
  196. package/dist/server/middleware-runtime.js.map +1 -1
  197. package/dist/server/middleware.d.ts +12 -0
  198. package/dist/server/middleware.js +12 -0
  199. package/dist/server/middleware.js.map +1 -1
  200. package/dist/server/navigation-planner.d.ts +19 -5
  201. package/dist/server/navigation-planner.js +278 -17
  202. package/dist/server/navigation-planner.js.map +1 -1
  203. package/dist/server/navigation-trace.d.ts +8 -1
  204. package/dist/server/navigation-trace.js +7 -0
  205. package/dist/server/navigation-trace.js.map +1 -1
  206. package/dist/server/normalize-path.d.ts +2 -1
  207. package/dist/server/normalize-path.js +4 -1
  208. package/dist/server/normalize-path.js.map +1 -1
  209. package/dist/server/pages-api-route.js +1 -0
  210. package/dist/server/pages-api-route.js.map +1 -1
  211. package/dist/server/pages-page-data.d.ts +3 -2
  212. package/dist/server/pages-page-data.js +22 -3
  213. package/dist/server/pages-page-data.js.map +1 -1
  214. package/dist/server/pages-page-response.js +1 -1
  215. package/dist/server/prod-server.d.ts +28 -1
  216. package/dist/server/prod-server.js +62 -9
  217. package/dist/server/prod-server.js.map +1 -1
  218. package/dist/server/server-action-not-found.d.ts +16 -3
  219. package/dist/server/server-action-not-found.js +19 -1
  220. package/dist/server/server-action-not-found.js.map +1 -1
  221. package/dist/server/server-globals.d.ts +5 -0
  222. package/dist/server/server-globals.js +37 -0
  223. package/dist/server/server-globals.js.map +1 -0
  224. package/dist/server/static-file-cache.js +1 -1
  225. package/dist/server/static-file-cache.js.map +1 -1
  226. package/dist/shims/cache-runtime.d.ts +19 -2
  227. package/dist/shims/cache-runtime.js +67 -11
  228. package/dist/shims/cache-runtime.js.map +1 -1
  229. package/dist/shims/cache.d.ts +5 -18
  230. package/dist/shims/cache.js +2 -0
  231. package/dist/shims/cache.js.map +1 -1
  232. package/dist/shims/error-boundary.js +6 -8
  233. package/dist/shims/error-boundary.js.map +1 -1
  234. package/dist/shims/error.d.ts +18 -1
  235. package/dist/shims/error.js +56 -1
  236. package/dist/shims/error.js.map +1 -1
  237. package/dist/shims/fetch-cache.d.ts +4 -1
  238. package/dist/shims/fetch-cache.js +40 -5
  239. package/dist/shims/fetch-cache.js.map +1 -1
  240. package/dist/shims/font-google-base.d.ts +22 -8
  241. package/dist/shims/font-google-base.js +41 -71
  242. package/dist/shims/font-google-base.js.map +1 -1
  243. package/dist/shims/font-local.d.ts +3 -20
  244. package/dist/shims/font-local.js +23 -75
  245. package/dist/shims/font-local.js.map +1 -1
  246. package/dist/shims/font-utils.d.ts +51 -0
  247. package/dist/shims/font-utils.js +97 -0
  248. package/dist/shims/font-utils.js.map +1 -0
  249. package/dist/shims/hash-scroll.d.ts +7 -0
  250. package/dist/shims/hash-scroll.js +30 -0
  251. package/dist/shims/hash-scroll.js.map +1 -0
  252. package/dist/shims/headers.d.ts +8 -11
  253. package/dist/shims/headers.js +22 -2
  254. package/dist/shims/headers.js.map +1 -1
  255. package/dist/shims/image.d.ts +1 -0
  256. package/dist/shims/image.js +144 -78
  257. package/dist/shims/image.js.map +1 -1
  258. package/dist/shims/internal/app-router-context.d.ts +6 -6
  259. package/dist/shims/internal/app-router-context.js +17 -6
  260. package/dist/shims/internal/app-router-context.js.map +1 -1
  261. package/dist/shims/link-prefetch.d.ts +9 -1
  262. package/dist/shims/link-prefetch.js +11 -6
  263. package/dist/shims/link-prefetch.js.map +1 -1
  264. package/dist/shims/link.d.ts +12 -2
  265. package/dist/shims/link.js +78 -32
  266. package/dist/shims/link.js.map +1 -1
  267. package/dist/shims/metadata.d.ts +16 -30
  268. package/dist/shims/metadata.js +87 -28
  269. package/dist/shims/metadata.js.map +1 -1
  270. package/dist/shims/navigation.d.ts +158 -17
  271. package/dist/shims/navigation.js +324 -74
  272. package/dist/shims/navigation.js.map +1 -1
  273. package/dist/shims/navigation.react-server.d.ts +3 -2
  274. package/dist/shims/navigation.react-server.js +5 -2
  275. package/dist/shims/navigation.react-server.js.map +1 -1
  276. package/dist/shims/pages-router-runtime.d.ts +7 -0
  277. package/dist/shims/pages-router-runtime.js +16 -0
  278. package/dist/shims/pages-router-runtime.js.map +1 -0
  279. package/dist/shims/router.d.ts +32 -6
  280. package/dist/shims/router.js +197 -242
  281. package/dist/shims/router.js.map +1 -1
  282. package/dist/shims/script.js +110 -32
  283. package/dist/shims/script.js.map +1 -1
  284. package/dist/shims/server.js +2 -1
  285. package/dist/shims/server.js.map +1 -1
  286. package/dist/shims/slot.d.ts +1 -0
  287. package/dist/shims/slot.js +41 -1
  288. package/dist/shims/slot.js.map +1 -1
  289. package/dist/shims/unified-request-context.js +2 -0
  290. package/dist/shims/unified-request-context.js.map +1 -1
  291. package/dist/shims/unrecognized-action-error.d.ts +35 -0
  292. package/dist/shims/unrecognized-action-error.js +41 -0
  293. package/dist/shims/unrecognized-action-error.js.map +1 -0
  294. package/dist/shims/url-utils.d.ts +21 -1
  295. package/dist/shims/url-utils.js +67 -3
  296. package/dist/shims/url-utils.js.map +1 -1
  297. package/dist/utils/asset-prefix.d.ts +69 -0
  298. package/dist/utils/asset-prefix.js +91 -0
  299. package/dist/utils/asset-prefix.js.map +1 -0
  300. package/dist/utils/base-path.d.ts +7 -1
  301. package/dist/utils/base-path.js +10 -1
  302. package/dist/utils/base-path.js.map +1 -1
  303. package/dist/utils/navigation-signal.d.ts +1 -2
  304. package/dist/utils/navigation-signal.js +1 -1
  305. package/dist/utils/navigation-signal.js.map +1 -1
  306. package/dist/utils/sorted-array.d.ts +9 -0
  307. package/dist/utils/sorted-array.js +22 -0
  308. package/dist/utils/sorted-array.js.map +1 -0
  309. package/package.json +3 -3
@@ -1,15 +1,39 @@
1
+ import { isInterceptionMatchedUrlPath } from "./normalize-path.js";
1
2
  import { createArtifactCompatibilityEnvelope, parseArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
2
3
  import { isValidElement } from "react";
3
4
  //#region src/server/app-elements-wire.ts
4
5
  const APP_INTERCEPTION_SEPARATOR = "\0";
5
6
  const APP_ARTIFACT_COMPATIBILITY_KEY = "__artifactCompatibility";
7
+ const APP_INTERCEPTION_KEY = "__interception";
6
8
  const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
7
9
  const APP_LAYOUT_IDS_KEY = "__layoutIds";
8
10
  const APP_LAYOUT_FLAGS_KEY = "__layoutFlags";
11
+ const APP_RENDER_OBSERVATION_KEY = "__renderObservation";
9
12
  const APP_ROUTE_KEY = "__route";
10
13
  const APP_ROOT_LAYOUT_KEY = "__rootLayout";
14
+ const APP_SLOT_BINDINGS_KEY = "__slotBindings";
11
15
  const APP_UNMATCHED_SLOT_WIRE_VALUE = "__VINEXT_UNMATCHED_SLOT__";
12
16
  const UNMATCHED_SLOT = Symbol.for("vinext.unmatchedSlot");
17
+ function compareAppElementsSlotIds(left, right) {
18
+ if (left < right) return -1;
19
+ if (left > right) return 1;
20
+ return 0;
21
+ }
22
+ function compareAppElementsSlotBindingsBySlotId(left, right) {
23
+ return compareAppElementsSlotIds(left.slotId, right.slotId);
24
+ }
25
+ function normalizeAppElementsSlotBindings(slotBindings, options = {}) {
26
+ const ownerLayoutIds = options.layoutIds ? new Set(options.layoutIds) : null;
27
+ const seenSlotIds = /* @__PURE__ */ new Set();
28
+ const normalized = [];
29
+ for (const binding of slotBindings) {
30
+ if (seenSlotIds.has(binding.slotId)) throw new Error("[vinext] Invalid __slotBindings in App Router payload: duplicate slot id");
31
+ seenSlotIds.add(binding.slotId);
32
+ if (ownerLayoutIds && binding.ownerLayoutId !== null && !ownerLayoutIds.has(binding.ownerLayoutId)) throw new Error("[vinext] Invalid __slotBindings in App Router payload: owner layout id missing from __layoutIds");
33
+ normalized.push({ ...binding });
34
+ }
35
+ return normalized.sort(compareAppElementsSlotBindingsBySlotId);
36
+ }
13
37
  function appendInterceptionContext(identity, interceptionContext) {
14
38
  return interceptionContext === null ? identity : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;
15
39
  }
@@ -101,12 +125,22 @@ function isAppElementsWireSlotId(key) {
101
125
  return separatorIndex > 0 && body.charCodeAt(separatorIndex + 1) === 47;
102
126
  }
103
127
  function createAppElementsWireMetadataEntries(input) {
104
- return {
128
+ const layoutIds = [...input.layoutIds ?? []];
129
+ const entries = {
105
130
  [APP_ROUTE_KEY]: input.routeId,
106
131
  [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,
107
- [APP_LAYOUT_IDS_KEY]: [...input.layoutIds ?? []],
132
+ [APP_LAYOUT_IDS_KEY]: layoutIds,
108
133
  [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath
109
134
  };
135
+ const entriesWithInterception = input.interception ? {
136
+ ...entries,
137
+ [APP_INTERCEPTION_KEY]: input.interception
138
+ } : entries;
139
+ if (input.slotBindings && input.slotBindings.length > 0) return {
140
+ ...entriesWithInterception,
141
+ [APP_SLOT_BINDINGS_KEY]: normalizeAppElementsSlotBindings(input.slotBindings, { layoutIds })
142
+ };
143
+ return entriesWithInterception;
110
144
  }
111
145
  function normalizeAppElements(elements) {
112
146
  let needsNormalization = false;
@@ -124,6 +158,9 @@ function isLayoutFlagsRecord(value) {
124
158
  for (const v of Object.values(value)) if (v !== "s" && v !== "d") return false;
125
159
  return true;
126
160
  }
161
+ function isRecord(value) {
162
+ return typeof value === "object" && value !== null && !Array.isArray(value);
163
+ }
127
164
  function parseLayoutFlags(value) {
128
165
  if (isLayoutFlagsRecord(value)) return value;
129
166
  return {};
@@ -139,6 +176,60 @@ function parseLayoutIds(value) {
139
176
  }
140
177
  return layoutIds;
141
178
  }
179
+ function isSlotBindingState(value) {
180
+ return value === "active" || value === "default" || value === "unmatched";
181
+ }
182
+ function parseSlotBindings(value, options = {}) {
183
+ if (value === void 0) return [];
184
+ if (!Array.isArray(value)) throw new Error("[vinext] Invalid __slotBindings in App Router payload: expected array");
185
+ const slotBindings = [];
186
+ for (const entry of value) {
187
+ if (!isRecord(entry)) throw new Error("[vinext] Invalid __slotBindings in App Router payload: expected objects");
188
+ const slotId = entry.slotId;
189
+ if (typeof slotId !== "string" || parseAppElementsWireElementKey(slotId)?.kind !== "slot") throw new Error("[vinext] Invalid __slotBindings in App Router payload: expected slot ids");
190
+ const ownerLayoutId = entry.ownerLayoutId;
191
+ if (ownerLayoutId !== null && (typeof ownerLayoutId !== "string" || parseAppElementsWireElementKey(ownerLayoutId)?.kind !== "layout")) throw new Error("[vinext] Invalid __slotBindings in App Router payload: expected owner layout ids");
192
+ const state = entry.state;
193
+ if (!isSlotBindingState(state)) throw new Error("[vinext] Invalid __slotBindings in App Router payload: expected state");
194
+ slotBindings.push({
195
+ ownerLayoutId,
196
+ slotId,
197
+ state
198
+ });
199
+ }
200
+ return normalizeAppElementsSlotBindings(slotBindings, options);
201
+ }
202
+ function readRequiredInterceptionString(entry, fieldName) {
203
+ const value = entry[fieldName];
204
+ if (typeof value !== "string") throw new Error("[vinext] Invalid __interception in App Router payload: expected strings");
205
+ return value;
206
+ }
207
+ function parseInterceptionMatchedUrl(value) {
208
+ if (!isInterceptionMatchedUrlPath(value)) throw new Error("[vinext] Invalid __interception in App Router payload: expected path URLs");
209
+ return value;
210
+ }
211
+ function parseInterceptionRouteId(value, matchedUrl) {
212
+ const parsed = parseAppElementsWireElementKey(value);
213
+ if (parsed?.kind !== "route" || parsed.path !== matchedUrl || parsed.interceptionContext !== null) throw new Error("[vinext] Invalid __interception in App Router payload: expected route ids");
214
+ return value;
215
+ }
216
+ function parseInterceptionSlotId(value) {
217
+ if (parseAppElementsWireElementKey(value)?.kind !== "slot") throw new Error("[vinext] Invalid __interception in App Router payload: expected slot id");
218
+ return value;
219
+ }
220
+ function parseInterceptionMetadata(value) {
221
+ if (value === void 0 || value === null) return null;
222
+ if (!isRecord(value)) throw new Error("[vinext] Invalid __interception in App Router payload: expected object");
223
+ const sourceMatchedUrl = parseInterceptionMatchedUrl(readRequiredInterceptionString(value, "sourceMatchedUrl"));
224
+ const targetMatchedUrl = parseInterceptionMatchedUrl(readRequiredInterceptionString(value, "targetMatchedUrl"));
225
+ return {
226
+ sourceMatchedUrl,
227
+ sourceRouteId: parseInterceptionRouteId(readRequiredInterceptionString(value, "sourceRouteId"), sourceMatchedUrl),
228
+ slotId: parseInterceptionSlotId(readRequiredInterceptionString(value, "slotId")),
229
+ targetMatchedUrl,
230
+ targetRouteId: parseInterceptionRouteId(readRequiredInterceptionString(value, "targetRouteId"), targetMatchedUrl)
231
+ };
232
+ }
142
233
  /**
143
234
  * Type predicate for a plain (non-null, non-array) record of app payload values.
144
235
  * Used to distinguish the App Router payload object from bare React elements at
@@ -162,11 +253,13 @@ function withLayoutFlags(elements, layoutFlags) {
162
253
  }
163
254
  function buildOutgoingAppPayload(input) {
164
255
  if (!isAppElementsRecord(input.element)) return input.element;
165
- return {
256
+ const payload = {
166
257
  ...input.element,
167
258
  [APP_LAYOUT_FLAGS_KEY]: input.layoutFlags,
168
259
  [APP_ARTIFACT_COMPATIBILITY_KEY]: input.artifactCompatibility ?? createArtifactCompatibilityEnvelope()
169
260
  };
261
+ if (input.renderObservation) payload[APP_RENDER_OBSERVATION_KEY] = input.renderObservation;
262
+ return payload;
170
263
  }
171
264
  function readArtifactCompatibilityMetadata(value) {
172
265
  if (value === void 0) return createArtifactCompatibilityEnvelope();
@@ -182,23 +275,30 @@ function readAppElementsMetadata(elements) {
182
275
  if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== "string") throw new Error("[vinext] Invalid __rootLayout in App Router payload: expected string or null");
183
276
  const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);
184
277
  const layoutIds = parseLayoutIds(elements[APP_LAYOUT_IDS_KEY]);
278
+ const slotBindings = parseSlotBindings(elements[APP_SLOT_BINDINGS_KEY], { layoutIds });
279
+ const interception = parseInterceptionMetadata(elements[APP_INTERCEPTION_KEY]);
185
280
  return {
186
281
  artifactCompatibility: readArtifactCompatibilityMetadata(elements[APP_ARTIFACT_COMPATIBILITY_KEY]),
282
+ interception,
187
283
  interceptionContext: interceptionContext ?? null,
188
284
  layoutIds,
189
285
  layoutFlags,
190
286
  routeId,
191
- rootLayoutTreePath
287
+ rootLayoutTreePath,
288
+ slotBindings
192
289
  };
193
290
  }
194
291
  const AppElementsWire = {
195
292
  keys: {
196
293
  artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,
294
+ interception: APP_INTERCEPTION_KEY,
197
295
  interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,
198
296
  layoutIds: APP_LAYOUT_IDS_KEY,
199
297
  layoutFlags: APP_LAYOUT_FLAGS_KEY,
298
+ renderObservation: APP_RENDER_OBSERVATION_KEY,
200
299
  rootLayout: APP_ROOT_LAYOUT_KEY,
201
- route: APP_ROUTE_KEY
300
+ route: APP_ROUTE_KEY,
301
+ slotBindings: APP_SLOT_BINDINGS_KEY
202
302
  },
203
303
  unmatchedSlotValue: APP_UNMATCHED_SLOT_WIRE_VALUE,
204
304
  createMetadataEntries: createAppElementsWireMetadataEntries,
@@ -216,6 +316,6 @@ const AppElementsWire = {
216
316
  withLayoutFlags
217
317
  };
218
318
  //#endregion
219
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags };
319
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SLOT_BINDINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags };
220
320
 
221
321
  //# sourceMappingURL=app-elements-wire.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-elements-wire.js","names":[],"sources":["../../src/server/app-elements-wire.ts"],"sourcesContent":["import { isValidElement, type ReactNode } from \"react\";\nimport {\n createArtifactCompatibilityEnvelope,\n parseArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEnvelope,\n} from \"./artifact-compatibility.js\";\n\nconst APP_INTERCEPTION_SEPARATOR = \"\\0\";\n\nexport const APP_ARTIFACT_COMPATIBILITY_KEY = \"__artifactCompatibility\";\nexport const APP_INTERCEPTION_CONTEXT_KEY = \"__interceptionContext\";\nexport const APP_LAYOUT_IDS_KEY = \"__layoutIds\";\nexport const APP_LAYOUT_FLAGS_KEY = \"__layoutFlags\";\nexport const APP_ROUTE_KEY = \"__route\";\nexport const APP_ROOT_LAYOUT_KEY = \"__rootLayout\";\nexport const APP_UNMATCHED_SLOT_WIRE_VALUE = \"__VINEXT_UNMATCHED_SLOT__\";\n\nexport const UNMATCHED_SLOT = Symbol.for(\"vinext.unmatchedSlot\");\n\nexport type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null;\ntype AppWireElementValue = ReactNode | string | null;\n\nexport type AppElements = Readonly<Record<string, AppElementValue>>;\nexport type AppWireElements = Readonly<Record<string, AppWireElementValue>>;\n\n/**\n * Per-layout static/dynamic flags. `\"s\"` = static (skippable on next nav);\n * `\"d\"` = dynamic (must always render).\n *\n * Lifecycle (partial — later PRs extend this):\n *\n * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns\n * LayoutFlags for every layout in the route at render time.\n *\n * 2. ATTACH — AppElementsWire.encodeOutgoingPayload writes `__layoutFlags`\n * into the outgoing App Router payload record.\n *\n * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.\n *\n * 4. PARSE — AppElementsWire.readMetadata extracts layoutFlags from the\n * wire payload on the client side.\n */\nexport type LayoutFlags = Readonly<Record<string, \"s\" | \"d\">>;\n\ntype AppElementsMetadata = {\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n interceptionContext: string | null;\n layoutIds: readonly string[];\n layoutFlags: LayoutFlags;\n routeId: string;\n rootLayoutTreePath: string | null;\n};\n\ntype AppElementsWireElementKey =\n | { kind: \"layout\"; treePath: string }\n | { interceptionContext: string | null; kind: \"page\"; path: string }\n | { interceptionContext: string | null; kind: \"route\"; path: string }\n | { kind: \"slot\"; name: string; treePath: string }\n | { kind: \"template\"; treePath: string };\n\ntype AppElementsWireMetadataInput = {\n interceptionContext: string | null;\n layoutIds?: readonly string[];\n routeId: string;\n rootLayoutTreePath: string | null;\n};\n\ntype AppElementsWireMetadataEntries = Readonly<{\n [APP_ROUTE_KEY]: string;\n [APP_INTERCEPTION_CONTEXT_KEY]: string | null;\n [APP_LAYOUT_IDS_KEY]: readonly string[];\n [APP_ROOT_LAYOUT_KEY]: string | null;\n}>;\n\n/**\n * The outgoing wire payload shape. Includes ReactNode values for the\n * rendered tree plus metadata values like LayoutFlags attached under\n * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements\n * which only carry render-time values.\n */\nexport type AppOutgoingElements = Readonly<\n Record<string, ReactNode | LayoutFlags | ArtifactCompatibilityEnvelope>\n>;\n\ntype AppElementsWireKeys = {\n readonly artifactCompatibility: typeof APP_ARTIFACT_COMPATIBILITY_KEY;\n readonly interceptionContext: typeof APP_INTERCEPTION_CONTEXT_KEY;\n readonly layoutIds: typeof APP_LAYOUT_IDS_KEY;\n readonly layoutFlags: typeof APP_LAYOUT_FLAGS_KEY;\n readonly rootLayout: typeof APP_ROOT_LAYOUT_KEY;\n readonly route: typeof APP_ROUTE_KEY;\n};\n\ntype AppElementsWireCodec = {\n readonly keys: AppElementsWireKeys;\n readonly unmatchedSlotValue: typeof APP_UNMATCHED_SLOT_WIRE_VALUE;\n createMetadataEntries(input: AppElementsWireMetadataInput): AppElementsWireMetadataEntries;\n decode(elements: AppWireElements): AppElements;\n encodeCacheKey(rscUrl: string, interceptionContext: string | null): string;\n encodeLayoutId(treePath: string): string;\n encodeOutgoingPayload(input: {\n element: ReactNode | Readonly<Record<string, ReactNode>>;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n }): ReactNode | AppOutgoingElements;\n encodePageId(routePath: string, interceptionContext: string | null): string;\n encodeRouteId(routePath: string, interceptionContext: string | null): string;\n encodeSlotId(slotName: string, treePath: string): string;\n encodeTemplateId(treePath: string): string;\n isSlotId(key: string): boolean;\n parseElementKey(key: string): AppElementsWireElementKey | null;\n readMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;\n withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n ): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags };\n};\n\nfunction appendInterceptionContext(identity: string, interceptionContext: string | null): string {\n return interceptionContext === null\n ? identity\n : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;\n}\n\nfunction createAppPayloadRouteId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`route:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadPageId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`page:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadLayoutId(treePath: string): string {\n return `layout:${treePath}`;\n}\n\nfunction createAppPayloadTemplateId(treePath: string): string {\n return `template:${treePath}`;\n}\n\nfunction createAppPayloadSlotId(slotName: string, treePath: string): string {\n return `slot:${slotName}:${treePath}`;\n}\n\nfunction createAppPayloadCacheKey(rscUrl: string, interceptionContext: string | null): string {\n return appendInterceptionContext(rscUrl, interceptionContext);\n}\n\nfunction parsePathWithInterception(input: string): {\n interceptionContext: string | null;\n path: string;\n} | null {\n const separatorIndex = input.indexOf(APP_INTERCEPTION_SEPARATOR);\n const path = separatorIndex === -1 ? input : input.slice(0, separatorIndex);\n if (!path.startsWith(\"/\")) return null;\n\n return {\n interceptionContext: separatorIndex === -1 ? null : input.slice(separatorIndex + 1),\n path,\n };\n}\n\n/**\n * AppElements tree paths are absolute route-tree paths on the wire.\n * Bare segment names are not valid layout/template/slot tree identities.\n */\nfunction parseTreePath(input: string): string | null {\n return input.startsWith(\"/\") ? input : null;\n}\n\nfunction parseAppElementsWireElementKey(key: string): AppElementsWireElementKey | null {\n if (key.startsWith(\"route:\")) {\n const parsed = parsePathWithInterception(key.slice(\"route:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"route\", path: parsed.path };\n }\n\n if (key.startsWith(\"page:\")) {\n const parsed = parsePathWithInterception(key.slice(\"page:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"page\", path: parsed.path };\n }\n\n if (key.startsWith(\"layout:\")) {\n const treePath = parseTreePath(key.slice(\"layout:\".length));\n return treePath ? { kind: \"layout\", treePath } : null;\n }\n\n if (key.startsWith(\"template:\")) {\n const treePath = parseTreePath(key.slice(\"template:\".length));\n return treePath ? { kind: \"template\", treePath } : null;\n }\n\n if (key.startsWith(\"slot:\")) {\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n if (separatorIndex <= 0) return null;\n const name = body.slice(0, separatorIndex);\n const treePath = parseTreePath(body.slice(separatorIndex + 1));\n return treePath ? { kind: \"slot\", name, treePath } : null;\n }\n\n return null;\n}\n\nfunction isAppElementsWireSlotId(key: string): boolean {\n if (!key.startsWith(\"slot:\")) return false;\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n return separatorIndex > 0 && body.charCodeAt(separatorIndex + 1) === 0x2f;\n}\n\nfunction createAppElementsWireMetadataEntries(\n input: AppElementsWireMetadataInput,\n): AppElementsWireMetadataEntries {\n return {\n [APP_ROUTE_KEY]: input.routeId,\n [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,\n [APP_LAYOUT_IDS_KEY]: [...(input.layoutIds ?? [])],\n [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath,\n };\n}\n\nexport function normalizeAppElements(elements: AppWireElements): AppElements {\n let needsNormalization = false;\n for (const [key, value] of Object.entries(elements)) {\n if (isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE) {\n needsNormalization = true;\n break;\n }\n }\n\n if (!needsNormalization) {\n return elements;\n }\n\n const normalized: Record<string, AppElementValue> = {};\n for (const [key, value] of Object.entries(elements)) {\n normalized[key] =\n isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE\n ? UNMATCHED_SLOT\n : value;\n }\n\n return normalized;\n}\n\nfunction isLayoutFlagsRecord(value: unknown): value is LayoutFlags {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n for (const v of Object.values(value)) {\n if (v !== \"s\" && v !== \"d\") return false;\n }\n return true;\n}\n\nfunction parseLayoutFlags(value: unknown): LayoutFlags {\n if (isLayoutFlagsRecord(value)) return value;\n return {};\n}\n\nfunction parseLayoutIds(value: unknown): readonly string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n throw new Error(\n \"[vinext] Invalid __layoutIds in App Router payload: expected layout id string[]\",\n );\n }\n\n const layoutIds: string[] = [];\n for (const entry of value) {\n if (typeof entry !== \"string\") {\n throw new Error(\n \"[vinext] Invalid __layoutIds in App Router payload: expected layout id string[]\",\n );\n }\n\n const parsed = parseAppElementsWireElementKey(entry);\n if (parsed?.kind !== \"layout\") {\n throw new Error(\"[vinext] Invalid __layoutIds in App Router payload: expected layout ids\");\n }\n\n layoutIds.push(entry);\n }\n return layoutIds;\n}\n\n/**\n * Type predicate for a plain (non-null, non-array) record of app payload values.\n * Used to distinguish the App Router payload object from bare React elements at\n * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because\n * the outgoing payload carries heterogeneous values (ReactNodes for the rendered\n * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates\n * to React's canonical `isValidElement` so we don't depend on React's internal\n * `$$typeof` marker scheme.\n */\nexport function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) return false;\n if (Array.isArray(value)) return false;\n if (isValidElement(value)) return false;\n return true;\n}\n\nexport function withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags } {\n return { ...elements, [APP_LAYOUT_FLAGS_KEY]: layoutFlags };\n}\n\nexport function buildOutgoingAppPayload(input: {\n element: ReactNode | Readonly<Record<string, ReactNode>>;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n}): ReactNode | AppOutgoingElements {\n if (!isAppElementsRecord(input.element)) {\n return input.element;\n }\n return {\n ...input.element,\n [APP_LAYOUT_FLAGS_KEY]: input.layoutFlags,\n [APP_ARTIFACT_COMPATIBILITY_KEY]:\n input.artifactCompatibility ?? createArtifactCompatibilityEnvelope(),\n };\n}\n\nfunction readArtifactCompatibilityMetadata(value: unknown): ArtifactCompatibilityEnvelope {\n if (value === undefined) return createArtifactCompatibilityEnvelope();\n\n const artifactCompatibility = parseArtifactCompatibilityEnvelope(value);\n // TODO(#726-COMPAT-04): hard-fail malformed compatibility metadata once\n // cache/skip consumers depend on this proof. During Wave01 the field is\n // emitted as scaffolding, so bad or future-version values degrade like\n // missing __layoutFlags instead of crashing render paths that do not read it.\n return artifactCompatibility ?? createArtifactCompatibilityEnvelope();\n}\n\nexport function readAppElementsMetadata(\n elements: Readonly<Record<string, unknown>>,\n): AppElementsMetadata {\n const routeId = elements[APP_ROUTE_KEY];\n if (typeof routeId !== \"string\") {\n throw new Error(\"[vinext] Missing __route string in App Router payload\");\n }\n\n const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];\n if (\n interceptionContext !== undefined &&\n interceptionContext !== null &&\n typeof interceptionContext !== \"string\"\n ) {\n throw new Error(\"[vinext] Invalid __interceptionContext in App Router payload\");\n }\n\n const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];\n if (rootLayoutTreePath === undefined) {\n throw new Error(\"[vinext] Missing __rootLayout key in App Router payload\");\n }\n if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== \"string\") {\n throw new Error(\"[vinext] Invalid __rootLayout in App Router payload: expected string or null\");\n }\n\n const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);\n const layoutIds = parseLayoutIds(elements[APP_LAYOUT_IDS_KEY]);\n const artifactCompatibility = readArtifactCompatibilityMetadata(\n elements[APP_ARTIFACT_COMPATIBILITY_KEY],\n );\n\n return {\n artifactCompatibility,\n interceptionContext: interceptionContext ?? null,\n layoutIds,\n layoutFlags,\n routeId,\n rootLayoutTreePath,\n };\n}\n\nexport const AppElementsWire: AppElementsWireCodec = {\n // WIRE follow-ups use these stable key names when moving payload readers and writers\n // behind the codec boundary.\n keys: {\n artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,\n interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,\n layoutIds: APP_LAYOUT_IDS_KEY,\n layoutFlags: APP_LAYOUT_FLAGS_KEY,\n rootLayout: APP_ROOT_LAYOUT_KEY,\n route: APP_ROUTE_KEY,\n },\n unmatchedSlotValue: APP_UNMATCHED_SLOT_WIRE_VALUE,\n createMetadataEntries: createAppElementsWireMetadataEntries,\n decode: normalizeAppElements,\n encodeCacheKey: createAppPayloadCacheKey,\n encodeLayoutId: createAppPayloadLayoutId,\n encodeOutgoingPayload: buildOutgoingAppPayload,\n encodePageId: createAppPayloadPageId,\n encodeRouteId: createAppPayloadRouteId,\n encodeSlotId: createAppPayloadSlotId,\n encodeTemplateId: createAppPayloadTemplateId,\n isSlotId: isAppElementsWireSlotId,\n parseElementKey: parseAppElementsWireElementKey,\n readMetadata: readAppElementsMetadata,\n withLayoutFlags,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-elements-wire.js","names":[],"sources":["../../src/server/app-elements-wire.ts"],"sourcesContent":["import { isValidElement, type ReactNode } from \"react\";\nimport {\n createArtifactCompatibilityEnvelope,\n parseArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEnvelope,\n} from \"./artifact-compatibility.js\";\nimport type { RenderObservation } from \"./cache-proof.js\";\nimport { isInterceptionMatchedUrlPath } from \"./normalize-path.js\";\n\nconst APP_INTERCEPTION_SEPARATOR = \"\\0\";\n\nexport const APP_ARTIFACT_COMPATIBILITY_KEY = \"__artifactCompatibility\";\nexport const APP_INTERCEPTION_KEY = \"__interception\";\nexport const APP_INTERCEPTION_CONTEXT_KEY = \"__interceptionContext\";\nexport const APP_LAYOUT_IDS_KEY = \"__layoutIds\";\nexport const APP_LAYOUT_FLAGS_KEY = \"__layoutFlags\";\nexport const APP_RENDER_OBSERVATION_KEY = \"__renderObservation\";\nexport const APP_ROUTE_KEY = \"__route\";\nexport const APP_ROOT_LAYOUT_KEY = \"__rootLayout\";\nexport const APP_SLOT_BINDINGS_KEY = \"__slotBindings\";\nexport const APP_UNMATCHED_SLOT_WIRE_VALUE = \"__VINEXT_UNMATCHED_SLOT__\";\n\nexport const UNMATCHED_SLOT = Symbol.for(\"vinext.unmatchedSlot\");\n\nexport type AppElementsSlotBindingState = \"active\" | \"default\" | \"unmatched\";\n\nexport type AppElementsSlotBinding = Readonly<{\n ownerLayoutId: string | null;\n slotId: string;\n state: AppElementsSlotBindingState;\n}>;\n\nexport type AppElementsInterception = Readonly<{\n sourceMatchedUrl: string;\n sourceRouteId: string;\n slotId: string;\n targetMatchedUrl: string;\n targetRouteId: string;\n}>;\n\nexport function compareAppElementsSlotIds(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction compareAppElementsSlotBindingsBySlotId(\n left: Pick<AppElementsSlotBinding, \"slotId\">,\n right: Pick<AppElementsSlotBinding, \"slotId\">,\n): number {\n return compareAppElementsSlotIds(left.slotId, right.slotId);\n}\n\nexport function normalizeAppElementsSlotBindings(\n slotBindings: readonly AppElementsSlotBinding[],\n options: { layoutIds?: readonly string[] } = {},\n): readonly AppElementsSlotBinding[] {\n const ownerLayoutIds = options.layoutIds ? new Set(options.layoutIds) : null;\n const seenSlotIds = new Set<string>();\n const normalized: AppElementsSlotBinding[] = [];\n\n for (const binding of slotBindings) {\n if (seenSlotIds.has(binding.slotId)) {\n throw new Error(\"[vinext] Invalid __slotBindings in App Router payload: duplicate slot id\");\n }\n seenSlotIds.add(binding.slotId);\n\n if (\n ownerLayoutIds &&\n binding.ownerLayoutId !== null &&\n !ownerLayoutIds.has(binding.ownerLayoutId)\n ) {\n throw new Error(\n \"[vinext] Invalid __slotBindings in App Router payload: owner layout id missing from __layoutIds\",\n );\n }\n\n normalized.push({ ...binding });\n }\n\n return normalized.sort(compareAppElementsSlotBindingsBySlotId);\n}\n\nexport type AppElementValue =\n | ReactNode\n | typeof UNMATCHED_SLOT\n | string\n | null\n | LayoutFlags\n | ArtifactCompatibilityEnvelope\n | AppElementsInterception\n | readonly AppElementsSlotBinding[];\ntype AppWireElementValue =\n | ReactNode\n | string\n | null\n | LayoutFlags\n | ArtifactCompatibilityEnvelope\n | AppElementsInterception\n | readonly AppElementsSlotBinding[];\n\nexport type AppElements = Readonly<Record<string, AppElementValue>>;\nexport type AppWireElements = Readonly<Record<string, AppWireElementValue>>;\n\n/**\n * Per-layout static/dynamic flags. `\"s\"` = static (skippable on next nav);\n * `\"d\"` = dynamic (must always render).\n *\n * Lifecycle (partial — later PRs extend this):\n *\n * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns\n * LayoutFlags for every layout in the route at render time.\n *\n * 2. ATTACH — AppElementsWire.encodeOutgoingPayload writes `__layoutFlags`\n * into the outgoing App Router payload record.\n *\n * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.\n *\n * 4. PARSE — AppElementsWire.readMetadata extracts layoutFlags from the\n * wire payload on the client side.\n */\nexport type LayoutFlags = Readonly<Record<string, \"s\" | \"d\">>;\n\ntype AppElementsMetadata = {\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n interception: AppElementsInterception | null;\n interceptionContext: string | null;\n layoutIds: readonly string[];\n layoutFlags: LayoutFlags;\n routeId: string;\n rootLayoutTreePath: string | null;\n slotBindings: readonly AppElementsSlotBinding[];\n};\n\ntype AppElementsWireElementKey =\n | { kind: \"layout\"; treePath: string }\n | { interceptionContext: string | null; kind: \"page\"; path: string }\n | { interceptionContext: string | null; kind: \"route\"; path: string }\n | { kind: \"slot\"; name: string; treePath: string }\n | { kind: \"template\"; treePath: string };\n\ntype AppElementsWireMetadataInput = {\n interception?: AppElementsInterception | null;\n interceptionContext: string | null;\n layoutIds?: readonly string[];\n routeId: string;\n rootLayoutTreePath: string | null;\n slotBindings?: readonly AppElementsSlotBinding[];\n};\n\ntype AppElementsWireMetadataEntries = Readonly<{\n [APP_ROUTE_KEY]: string;\n [APP_INTERCEPTION_KEY]?: AppElementsInterception;\n [APP_INTERCEPTION_CONTEXT_KEY]: string | null;\n [APP_LAYOUT_IDS_KEY]: readonly string[];\n [APP_ROOT_LAYOUT_KEY]: string | null;\n [APP_SLOT_BINDINGS_KEY]?: readonly AppElementsSlotBinding[];\n}>;\n\n/**\n * The outgoing wire payload shape. Includes ReactNode values for the\n * rendered tree plus metadata values like LayoutFlags attached under\n * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements\n * which only carry render-time values.\n */\nexport type AppOutgoingElements = Readonly<\n Record<\n string,\n | ReactNode\n | LayoutFlags\n | ArtifactCompatibilityEnvelope\n | AppElementsInterception\n | RenderObservation\n | readonly AppElementsSlotBinding[]\n >\n>;\n\ntype AppElementsWireKeys = {\n readonly artifactCompatibility: typeof APP_ARTIFACT_COMPATIBILITY_KEY;\n readonly interception: typeof APP_INTERCEPTION_KEY;\n readonly interceptionContext: typeof APP_INTERCEPTION_CONTEXT_KEY;\n readonly layoutIds: typeof APP_LAYOUT_IDS_KEY;\n readonly layoutFlags: typeof APP_LAYOUT_FLAGS_KEY;\n readonly renderObservation: typeof APP_RENDER_OBSERVATION_KEY;\n readonly rootLayout: typeof APP_ROOT_LAYOUT_KEY;\n readonly route: typeof APP_ROUTE_KEY;\n readonly slotBindings: typeof APP_SLOT_BINDINGS_KEY;\n};\n\ntype AppElementsWireCodec = {\n readonly keys: AppElementsWireKeys;\n readonly unmatchedSlotValue: typeof APP_UNMATCHED_SLOT_WIRE_VALUE;\n createMetadataEntries(input: AppElementsWireMetadataInput): AppElementsWireMetadataEntries;\n decode(elements: AppWireElements): AppElements;\n encodeCacheKey(rscUrl: string, interceptionContext: string | null): string;\n encodeLayoutId(treePath: string): string;\n encodeOutgoingPayload(input: {\n element:\n | ReactNode\n | Readonly<\n Record<string, ReactNode | AppElementsInterception | readonly AppElementsSlotBinding[]>\n >;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n renderObservation?: RenderObservation;\n }): ReactNode | AppOutgoingElements;\n encodePageId(routePath: string, interceptionContext: string | null): string;\n encodeRouteId(routePath: string, interceptionContext: string | null): string;\n encodeSlotId(slotName: string, treePath: string): string;\n encodeTemplateId(treePath: string): string;\n isSlotId(key: string): boolean;\n parseElementKey(key: string): AppElementsWireElementKey | null;\n readMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;\n withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n ): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags };\n};\n\nfunction appendInterceptionContext(identity: string, interceptionContext: string | null): string {\n return interceptionContext === null\n ? identity\n : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;\n}\n\nfunction createAppPayloadRouteId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`route:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadPageId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`page:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadLayoutId(treePath: string): string {\n return `layout:${treePath}`;\n}\n\nfunction createAppPayloadTemplateId(treePath: string): string {\n return `template:${treePath}`;\n}\n\nfunction createAppPayloadSlotId(slotName: string, treePath: string): string {\n return `slot:${slotName}:${treePath}`;\n}\n\nfunction createAppPayloadCacheKey(rscUrl: string, interceptionContext: string | null): string {\n return appendInterceptionContext(rscUrl, interceptionContext);\n}\n\nfunction parsePathWithInterception(input: string): {\n interceptionContext: string | null;\n path: string;\n} | null {\n const separatorIndex = input.indexOf(APP_INTERCEPTION_SEPARATOR);\n const path = separatorIndex === -1 ? input : input.slice(0, separatorIndex);\n if (!path.startsWith(\"/\")) return null;\n\n return {\n interceptionContext: separatorIndex === -1 ? null : input.slice(separatorIndex + 1),\n path,\n };\n}\n\n/**\n * AppElements tree paths are absolute route-tree paths on the wire.\n * Bare segment names are not valid layout/template/slot tree identities.\n */\nfunction parseTreePath(input: string): string | null {\n return input.startsWith(\"/\") ? input : null;\n}\n\nfunction parseAppElementsWireElementKey(key: string): AppElementsWireElementKey | null {\n if (key.startsWith(\"route:\")) {\n const parsed = parsePathWithInterception(key.slice(\"route:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"route\", path: parsed.path };\n }\n\n if (key.startsWith(\"page:\")) {\n const parsed = parsePathWithInterception(key.slice(\"page:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"page\", path: parsed.path };\n }\n\n if (key.startsWith(\"layout:\")) {\n const treePath = parseTreePath(key.slice(\"layout:\".length));\n return treePath ? { kind: \"layout\", treePath } : null;\n }\n\n if (key.startsWith(\"template:\")) {\n const treePath = parseTreePath(key.slice(\"template:\".length));\n return treePath ? { kind: \"template\", treePath } : null;\n }\n\n if (key.startsWith(\"slot:\")) {\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n if (separatorIndex <= 0) return null;\n const name = body.slice(0, separatorIndex);\n const treePath = parseTreePath(body.slice(separatorIndex + 1));\n return treePath ? { kind: \"slot\", name, treePath } : null;\n }\n\n return null;\n}\n\nfunction isAppElementsWireSlotId(key: string): boolean {\n if (!key.startsWith(\"slot:\")) return false;\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n return separatorIndex > 0 && body.charCodeAt(separatorIndex + 1) === 0x2f;\n}\n\nfunction createAppElementsWireMetadataEntries(\n input: AppElementsWireMetadataInput,\n): AppElementsWireMetadataEntries {\n const layoutIds = [...(input.layoutIds ?? [])];\n const entries: AppElementsWireMetadataEntries = {\n [APP_ROUTE_KEY]: input.routeId,\n [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,\n [APP_LAYOUT_IDS_KEY]: layoutIds,\n [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath,\n };\n // Empty slot binding metadata is intentionally omitted. Missing\n // __slotBindings round-trips as [] and means \"no route-state proof\", so\n // default/unmatched slot preservation is not promoted for that payload.\n const entriesWithInterception = input.interception\n ? { ...entries, [APP_INTERCEPTION_KEY]: input.interception }\n : entries;\n if (input.slotBindings && input.slotBindings.length > 0) {\n return {\n ...entriesWithInterception,\n [APP_SLOT_BINDINGS_KEY]: normalizeAppElementsSlotBindings(input.slotBindings, { layoutIds }),\n };\n }\n return entriesWithInterception;\n}\n\nexport function normalizeAppElements(elements: AppWireElements): AppElements {\n let needsNormalization = false;\n for (const [key, value] of Object.entries(elements)) {\n if (isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE) {\n needsNormalization = true;\n break;\n }\n }\n\n if (!needsNormalization) {\n return elements;\n }\n\n const normalized: Record<string, AppElementValue> = {};\n for (const [key, value] of Object.entries(elements)) {\n normalized[key] =\n isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE\n ? UNMATCHED_SLOT\n : value;\n }\n\n return normalized;\n}\n\nfunction isLayoutFlagsRecord(value: unknown): value is LayoutFlags {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n for (const v of Object.values(value)) {\n if (v !== \"s\" && v !== \"d\") return false;\n }\n return true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseLayoutFlags(value: unknown): LayoutFlags {\n if (isLayoutFlagsRecord(value)) return value;\n return {};\n}\n\nfunction parseLayoutIds(value: unknown): readonly string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n throw new Error(\n \"[vinext] Invalid __layoutIds in App Router payload: expected layout id string[]\",\n );\n }\n\n const layoutIds: string[] = [];\n for (const entry of value) {\n if (typeof entry !== \"string\") {\n throw new Error(\n \"[vinext] Invalid __layoutIds in App Router payload: expected layout id string[]\",\n );\n }\n\n const parsed = parseAppElementsWireElementKey(entry);\n if (parsed?.kind !== \"layout\") {\n throw new Error(\"[vinext] Invalid __layoutIds in App Router payload: expected layout ids\");\n }\n\n layoutIds.push(entry);\n }\n return layoutIds;\n}\n\nfunction isSlotBindingState(value: unknown): value is AppElementsSlotBindingState {\n return value === \"active\" || value === \"default\" || value === \"unmatched\";\n}\n\nfunction parseSlotBindings(\n value: unknown,\n options: { layoutIds?: readonly string[] } = {},\n): readonly AppElementsSlotBinding[] {\n // Missing metadata is compatibility-safe but not semantic proof: callers see\n // an empty binding list, so promoted default/unmatched slot preservation is\n // denied instead of inferred from legacy transport shape.\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n throw new Error(\"[vinext] Invalid __slotBindings in App Router payload: expected array\");\n }\n\n const slotBindings: AppElementsSlotBinding[] = [];\n for (const entry of value) {\n if (!isRecord(entry)) {\n throw new Error(\"[vinext] Invalid __slotBindings in App Router payload: expected objects\");\n }\n\n const slotId = entry.slotId;\n if (typeof slotId !== \"string\" || parseAppElementsWireElementKey(slotId)?.kind !== \"slot\") {\n throw new Error(\"[vinext] Invalid __slotBindings in App Router payload: expected slot ids\");\n }\n\n const ownerLayoutId = entry.ownerLayoutId;\n if (\n ownerLayoutId !== null &&\n (typeof ownerLayoutId !== \"string\" ||\n parseAppElementsWireElementKey(ownerLayoutId)?.kind !== \"layout\")\n ) {\n throw new Error(\n \"[vinext] Invalid __slotBindings in App Router payload: expected owner layout ids\",\n );\n }\n\n const state = entry.state;\n if (!isSlotBindingState(state)) {\n throw new Error(\"[vinext] Invalid __slotBindings in App Router payload: expected state\");\n }\n\n slotBindings.push({ ownerLayoutId, slotId, state });\n }\n return normalizeAppElementsSlotBindings(slotBindings, options);\n}\n\nfunction readRequiredInterceptionString(\n entry: Record<string, unknown>,\n fieldName: keyof AppElementsInterception,\n): string {\n const value = entry[fieldName];\n if (typeof value !== \"string\") {\n throw new Error(\"[vinext] Invalid __interception in App Router payload: expected strings\");\n }\n return value;\n}\n\nfunction parseInterceptionMatchedUrl(value: string): string {\n if (!isInterceptionMatchedUrlPath(value)) {\n throw new Error(\"[vinext] Invalid __interception in App Router payload: expected path URLs\");\n }\n return value;\n}\n\nfunction parseInterceptionRouteId(value: string, matchedUrl: string): string {\n const parsed = parseAppElementsWireElementKey(value);\n if (\n parsed?.kind !== \"route\" ||\n parsed.path !== matchedUrl ||\n parsed.interceptionContext !== null\n ) {\n throw new Error(\"[vinext] Invalid __interception in App Router payload: expected route ids\");\n }\n return value;\n}\n\nfunction parseInterceptionSlotId(value: string): string {\n if (parseAppElementsWireElementKey(value)?.kind !== \"slot\") {\n throw new Error(\"[vinext] Invalid __interception in App Router payload: expected slot id\");\n }\n return value;\n}\n\nfunction parseInterceptionMetadata(value: unknown): AppElementsInterception | null {\n if (value === undefined || value === null) return null;\n if (!isRecord(value)) {\n throw new Error(\"[vinext] Invalid __interception in App Router payload: expected object\");\n }\n\n const sourceMatchedUrl = parseInterceptionMatchedUrl(\n readRequiredInterceptionString(value, \"sourceMatchedUrl\"),\n );\n const targetMatchedUrl = parseInterceptionMatchedUrl(\n readRequiredInterceptionString(value, \"targetMatchedUrl\"),\n );\n return {\n sourceMatchedUrl,\n sourceRouteId: parseInterceptionRouteId(\n readRequiredInterceptionString(value, \"sourceRouteId\"),\n sourceMatchedUrl,\n ),\n slotId: parseInterceptionSlotId(readRequiredInterceptionString(value, \"slotId\")),\n targetMatchedUrl,\n targetRouteId: parseInterceptionRouteId(\n readRequiredInterceptionString(value, \"targetRouteId\"),\n targetMatchedUrl,\n ),\n };\n}\n\n/**\n * Type predicate for a plain (non-null, non-array) record of app payload values.\n * Used to distinguish the App Router payload object from bare React elements at\n * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because\n * the outgoing payload carries heterogeneous values (ReactNodes for the rendered\n * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates\n * to React's canonical `isValidElement` so we don't depend on React's internal\n * `$$typeof` marker scheme.\n */\nexport function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) return false;\n if (Array.isArray(value)) return false;\n if (isValidElement(value)) return false;\n return true;\n}\n\nexport function withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags } {\n return { ...elements, [APP_LAYOUT_FLAGS_KEY]: layoutFlags };\n}\n\nexport function buildOutgoingAppPayload(input: {\n element:\n | ReactNode\n | Readonly<\n Record<string, ReactNode | AppElementsInterception | readonly AppElementsSlotBinding[]>\n >;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n renderObservation?: RenderObservation;\n}): ReactNode | AppOutgoingElements {\n if (!isAppElementsRecord(input.element)) {\n return input.element;\n }\n const payload: Record<\n string,\n | ReactNode\n | LayoutFlags\n | ArtifactCompatibilityEnvelope\n | AppElementsInterception\n | RenderObservation\n | readonly AppElementsSlotBinding[]\n > = {\n ...input.element,\n [APP_LAYOUT_FLAGS_KEY]: input.layoutFlags,\n [APP_ARTIFACT_COMPATIBILITY_KEY]:\n input.artifactCompatibility ?? createArtifactCompatibilityEnvelope(),\n };\n if (input.renderObservation) {\n payload[APP_RENDER_OBSERVATION_KEY] = input.renderObservation;\n }\n return payload;\n}\n\nfunction readArtifactCompatibilityMetadata(value: unknown): ArtifactCompatibilityEnvelope {\n if (value === undefined) return createArtifactCompatibilityEnvelope();\n\n const artifactCompatibility = parseArtifactCompatibilityEnvelope(value);\n // TODO(#726-COMPAT-04): hard-fail malformed compatibility metadata once\n // cache/skip consumers depend on this proof. During Wave01 the field is\n // emitted as scaffolding, so bad or future-version values degrade like\n // missing __layoutFlags instead of crashing render paths that do not read it.\n return artifactCompatibility ?? createArtifactCompatibilityEnvelope();\n}\n\nexport function readAppElementsMetadata(\n elements: Readonly<Record<string, unknown>>,\n): AppElementsMetadata {\n const routeId = elements[APP_ROUTE_KEY];\n if (typeof routeId !== \"string\") {\n throw new Error(\"[vinext] Missing __route string in App Router payload\");\n }\n\n const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];\n if (\n interceptionContext !== undefined &&\n interceptionContext !== null &&\n typeof interceptionContext !== \"string\"\n ) {\n throw new Error(\"[vinext] Invalid __interceptionContext in App Router payload\");\n }\n\n const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];\n if (rootLayoutTreePath === undefined) {\n throw new Error(\"[vinext] Missing __rootLayout key in App Router payload\");\n }\n if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== \"string\") {\n throw new Error(\"[vinext] Invalid __rootLayout in App Router payload: expected string or null\");\n }\n\n const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);\n const layoutIds = parseLayoutIds(elements[APP_LAYOUT_IDS_KEY]);\n const slotBindings = parseSlotBindings(elements[APP_SLOT_BINDINGS_KEY], { layoutIds });\n const interception = parseInterceptionMetadata(elements[APP_INTERCEPTION_KEY]);\n const artifactCompatibility = readArtifactCompatibilityMetadata(\n elements[APP_ARTIFACT_COMPATIBILITY_KEY],\n );\n\n return {\n artifactCompatibility,\n interception,\n interceptionContext: interceptionContext ?? null,\n layoutIds,\n layoutFlags,\n routeId,\n rootLayoutTreePath,\n slotBindings,\n };\n}\n\nexport const AppElementsWire: AppElementsWireCodec = {\n // WIRE follow-ups use these stable key names when moving payload readers and writers\n // behind the codec boundary.\n keys: {\n artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,\n interception: APP_INTERCEPTION_KEY,\n interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,\n layoutIds: APP_LAYOUT_IDS_KEY,\n layoutFlags: APP_LAYOUT_FLAGS_KEY,\n renderObservation: APP_RENDER_OBSERVATION_KEY,\n rootLayout: APP_ROOT_LAYOUT_KEY,\n route: APP_ROUTE_KEY,\n slotBindings: APP_SLOT_BINDINGS_KEY,\n },\n unmatchedSlotValue: APP_UNMATCHED_SLOT_WIRE_VALUE,\n createMetadataEntries: createAppElementsWireMetadataEntries,\n decode: normalizeAppElements,\n encodeCacheKey: createAppPayloadCacheKey,\n encodeLayoutId: createAppPayloadLayoutId,\n encodeOutgoingPayload: buildOutgoingAppPayload,\n encodePageId: createAppPayloadPageId,\n encodeRouteId: createAppPayloadRouteId,\n encodeSlotId: createAppPayloadSlotId,\n encodeTemplateId: createAppPayloadTemplateId,\n isSlotId: isAppElementsWireSlotId,\n parseElementKey: parseAppElementsWireElementKey,\n readMetadata: readAppElementsMetadata,\n withLayoutFlags,\n};\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsWire, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
1
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SLOT_BINDINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsInterception, AppElementsSlotBinding, AppElementsWire, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
2
2
 
3
3
  //#region src/server/app-elements.d.ts
4
4
  declare function getMountedSlotIds(elements: AppElements): string[];
5
5
  declare function getMountedSlotIdsHeader(elements: AppElements): string | null;
6
6
  declare function resolveVisitedResponseInterceptionContext(requestInterceptionContext: string | null, payloadInterceptionContext: string | null): string | null;
7
7
  //#endregion
8
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, type AppElementValue, type AppElements, AppElementsWire, type AppOutgoingElements, type AppWireElements, type LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
8
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SLOT_BINDINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, type AppElementValue, type AppElements, type AppElementsInterception, type AppElementsSlotBinding, AppElementsWire, type AppOutgoingElements, type AppWireElements, type LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
9
9
  //# sourceMappingURL=app-elements.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
2
- import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
2
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SLOT_BINDINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
3
3
  //#region src/server/app-elements.ts
4
4
  function getMountedSlotIds(elements) {
5
5
  return Object.keys(elements).filter((key) => {
@@ -14,6 +14,6 @@ function resolveVisitedResponseInterceptionContext(requestInterceptionContext, p
14
14
  return payloadInterceptionContext ?? requestInterceptionContext;
15
15
  }
16
16
  //#endregion
17
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
17
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SLOT_BINDINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
18
18
 
19
19
  //# sourceMappingURL=app-elements.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-elements.js","names":[],"sources":["../../src/server/app-elements.ts"],"sourcesContent":["import { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { AppElementsWire, UNMATCHED_SLOT, type AppElements } from \"./app-elements-wire.js\";\n\nexport {\n AppElementsWire,\n APP_ARTIFACT_COMPATIBILITY_KEY,\n APP_INTERCEPTION_CONTEXT_KEY,\n APP_LAYOUT_IDS_KEY,\n APP_LAYOUT_FLAGS_KEY,\n APP_ROOT_LAYOUT_KEY,\n APP_ROUTE_KEY,\n APP_UNMATCHED_SLOT_WIRE_VALUE,\n UNMATCHED_SLOT,\n buildOutgoingAppPayload,\n isAppElementsRecord,\n normalizeAppElements,\n readAppElementsMetadata,\n withLayoutFlags,\n type AppElementValue,\n type AppElements,\n type AppOutgoingElements,\n type AppWireElements,\n type LayoutFlags,\n} from \"./app-elements-wire.js\";\n\n// Raw constructor helpers stay private because callers use AppElementsWire codecs.\n\nexport function getMountedSlotIds(elements: AppElements): string[] {\n return Object.keys(elements)\n .filter((key) => {\n const value = elements[key];\n return (\n AppElementsWire.isSlotId(key) &&\n value !== null &&\n value !== undefined &&\n value !== UNMATCHED_SLOT\n );\n })\n .sort();\n}\n\nexport function getMountedSlotIdsHeader(elements: AppElements): string | null {\n return normalizeMountedSlotsHeader(getMountedSlotIds(elements).join(\" \"));\n}\n\nexport function resolveVisitedResponseInterceptionContext(\n requestInterceptionContext: string | null,\n payloadInterceptionContext: string | null,\n): string | null {\n return payloadInterceptionContext ?? requestInterceptionContext;\n}\n"],"mappings":";;;AA2BA,SAAgB,kBAAkB,UAAiC;CACjE,OAAO,OAAO,KAAK,SAAS,CACzB,QAAQ,QAAQ;EACf,MAAM,QAAQ,SAAS;EACvB,OACE,gBAAgB,SAAS,IAAI,IAC7B,UAAU,QACV,UAAU,KAAA,KACV,UAAU;GAEZ,CACD,MAAM;;AAGX,SAAgB,wBAAwB,UAAsC;CAC5E,OAAO,4BAA4B,kBAAkB,SAAS,CAAC,KAAK,IAAI,CAAC;;AAG3E,SAAgB,0CACd,4BACA,4BACe;CACf,OAAO,8BAA8B"}
1
+ {"version":3,"file":"app-elements.js","names":[],"sources":["../../src/server/app-elements.ts"],"sourcesContent":["import { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { AppElementsWire, UNMATCHED_SLOT, type AppElements } from \"./app-elements-wire.js\";\n\nexport {\n AppElementsWire,\n APP_ARTIFACT_COMPATIBILITY_KEY,\n APP_INTERCEPTION_KEY,\n APP_INTERCEPTION_CONTEXT_KEY,\n APP_LAYOUT_IDS_KEY,\n APP_LAYOUT_FLAGS_KEY,\n APP_RENDER_OBSERVATION_KEY,\n APP_ROOT_LAYOUT_KEY,\n APP_ROUTE_KEY,\n APP_SLOT_BINDINGS_KEY,\n APP_UNMATCHED_SLOT_WIRE_VALUE,\n UNMATCHED_SLOT,\n buildOutgoingAppPayload,\n compareAppElementsSlotIds,\n isAppElementsRecord,\n normalizeAppElementsSlotBindings,\n normalizeAppElements,\n readAppElementsMetadata,\n withLayoutFlags,\n type AppElementValue,\n type AppElementsInterception,\n type AppElementsSlotBinding,\n type AppElements,\n type AppOutgoingElements,\n type AppWireElements,\n type LayoutFlags,\n} from \"./app-elements-wire.js\";\n\n// Raw constructor helpers stay private because callers use AppElementsWire codecs.\n\nexport function getMountedSlotIds(elements: AppElements): string[] {\n return Object.keys(elements)\n .filter((key) => {\n const value = elements[key];\n return (\n AppElementsWire.isSlotId(key) &&\n value !== null &&\n value !== undefined &&\n value !== UNMATCHED_SLOT\n );\n })\n .sort();\n}\n\nexport function getMountedSlotIdsHeader(elements: AppElements): string | null {\n return normalizeMountedSlotsHeader(getMountedSlotIds(elements).join(\" \"));\n}\n\nexport function resolveVisitedResponseInterceptionContext(\n requestInterceptionContext: string | null,\n payloadInterceptionContext: string | null,\n): string | null {\n return payloadInterceptionContext ?? requestInterceptionContext;\n}\n"],"mappings":";;;AAkCA,SAAgB,kBAAkB,UAAiC;CACjE,OAAO,OAAO,KAAK,SAAS,CACzB,QAAQ,QAAQ;EACf,MAAM,QAAQ,SAAS;EACvB,OACE,gBAAgB,SAAS,IAAI,IAC7B,UAAU,QACV,UAAU,KAAA,KACV,UAAU;GAEZ,CACD,MAAM;;AAGX,SAAgB,wBAAwB,UAAsC;CAC5E,OAAO,4BAA4B,kBAAkB,SAAS,CAAC,KAAK,IAAI,CAAC;;AAG3E,SAAgB,0CACd,4BACA,4BACe;CACf,OAAO,8BAA8B"}
@@ -32,8 +32,17 @@ type AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> =
32
32
  fontProviders: AppFallbackRendererFontProviders;
33
33
  getNavigationContext: () => unknown;
34
34
  globalErrorModule?: TModule | null;
35
+ /**
36
+ * Optional `app/global-not-found.tsx` module. When provided, route-miss 404s
37
+ * render this module as a standalone document (skipping the root layout)
38
+ * because it ships its own `<html>` and `<body>`. Page-triggered `notFound()`
39
+ * calls continue to use the regular `not-found.tsx` boundary inside layouts.
40
+ * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/app-render.tsx
41
+ */
42
+ globalNotFoundModule?: TModule | null;
35
43
  makeThenableParams: (params: AppPageParams) => unknown;
36
- metadataRoutes: MetadataFileRoute[];
44
+ metadataRoutes: MetadataFileRoute[]; /** Configured next.config `basePath`, threaded into file-based metadata href emission. */
45
+ basePath?: string;
37
46
  resolveChildSegments: (routeSegments: readonly string[], treePosition: number, params: AppPageParams) => string[];
38
47
  rootBoundaries: AppFallbackRendererRootBoundaries<TModule>;
39
48
  rscRenderer: (element: ReactNode | AppElements, options: {
@@ -5,11 +5,46 @@ const EMPTY_MW_CTX = {
5
5
  status: null
6
6
  };
7
7
  function createAppFallbackRenderer(options) {
8
- const { clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader } = options;
8
+ const { basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, globalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader } = options;
9
9
  const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } = rootBoundaries;
10
10
  return {
11
11
  renderHttpAccessFallback(route, statusCode, isRscRequest, request, opts, scriptNonce, middlewareContext) {
12
+ if (statusCode === 404 && !!globalNotFoundModule && !route && !opts?.boundaryComponent) {
13
+ const globalNotFoundComponent = globalNotFoundModule?.default ?? null;
14
+ if (globalNotFoundComponent) return renderAppPageHttpAccessFallback({
15
+ boundaryComponent: globalNotFoundComponent,
16
+ buildFontLinkHeader: fontProviders.buildFontLinkHeader,
17
+ clearRequestContext,
18
+ createRscOnErrorHandler(pathname, routePath) {
19
+ return buildRscOnErrorHandler(request, pathname, routePath);
20
+ },
21
+ getFontLinks: fontProviders.getFontLinks,
22
+ getFontPreloads: fontProviders.getFontPreloads,
23
+ getFontStyles: fontProviders.getFontStyles,
24
+ getNavigationContext,
25
+ globalErrorModule,
26
+ isRscRequest,
27
+ layoutModules: [],
28
+ loadSsrHandler: ssrLoader,
29
+ makeThenableParams,
30
+ matchedParams: opts?.matchedParams ?? {},
31
+ middlewareContext: middlewareContext ?? EMPTY_MW_CTX,
32
+ metadataRoutes,
33
+ requestUrl: request.url,
34
+ resolveChildSegments,
35
+ rootForbiddenModule: null,
36
+ rootLayouts: [],
37
+ rootNotFoundModule: null,
38
+ rootUnauthorizedModule: null,
39
+ route: null,
40
+ renderToReadableStream: rscRenderer,
41
+ scriptNonce,
42
+ skipLayoutWrapping: true,
43
+ statusCode
44
+ });
45
+ }
12
46
  return renderAppPageHttpAccessFallback({
47
+ basePath,
13
48
  boundaryComponent: opts?.boundaryComponent ?? null,
14
49
  buildFontLinkHeader: fontProviders.buildFontLinkHeader,
15
50
  clearRequestContext,
@@ -45,6 +80,7 @@ function createAppFallbackRenderer(options) {
45
80
  },
46
81
  renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext) {
47
82
  return renderAppPageErrorBoundary({
83
+ basePath,
48
84
  buildFontLinkHeader: fontProviders.buildFontLinkHeader,
49
85
  clearRequestContext,
50
86
  createRscOnErrorHandler(pathname, routePath) {
@@ -1 +1 @@
1
- {"version":3,"file":"app-fallback-renderer.js","names":[],"sources":["../../src/server/app-fallback-renderer.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport {\n renderAppPageErrorBoundary,\n renderAppPageHttpAccessFallback,\n type AppPageBoundaryRoute,\n} from \"./app-page-boundary-render.js\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport type { AppPageSsrHandler } from \"./app-page-stream.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport type { AppElements } from \"./app-elements.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = import(\"react\").ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppFallbackRendererRootBoundaries<TModule extends AppPageModule = AppPageModule> = {\n rootForbiddenModule?: TModule | null;\n rootLayouts: readonly (TModule | null | undefined)[];\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n};\n\ntype AppFallbackRendererFontProviders = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n};\n\ntype AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> = {\n clearRequestContext: () => void;\n createRscOnErrorHandler: (\n request: Request,\n pathname: string,\n routePath: string,\n ) => AppPageBoundaryOnError;\n fontProviders: AppFallbackRendererFontProviders;\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n metadataRoutes: MetadataFileRoute[];\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootBoundaries: AppFallbackRendererRootBoundaries<TModule>;\n rscRenderer: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n sanitizer: (error: Error) => Error;\n ssrLoader: () => Promise<AppPageSsrHandler>;\n};\n\ntype AppFallbackRenderer<TModule extends AppPageModule = AppPageModule> = {\n renderErrorBoundary: (\n route: AppPageBoundaryRoute<TModule> | null,\n error: unknown,\n isRscRequest: boolean,\n request: Request,\n matchedParams: AppPageParams | undefined,\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n renderHttpAccessFallback: (\n route: AppPageBoundaryRoute<TModule> | null,\n statusCode: number,\n isRscRequest: boolean,\n request: Request,\n opts: {\n boundaryComponent?: AppPageComponent | null;\n layouts?: readonly (TModule | null | undefined)[] | null;\n matchedParams?: AppPageParams;\n },\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n renderNotFound: (\n route: AppPageBoundaryRoute<TModule> | null,\n isRscRequest: boolean,\n request: Request,\n matchedParams: AppPageParams | undefined,\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n};\n\nconst EMPTY_MW_CTX: AppPageMiddlewareContext = { headers: null, status: null };\n\nexport function createAppFallbackRenderer<TModule extends AppPageModule>(\n options: AppFallbackRendererOptions<TModule>,\n): AppFallbackRenderer<TModule> {\n const {\n clearRequestContext,\n createRscOnErrorHandler: buildRscOnErrorHandler,\n fontProviders,\n getNavigationContext,\n globalErrorModule,\n makeThenableParams,\n metadataRoutes,\n resolveChildSegments,\n rootBoundaries,\n rscRenderer,\n sanitizer,\n ssrLoader,\n } = options;\n\n const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } =\n rootBoundaries;\n\n return {\n renderHttpAccessFallback(\n route,\n statusCode,\n isRscRequest,\n request,\n opts,\n scriptNonce,\n middlewareContext,\n ) {\n return renderAppPageHttpAccessFallback({\n boundaryComponent: opts?.boundaryComponent ?? null,\n buildFontLinkHeader: fontProviders.buildFontLinkHeader,\n clearRequestContext,\n createRscOnErrorHandler(pathname, routePath) {\n return buildRscOnErrorHandler(request, pathname, routePath);\n },\n getFontLinks: fontProviders.getFontLinks,\n getFontPreloads: fontProviders.getFontPreloads,\n getFontStyles: fontProviders.getFontStyles,\n getNavigationContext,\n globalErrorModule,\n isRscRequest,\n layoutModules: opts?.layouts ?? null,\n loadSsrHandler: ssrLoader,\n makeThenableParams,\n matchedParams: opts?.matchedParams ?? route?.params ?? {},\n middlewareContext: middlewareContext ?? EMPTY_MW_CTX,\n metadataRoutes,\n requestUrl: request.url,\n resolveChildSegments,\n rootForbiddenModule,\n rootLayouts,\n rootNotFoundModule,\n rootUnauthorizedModule,\n route,\n renderToReadableStream: rscRenderer,\n scriptNonce,\n statusCode,\n });\n },\n\n renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext) {\n return this.renderHttpAccessFallback(\n route,\n 404,\n isRscRequest,\n request,\n { matchedParams },\n scriptNonce,\n middlewareContext,\n );\n },\n\n renderErrorBoundary(\n route,\n error,\n isRscRequest,\n request,\n matchedParams,\n scriptNonce,\n middlewareContext,\n ) {\n return renderAppPageErrorBoundary({\n buildFontLinkHeader: fontProviders.buildFontLinkHeader,\n clearRequestContext,\n createRscOnErrorHandler(pathname, routePath) {\n return buildRscOnErrorHandler(request, pathname, routePath);\n },\n error,\n getFontLinks: fontProviders.getFontLinks,\n getFontPreloads: fontProviders.getFontPreloads,\n getFontStyles: fontProviders.getFontStyles,\n getNavigationContext,\n globalErrorModule,\n isRscRequest,\n loadSsrHandler: ssrLoader,\n makeThenableParams,\n matchedParams: matchedParams ?? route?.params ?? {},\n middlewareContext: middlewareContext ?? EMPTY_MW_CTX,\n metadataRoutes,\n requestUrl: request.url,\n resolveChildSegments,\n rootLayouts,\n route,\n renderToReadableStream: rscRenderer,\n sanitizeErrorForClient: sanitizer,\n scriptNonce,\n });\n },\n };\n}\n"],"mappings":";;AAiGA,MAAM,eAAyC;CAAE,SAAS;CAAM,QAAQ;CAAM;AAE9E,SAAgB,0BACd,SAC8B;CAC9B,MAAM,EACJ,qBACA,yBAAyB,wBACzB,eACA,sBACA,mBACA,oBACA,gBACA,sBACA,gBACA,aACA,WACA,cACE;CAEJ,MAAM,EAAE,qBAAqB,aAAa,oBAAoB,2BAC5D;CAEF,OAAO;EACL,yBACE,OACA,YACA,cACA,SACA,MACA,aACA,mBACA;GACA,OAAO,gCAAgC;IACrC,mBAAmB,MAAM,qBAAqB;IAC9C,qBAAqB,cAAc;IACnC;IACA,wBAAwB,UAAU,WAAW;KAC3C,OAAO,uBAAuB,SAAS,UAAU,UAAU;;IAE7D,cAAc,cAAc;IAC5B,iBAAiB,cAAc;IAC/B,eAAe,cAAc;IAC7B;IACA;IACA;IACA,eAAe,MAAM,WAAW;IAChC,gBAAgB;IAChB;IACA,eAAe,MAAM,iBAAiB,OAAO,UAAU,EAAE;IACzD,mBAAmB,qBAAqB;IACxC;IACA,YAAY,QAAQ;IACpB;IACA;IACA;IACA;IACA;IACA;IACA,wBAAwB;IACxB;IACA;IACD,CAAC;;EAGJ,eAAe,OAAO,cAAc,SAAS,eAAe,aAAa,mBAAmB;GAC1F,OAAO,KAAK,yBACV,OACA,KACA,cACA,SACA,EAAE,eAAe,EACjB,aACA,kBACD;;EAGH,oBACE,OACA,OACA,cACA,SACA,eACA,aACA,mBACA;GACA,OAAO,2BAA2B;IAChC,qBAAqB,cAAc;IACnC;IACA,wBAAwB,UAAU,WAAW;KAC3C,OAAO,uBAAuB,SAAS,UAAU,UAAU;;IAE7D;IACA,cAAc,cAAc;IAC5B,iBAAiB,cAAc;IAC/B,eAAe,cAAc;IAC7B;IACA;IACA;IACA,gBAAgB;IAChB;IACA,eAAe,iBAAiB,OAAO,UAAU,EAAE;IACnD,mBAAmB,qBAAqB;IACxC;IACA,YAAY,QAAQ;IACpB;IACA;IACA;IACA,wBAAwB;IACxB,wBAAwB;IACxB;IACD,CAAC;;EAEL"}
1
+ {"version":3,"file":"app-fallback-renderer.js","names":[],"sources":["../../src/server/app-fallback-renderer.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport {\n renderAppPageErrorBoundary,\n renderAppPageHttpAccessFallback,\n type AppPageBoundaryRoute,\n} from \"./app-page-boundary-render.js\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport type { AppPageSsrHandler } from \"./app-page-stream.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport type { AppElements } from \"./app-elements.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = import(\"react\").ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppFallbackRendererRootBoundaries<TModule extends AppPageModule = AppPageModule> = {\n rootForbiddenModule?: TModule | null;\n rootLayouts: readonly (TModule | null | undefined)[];\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n};\n\ntype AppFallbackRendererFontProviders = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n};\n\ntype AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> = {\n clearRequestContext: () => void;\n createRscOnErrorHandler: (\n request: Request,\n pathname: string,\n routePath: string,\n ) => AppPageBoundaryOnError;\n fontProviders: AppFallbackRendererFontProviders;\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n /**\n * Optional `app/global-not-found.tsx` module. When provided, route-miss 404s\n * render this module as a standalone document (skipping the root layout)\n * because it ships its own `<html>` and `<body>`. Page-triggered `notFound()`\n * calls continue to use the regular `not-found.tsx` boundary inside layouts.\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/app-render.tsx\n */\n globalNotFoundModule?: TModule | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n metadataRoutes: MetadataFileRoute[];\n /** Configured next.config `basePath`, threaded into file-based metadata href emission. */\n basePath?: string;\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootBoundaries: AppFallbackRendererRootBoundaries<TModule>;\n rscRenderer: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n sanitizer: (error: Error) => Error;\n ssrLoader: () => Promise<AppPageSsrHandler>;\n};\n\ntype AppFallbackRenderer<TModule extends AppPageModule = AppPageModule> = {\n renderErrorBoundary: (\n route: AppPageBoundaryRoute<TModule> | null,\n error: unknown,\n isRscRequest: boolean,\n request: Request,\n matchedParams: AppPageParams | undefined,\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n renderHttpAccessFallback: (\n route: AppPageBoundaryRoute<TModule> | null,\n statusCode: number,\n isRscRequest: boolean,\n request: Request,\n opts: {\n boundaryComponent?: AppPageComponent | null;\n layouts?: readonly (TModule | null | undefined)[] | null;\n matchedParams?: AppPageParams;\n },\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n renderNotFound: (\n route: AppPageBoundaryRoute<TModule> | null,\n isRscRequest: boolean,\n request: Request,\n matchedParams: AppPageParams | undefined,\n scriptNonce: string | undefined,\n middlewareContext: AppPageMiddlewareContext,\n ) => Promise<Response | null>;\n};\n\nconst EMPTY_MW_CTX: AppPageMiddlewareContext = { headers: null, status: null };\n\nexport function createAppFallbackRenderer<TModule extends AppPageModule>(\n options: AppFallbackRendererOptions<TModule>,\n): AppFallbackRenderer<TModule> {\n const {\n basePath = \"\",\n clearRequestContext,\n createRscOnErrorHandler: buildRscOnErrorHandler,\n fontProviders,\n getNavigationContext,\n globalErrorModule,\n globalNotFoundModule,\n makeThenableParams,\n metadataRoutes,\n resolveChildSegments,\n rootBoundaries,\n rscRenderer,\n sanitizer,\n ssrLoader,\n } = options;\n\n const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } =\n rootBoundaries;\n\n return {\n renderHttpAccessFallback(\n route,\n statusCode,\n isRscRequest,\n request,\n opts,\n scriptNonce,\n middlewareContext,\n ) {\n // global-not-found.tsx replaces the root layout for route-miss 404s.\n // Only applies when:\n // - The user defined app/global-not-found.tsx\n // - The 404 originates from a route miss (no matched route)\n // - The caller did not already pick a specific boundary component\n // Page-triggered notFound() calls (route is non-null) keep using the\n // regular not-found.tsx boundary inside the route's layouts.\n // See https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/app-render.tsx#L495-L520\n const useGlobalNotFound =\n statusCode === 404 && !!globalNotFoundModule && !route && !opts?.boundaryComponent;\n\n if (useGlobalNotFound) {\n const globalNotFoundComponent = globalNotFoundModule?.default ?? null;\n if (globalNotFoundComponent) {\n return renderAppPageHttpAccessFallback({\n boundaryComponent: globalNotFoundComponent,\n buildFontLinkHeader: fontProviders.buildFontLinkHeader,\n clearRequestContext,\n createRscOnErrorHandler(pathname, routePath) {\n return buildRscOnErrorHandler(request, pathname, routePath);\n },\n getFontLinks: fontProviders.getFontLinks,\n getFontPreloads: fontProviders.getFontPreloads,\n getFontStyles: fontProviders.getFontStyles,\n getNavigationContext,\n globalErrorModule,\n isRscRequest,\n layoutModules: [],\n loadSsrHandler: ssrLoader,\n makeThenableParams,\n matchedParams: opts?.matchedParams ?? {},\n middlewareContext: middlewareContext ?? EMPTY_MW_CTX,\n metadataRoutes,\n requestUrl: request.url,\n resolveChildSegments,\n rootForbiddenModule: null,\n rootLayouts: [],\n rootNotFoundModule: null,\n rootUnauthorizedModule: null,\n route: null,\n renderToReadableStream: rscRenderer,\n scriptNonce,\n skipLayoutWrapping: true,\n statusCode,\n });\n }\n }\n\n return renderAppPageHttpAccessFallback({\n basePath,\n boundaryComponent: opts?.boundaryComponent ?? null,\n buildFontLinkHeader: fontProviders.buildFontLinkHeader,\n clearRequestContext,\n createRscOnErrorHandler(pathname, routePath) {\n return buildRscOnErrorHandler(request, pathname, routePath);\n },\n getFontLinks: fontProviders.getFontLinks,\n getFontPreloads: fontProviders.getFontPreloads,\n getFontStyles: fontProviders.getFontStyles,\n getNavigationContext,\n globalErrorModule,\n isRscRequest,\n layoutModules: opts?.layouts ?? null,\n loadSsrHandler: ssrLoader,\n makeThenableParams,\n matchedParams: opts?.matchedParams ?? route?.params ?? {},\n middlewareContext: middlewareContext ?? EMPTY_MW_CTX,\n metadataRoutes,\n requestUrl: request.url,\n resolveChildSegments,\n rootForbiddenModule,\n rootLayouts,\n rootNotFoundModule,\n rootUnauthorizedModule,\n route,\n renderToReadableStream: rscRenderer,\n scriptNonce,\n statusCode,\n });\n },\n\n renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext) {\n return this.renderHttpAccessFallback(\n route,\n 404,\n isRscRequest,\n request,\n { matchedParams },\n scriptNonce,\n middlewareContext,\n );\n },\n\n renderErrorBoundary(\n route,\n error,\n isRscRequest,\n request,\n matchedParams,\n scriptNonce,\n middlewareContext,\n ) {\n return renderAppPageErrorBoundary({\n basePath,\n buildFontLinkHeader: fontProviders.buildFontLinkHeader,\n clearRequestContext,\n createRscOnErrorHandler(pathname, routePath) {\n return buildRscOnErrorHandler(request, pathname, routePath);\n },\n error,\n getFontLinks: fontProviders.getFontLinks,\n getFontPreloads: fontProviders.getFontPreloads,\n getFontStyles: fontProviders.getFontStyles,\n getNavigationContext,\n globalErrorModule,\n isRscRequest,\n loadSsrHandler: ssrLoader,\n makeThenableParams,\n matchedParams: matchedParams ?? route?.params ?? {},\n middlewareContext: middlewareContext ?? EMPTY_MW_CTX,\n metadataRoutes,\n requestUrl: request.url,\n resolveChildSegments,\n rootLayouts,\n route,\n renderToReadableStream: rscRenderer,\n sanitizeErrorForClient: sanitizer,\n scriptNonce,\n });\n },\n };\n}\n"],"mappings":";;AA2GA,MAAM,eAAyC;CAAE,SAAS;CAAM,QAAQ;CAAM;AAE9E,SAAgB,0BACd,SAC8B;CAC9B,MAAM,EACJ,WAAW,IACX,qBACA,yBAAyB,wBACzB,eACA,sBACA,mBACA,sBACA,oBACA,gBACA,sBACA,gBACA,aACA,WACA,cACE;CAEJ,MAAM,EAAE,qBAAqB,aAAa,oBAAoB,2BAC5D;CAEF,OAAO;EACL,yBACE,OACA,YACA,cACA,SACA,MACA,aACA,mBACA;GAYA,IAFE,eAAe,OAAO,CAAC,CAAC,wBAAwB,CAAC,SAAS,CAAC,MAAM,mBAE5C;IACrB,MAAM,0BAA0B,sBAAsB,WAAW;IACjE,IAAI,yBACF,OAAO,gCAAgC;KACrC,mBAAmB;KACnB,qBAAqB,cAAc;KACnC;KACA,wBAAwB,UAAU,WAAW;MAC3C,OAAO,uBAAuB,SAAS,UAAU,UAAU;;KAE7D,cAAc,cAAc;KAC5B,iBAAiB,cAAc;KAC/B,eAAe,cAAc;KAC7B;KACA;KACA;KACA,eAAe,EAAE;KACjB,gBAAgB;KAChB;KACA,eAAe,MAAM,iBAAiB,EAAE;KACxC,mBAAmB,qBAAqB;KACxC;KACA,YAAY,QAAQ;KACpB;KACA,qBAAqB;KACrB,aAAa,EAAE;KACf,oBAAoB;KACpB,wBAAwB;KACxB,OAAO;KACP,wBAAwB;KACxB;KACA,oBAAoB;KACpB;KACD,CAAC;;GAIN,OAAO,gCAAgC;IACrC;IACA,mBAAmB,MAAM,qBAAqB;IAC9C,qBAAqB,cAAc;IACnC;IACA,wBAAwB,UAAU,WAAW;KAC3C,OAAO,uBAAuB,SAAS,UAAU,UAAU;;IAE7D,cAAc,cAAc;IAC5B,iBAAiB,cAAc;IAC/B,eAAe,cAAc;IAC7B;IACA;IACA;IACA,eAAe,MAAM,WAAW;IAChC,gBAAgB;IAChB;IACA,eAAe,MAAM,iBAAiB,OAAO,UAAU,EAAE;IACzD,mBAAmB,qBAAqB;IACxC;IACA,YAAY,QAAQ;IACpB;IACA;IACA;IACA;IACA;IACA;IACA,wBAAwB;IACxB;IACA;IACD,CAAC;;EAGJ,eAAe,OAAO,cAAc,SAAS,eAAe,aAAa,mBAAmB;GAC1F,OAAO,KAAK,yBACV,OACA,KACA,cACA,SACA,EAAE,eAAe,EACjB,aACA,kBACD;;EAGH,oBACE,OACA,OACA,cACA,SACA,eACA,aACA,mBACA;GACA,OAAO,2BAA2B;IAChC;IACA,qBAAqB,cAAc;IACnC;IACA,wBAAwB,UAAU,WAAW;KAC3C,OAAO,uBAAuB,SAAS,UAAU,UAAU;;IAE7D;IACA,cAAc,cAAc;IAC5B,iBAAiB,cAAc;IAC/B,eAAe,cAAc;IAC7B;IACA;IACA;IACA,gBAAgB;IAChB;IACA,eAAe,iBAAiB,OAAO,UAAU,EAAE;IACnD,mBAAmB,qBAAqB;IACxC;IACA,YAAY,QAAQ;IACpB;IACA;IACA;IACA,wBAAwB;IACxB,wBAAwB;IACxB;IACD,CAAC;;EAEL"}
@@ -0,0 +1,26 @@
1
+ import { TraverseDirection } from "./navigation-planner.js";
2
+
3
+ //#region src/server/app-history-state.d.ts
4
+ type HistoryStateRecord = {
5
+ [key: string]: unknown;
6
+ };
7
+ type HistoryTraversalIntent = {
8
+ direction: TraverseDirection;
9
+ historyState: unknown;
10
+ targetHistoryIndex: number | null;
11
+ };
12
+ declare function createHistoryStateWithPreviousNextUrl(state: unknown, previousNextUrl: string | null): HistoryStateRecord | null;
13
+ declare function createHistoryStateWithNavigationMetadata(state: unknown, metadata: {
14
+ previousNextUrl: string | null;
15
+ traversalIndex?: number | null;
16
+ }): HistoryStateRecord | null;
17
+ declare function createExternalHistoryStatePreservingMetadata(callerState: unknown, currentHistoryState: unknown): unknown;
18
+ declare function readHistoryStatePreviousNextUrl(state: unknown): string | null;
19
+ declare function readHistoryStateTraversalIndex(state: unknown): number | null;
20
+ declare function resolveHistoryTraversalIntent(options: {
21
+ currentHistoryIndex: number | null;
22
+ historyState: unknown;
23
+ }): HistoryTraversalIntent;
24
+ //#endregion
25
+ export { HistoryTraversalIntent, createExternalHistoryStatePreservingMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
26
+ //# sourceMappingURL=app-history-state.d.ts.map
@@ -0,0 +1,53 @@
1
+ //#region src/server/app-history-state.ts
2
+ const VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY = "__vinext_previousNextUrl";
3
+ const VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY = "__vinext_historyIndex";
4
+ function cloneHistoryState(state) {
5
+ if (!state || typeof state !== "object") return {};
6
+ const nextState = {};
7
+ for (const [key, value] of Object.entries(state)) nextState[key] = value;
8
+ return nextState;
9
+ }
10
+ function createHistoryStateWithPreviousNextUrl(state, previousNextUrl) {
11
+ return createHistoryStateWithNavigationMetadata(state, { previousNextUrl });
12
+ }
13
+ function createHistoryStateWithNavigationMetadata(state, metadata) {
14
+ const nextState = cloneHistoryState(state);
15
+ if (metadata.previousNextUrl === null) delete nextState[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY];
16
+ else nextState[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY] = metadata.previousNextUrl;
17
+ if (metadata.traversalIndex !== void 0) if (isValidHistoryTraversalIndex(metadata.traversalIndex)) nextState[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY] = metadata.traversalIndex;
18
+ else delete nextState[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY];
19
+ return Object.keys(nextState).length > 0 ? nextState : null;
20
+ }
21
+ function createExternalHistoryStatePreservingMetadata(callerState, currentHistoryState) {
22
+ const previousNextUrl = readHistoryStatePreviousNextUrl(currentHistoryState);
23
+ if (previousNextUrl === null) return callerState;
24
+ return createHistoryStateWithPreviousNextUrl(callerState, previousNextUrl);
25
+ }
26
+ function readHistoryStatePreviousNextUrl(state) {
27
+ const value = cloneHistoryState(state)[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY];
28
+ return typeof value === "string" ? value : null;
29
+ }
30
+ function isValidHistoryTraversalIndex(value) {
31
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
32
+ }
33
+ function readHistoryStateTraversalIndex(state) {
34
+ const value = cloneHistoryState(state)[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY];
35
+ return isValidHistoryTraversalIndex(value) ? value : null;
36
+ }
37
+ function resolveHistoryTraversalIntent(options) {
38
+ const targetHistoryIndex = readHistoryStateTraversalIndex(options.historyState);
39
+ let direction = "unknown";
40
+ if (options.currentHistoryIndex !== null && targetHistoryIndex !== null) {
41
+ if (targetHistoryIndex < options.currentHistoryIndex) direction = "back";
42
+ else if (targetHistoryIndex > options.currentHistoryIndex) direction = "forward";
43
+ }
44
+ return {
45
+ direction,
46
+ historyState: options.historyState,
47
+ targetHistoryIndex
48
+ };
49
+ }
50
+ //#endregion
51
+ export { createExternalHistoryStatePreservingMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
52
+
53
+ //# sourceMappingURL=app-history-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-history-state.js","names":[],"sources":["../../src/server/app-history-state.ts"],"sourcesContent":["import type { TraverseDirection } from \"./navigation-planner.js\";\n\nconst VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY = \"__vinext_previousNextUrl\";\nconst VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY = \"__vinext_historyIndex\";\n\ntype HistoryStateRecord = {\n [key: string]: unknown;\n};\n\nexport type HistoryTraversalIntent = {\n direction: TraverseDirection;\n historyState: unknown;\n targetHistoryIndex: number | null;\n};\n\nfunction cloneHistoryState(state: unknown): HistoryStateRecord {\n if (!state || typeof state !== \"object\") {\n return {};\n }\n\n const nextState: HistoryStateRecord = {};\n for (const [key, value] of Object.entries(state)) {\n nextState[key] = value;\n }\n return nextState;\n}\n\nexport function createHistoryStateWithPreviousNextUrl(\n state: unknown,\n previousNextUrl: string | null,\n): HistoryStateRecord | null {\n return createHistoryStateWithNavigationMetadata(state, { previousNextUrl });\n}\n\nexport function createHistoryStateWithNavigationMetadata(\n state: unknown,\n metadata: {\n previousNextUrl: string | null;\n traversalIndex?: number | null;\n },\n): HistoryStateRecord | null {\n const nextState = cloneHistoryState(state);\n\n if (metadata.previousNextUrl === null) {\n delete nextState[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY];\n } else {\n nextState[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY] = metadata.previousNextUrl;\n }\n\n if (metadata.traversalIndex !== undefined) {\n if (isValidHistoryTraversalIndex(metadata.traversalIndex)) {\n nextState[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY] = metadata.traversalIndex;\n } else {\n delete nextState[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY];\n }\n }\n\n return Object.keys(nextState).length > 0 ? nextState : null;\n}\n\nexport function createExternalHistoryStatePreservingMetadata(\n callerState: unknown,\n currentHistoryState: unknown,\n): unknown {\n const previousNextUrl = readHistoryStatePreviousNextUrl(currentHistoryState);\n if (previousNextUrl === null) {\n return callerState;\n }\n\n return createHistoryStateWithPreviousNextUrl(callerState, previousNextUrl);\n}\n\nexport function readHistoryStatePreviousNextUrl(state: unknown): string | null {\n const value = cloneHistoryState(state)[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY];\n return typeof value === \"string\" ? value : null;\n}\n\nfunction isValidHistoryTraversalIndex(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nexport function readHistoryStateTraversalIndex(state: unknown): number | null {\n const value = cloneHistoryState(state)[VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY];\n return isValidHistoryTraversalIndex(value) ? value : null;\n}\n\nexport function resolveHistoryTraversalIntent(options: {\n currentHistoryIndex: number | null;\n historyState: unknown;\n}): HistoryTraversalIntent {\n const targetHistoryIndex = readHistoryStateTraversalIndex(options.historyState);\n let direction: TraverseDirection = \"unknown\";\n\n if (options.currentHistoryIndex !== null && targetHistoryIndex !== null) {\n if (targetHistoryIndex < options.currentHistoryIndex) {\n direction = \"back\";\n } else if (targetHistoryIndex > options.currentHistoryIndex) {\n direction = \"forward\";\n }\n }\n\n return {\n direction,\n historyState: options.historyState,\n targetHistoryIndex,\n };\n}\n"],"mappings":";AAEA,MAAM,6CAA6C;AACnD,MAAM,yCAAyC;AAY/C,SAAS,kBAAkB,OAAoC;CAC7D,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO,EAAE;CAGX,MAAM,YAAgC,EAAE;CACxC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAC9C,UAAU,OAAO;CAEnB,OAAO;;AAGT,SAAgB,sCACd,OACA,iBAC2B;CAC3B,OAAO,yCAAyC,OAAO,EAAE,iBAAiB,CAAC;;AAG7E,SAAgB,yCACd,OACA,UAI2B;CAC3B,MAAM,YAAY,kBAAkB,MAAM;CAE1C,IAAI,SAAS,oBAAoB,MAC/B,OAAO,UAAU;MAEjB,UAAU,8CAA8C,SAAS;CAGnE,IAAI,SAAS,mBAAmB,KAAA,GAC9B,IAAI,6BAA6B,SAAS,eAAe,EACvD,UAAU,0CAA0C,SAAS;MAE7D,OAAO,UAAU;CAIrB,OAAO,OAAO,KAAK,UAAU,CAAC,SAAS,IAAI,YAAY;;AAGzD,SAAgB,6CACd,aACA,qBACS;CACT,MAAM,kBAAkB,gCAAgC,oBAAoB;CAC5E,IAAI,oBAAoB,MACtB,OAAO;CAGT,OAAO,sCAAsC,aAAa,gBAAgB;;AAG5E,SAAgB,gCAAgC,OAA+B;CAC7E,MAAM,QAAQ,kBAAkB,MAAM,CAAC;CACvC,OAAO,OAAO,UAAU,WAAW,QAAQ;;AAG7C,SAAS,6BAA6B,OAAiC;CACrE,OAAO,OAAO,UAAU,YAAY,OAAO,cAAc,MAAM,IAAI,SAAS;;AAG9E,SAAgB,+BAA+B,OAA+B;CAC5E,MAAM,QAAQ,kBAAkB,MAAM,CAAC;CACvC,OAAO,6BAA6B,MAAM,GAAG,QAAQ;;AAGvD,SAAgB,8BAA8B,SAGnB;CACzB,MAAM,qBAAqB,+BAA+B,QAAQ,aAAa;CAC/E,IAAI,YAA+B;CAEnC,IAAI,QAAQ,wBAAwB,QAAQ,uBAAuB;MAC7D,qBAAqB,QAAQ,qBAC/B,YAAY;OACP,IAAI,qBAAqB,QAAQ,qBACtC,YAAY;;CAIhB,OAAO;EACL;EACA,cAAc,QAAQ;EACtB;EACD"}
@@ -38,7 +38,8 @@ type AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageM
38
38
  loadSsrHandler: () => Promise<AppPageSsrHandler>;
39
39
  makeThenableParams: (params: AppPageParams) => unknown;
40
40
  middlewareContext: AppPageMiddlewareContext;
41
- metadataRoutes: MetadataFileRoute[];
41
+ metadataRoutes: MetadataFileRoute[]; /** Configured next.config `basePath`, threaded into file-based metadata href emission. */
42
+ basePath?: string;
42
43
  renderToReadableStream: (element: ReactNode | AppElements, options: {
43
44
  onError: AppPageBoundaryOnError;
44
45
  }) => ReadableStream<Uint8Array>;
@@ -55,6 +56,14 @@ type RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppP
55
56
  rootNotFoundModule?: TModule | null;
56
57
  rootUnauthorizedModule?: TModule | null;
57
58
  route?: AppPageBoundaryRoute<TModule> | null;
59
+ /**
60
+ * When true, the resolved boundary is rendered without wrapping it in the
61
+ * route's layouts. Used by `global-not-found.tsx`, which provides its own
62
+ * `<html>`/`<body>` and intentionally replaces the root layout.
63
+ * Mirrors Next.js's `createNotFoundLoaderTree` behavior for `hasGlobalNotFound`.
64
+ * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/app-render.tsx#L495-L520
65
+ */
66
+ skipLayoutWrapping?: boolean;
58
67
  statusCode: number;
59
68
  } & AppPageBoundaryRenderCommonOptions<TModule>;
60
69
  type RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {