vinext 0.0.53 → 0.0.55

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 (276) hide show
  1. package/README.md +1 -0
  2. package/dist/build/inline-css.d.ts +7 -0
  3. package/dist/build/inline-css.js +50 -0
  4. package/dist/build/inline-css.js.map +1 -0
  5. package/dist/build/prerender.js +2 -1
  6. package/dist/build/prerender.js.map +1 -1
  7. package/dist/check.js +19 -3
  8. package/dist/check.js.map +1 -1
  9. package/dist/client/navigation-runtime.d.ts +3 -1
  10. package/dist/client/navigation-runtime.js +1 -1
  11. package/dist/client/navigation-runtime.js.map +1 -1
  12. package/dist/client/window-next.d.ts +7 -0
  13. package/dist/client/window-next.js.map +1 -1
  14. package/dist/config/next-config.d.ts +97 -2
  15. package/dist/config/next-config.js +155 -6
  16. package/dist/config/next-config.js.map +1 -1
  17. package/dist/config/tsconfig-paths.d.ts +12 -3
  18. package/dist/config/tsconfig-paths.js +55 -24
  19. package/dist/config/tsconfig-paths.js.map +1 -1
  20. package/dist/deploy.js +13 -0
  21. package/dist/deploy.js.map +1 -1
  22. package/dist/entries/app-browser-entry.d.ts +11 -1
  23. package/dist/entries/app-browser-entry.js +16 -6
  24. package/dist/entries/app-browser-entry.js.map +1 -1
  25. package/dist/entries/app-rsc-entry.d.ts +9 -1
  26. package/dist/entries/app-rsc-entry.js +30 -5
  27. package/dist/entries/app-rsc-entry.js.map +1 -1
  28. package/dist/entries/app-rsc-manifest.d.ts +21 -1
  29. package/dist/entries/app-rsc-manifest.js +28 -9
  30. package/dist/entries/app-rsc-manifest.js.map +1 -1
  31. package/dist/entries/pages-client-entry.d.ts +4 -1
  32. package/dist/entries/pages-client-entry.js +18 -2
  33. package/dist/entries/pages-client-entry.js.map +1 -1
  34. package/dist/entries/pages-server-entry.js +123 -8
  35. package/dist/entries/pages-server-entry.js.map +1 -1
  36. package/dist/entries/runtime-entry-module.d.ts +1 -10
  37. package/dist/entries/runtime-entry-module.js +2 -12
  38. package/dist/entries/runtime-entry-module.js.map +1 -1
  39. package/dist/index.js +144 -44
  40. package/dist/index.js.map +1 -1
  41. package/dist/plugins/import-meta-url.d.ts +16 -0
  42. package/dist/plugins/import-meta-url.js +193 -0
  43. package/dist/plugins/import-meta-url.js.map +1 -0
  44. package/dist/plugins/remove-console.d.ts +16 -0
  45. package/dist/plugins/remove-console.js +176 -0
  46. package/dist/plugins/remove-console.js.map +1 -0
  47. package/dist/routing/app-route-graph.d.ts +24 -1
  48. package/dist/routing/app-route-graph.js +52 -4
  49. package/dist/routing/app-route-graph.js.map +1 -1
  50. package/dist/routing/app-router.d.ts +2 -2
  51. package/dist/routing/app-router.js +2 -2
  52. package/dist/routing/app-router.js.map +1 -1
  53. package/dist/routing/file-matcher.d.ts +21 -1
  54. package/dist/routing/file-matcher.js +39 -1
  55. package/dist/routing/file-matcher.js.map +1 -1
  56. package/dist/routing/pages-router.d.ts +1 -1
  57. package/dist/routing/pages-router.js +10 -3
  58. package/dist/routing/pages-router.js.map +1 -1
  59. package/dist/server/api-handler.js +1 -1
  60. package/dist/server/app-browser-action-result.d.ts +9 -16
  61. package/dist/server/app-browser-action-result.js +25 -14
  62. package/dist/server/app-browser-action-result.js.map +1 -1
  63. package/dist/server/app-browser-entry.js +195 -60
  64. package/dist/server/app-browser-entry.js.map +1 -1
  65. package/dist/server/app-browser-mpa-navigation.d.ts +16 -0
  66. package/dist/server/app-browser-mpa-navigation.js +36 -0
  67. package/dist/server/app-browser-mpa-navigation.js.map +1 -0
  68. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  69. package/dist/server/app-browser-navigation-controller.js +4 -0
  70. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  71. package/dist/server/app-browser-popstate.d.ts +3 -1
  72. package/dist/server/app-browser-popstate.js +15 -1
  73. package/dist/server/app-browser-popstate.js.map +1 -1
  74. package/dist/server/app-browser-state.js +2 -1
  75. package/dist/server/app-browser-state.js.map +1 -1
  76. package/dist/server/app-elements-wire.d.ts +13 -4
  77. package/dist/server/app-elements-wire.js +10 -1
  78. package/dist/server/app-elements-wire.js.map +1 -1
  79. package/dist/server/app-elements.d.ts +2 -2
  80. package/dist/server/app-elements.js +2 -2
  81. package/dist/server/app-elements.js.map +1 -1
  82. package/dist/server/app-fallback-renderer.d.ts +15 -5
  83. package/dist/server/app-fallback-renderer.js +10 -4
  84. package/dist/server/app-fallback-renderer.js.map +1 -1
  85. package/dist/server/app-inline-css-client.d.ts +7 -0
  86. package/dist/server/app-inline-css-client.js +37 -0
  87. package/dist/server/app-inline-css-client.js.map +1 -0
  88. package/dist/server/app-layout-param-observation.d.ts +30 -0
  89. package/dist/server/app-layout-param-observation.js +130 -0
  90. package/dist/server/app-layout-param-observation.js.map +1 -0
  91. package/dist/server/app-page-boundary-render.js +2 -2
  92. package/dist/server/app-page-boundary-render.js.map +1 -1
  93. package/dist/server/app-page-boundary.d.ts +21 -1
  94. package/dist/server/app-page-boundary.js +28 -3
  95. package/dist/server/app-page-boundary.js.map +1 -1
  96. package/dist/server/app-page-cache.d.ts +7 -3
  97. package/dist/server/app-page-cache.js +7 -7
  98. package/dist/server/app-page-cache.js.map +1 -1
  99. package/dist/server/app-page-dispatch.d.ts +10 -1
  100. package/dist/server/app-page-dispatch.js +126 -79
  101. package/dist/server/app-page-dispatch.js.map +1 -1
  102. package/dist/server/app-page-element-builder.js +12 -28
  103. package/dist/server/app-page-element-builder.js.map +1 -1
  104. package/dist/server/app-page-params.d.ts +2 -1
  105. package/dist/server/app-page-params.js +14 -1
  106. package/dist/server/app-page-params.js.map +1 -1
  107. package/dist/server/app-page-probe.d.ts +12 -1
  108. package/dist/server/app-page-probe.js +116 -1
  109. package/dist/server/app-page-probe.js.map +1 -1
  110. package/dist/server/app-page-render-identity.d.ts +22 -0
  111. package/dist/server/app-page-render-identity.js +42 -0
  112. package/dist/server/app-page-render-identity.js.map +1 -0
  113. package/dist/server/app-page-render.d.ts +8 -1
  114. package/dist/server/app-page-render.js +4 -1
  115. package/dist/server/app-page-render.js.map +1 -1
  116. package/dist/server/app-page-request.d.ts +6 -3
  117. package/dist/server/app-page-request.js +5 -2
  118. package/dist/server/app-page-request.js.map +1 -1
  119. package/dist/server/app-page-response.js +2 -2
  120. package/dist/server/app-page-response.js.map +1 -1
  121. package/dist/server/app-page-route-wiring.d.ts +15 -0
  122. package/dist/server/app-page-route-wiring.js +7 -5
  123. package/dist/server/app-page-route-wiring.js.map +1 -1
  124. package/dist/server/app-page-stream.d.ts +11 -0
  125. package/dist/server/app-page-stream.js +1 -0
  126. package/dist/server/app-page-stream.js.map +1 -1
  127. package/dist/server/app-route-handler-response.js +37 -5
  128. package/dist/server/app-route-handler-response.js.map +1 -1
  129. package/dist/server/app-rsc-cache-busting.d.ts +3 -2
  130. package/dist/server/app-rsc-cache-busting.js +9 -7
  131. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  132. package/dist/server/app-rsc-handler.d.ts +14 -3
  133. package/dist/server/app-rsc-handler.js +56 -6
  134. package/dist/server/app-rsc-handler.js.map +1 -1
  135. package/dist/server/app-rsc-request-normalization.d.ts +2 -1
  136. package/dist/server/app-rsc-request-normalization.js +3 -2
  137. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  138. package/dist/server/app-segment-config.d.ts +1 -1
  139. package/dist/server/app-segment-config.js +4 -1
  140. package/dist/server/app-segment-config.js.map +1 -1
  141. package/dist/server/app-server-action-execution.d.ts +26 -3
  142. package/dist/server/app-server-action-execution.js +240 -29
  143. package/dist/server/app-server-action-execution.js.map +1 -1
  144. package/dist/server/app-ssr-entry.d.ts +6 -0
  145. package/dist/server/app-ssr-entry.js +22 -7
  146. package/dist/server/app-ssr-entry.js.map +1 -1
  147. package/dist/server/app-ssr-error-meta.js +3 -3
  148. package/dist/server/app-ssr-error-meta.js.map +1 -1
  149. package/dist/server/app-ssr-stream.d.ts +2 -1
  150. package/dist/server/app-ssr-stream.js +176 -31
  151. package/dist/server/app-ssr-stream.js.map +1 -1
  152. package/dist/server/artifact-compatibility.d.ts +2 -1
  153. package/dist/server/artifact-compatibility.js +10 -1
  154. package/dist/server/artifact-compatibility.js.map +1 -1
  155. package/dist/server/client-reuse-manifest.d.ts +9 -4
  156. package/dist/server/client-reuse-manifest.js +2 -1
  157. package/dist/server/client-reuse-manifest.js.map +1 -1
  158. package/dist/server/client-trace-metadata.d.ts +31 -0
  159. package/dist/server/client-trace-metadata.js +83 -0
  160. package/dist/server/client-trace-metadata.js.map +1 -0
  161. package/dist/server/cookie-utils.d.ts +13 -0
  162. package/dist/server/cookie-utils.js +20 -0
  163. package/dist/server/cookie-utils.js.map +1 -0
  164. package/dist/server/dev-server.d.ts +8 -1
  165. package/dist/server/dev-server.js +83 -12
  166. package/dist/server/dev-server.js.map +1 -1
  167. package/dist/server/document-initial-head.d.ts +7 -0
  168. package/dist/server/document-initial-head.js +35 -0
  169. package/dist/server/document-initial-head.js.map +1 -0
  170. package/dist/server/html.d.ts +2 -1
  171. package/dist/server/html.js +6 -1
  172. package/dist/server/html.js.map +1 -1
  173. package/dist/server/isr-cache.d.ts +7 -5
  174. package/dist/server/isr-cache.js +17 -6
  175. package/dist/server/isr-cache.js.map +1 -1
  176. package/dist/server/middleware-runtime.js +1 -2
  177. package/dist/server/middleware-runtime.js.map +1 -1
  178. package/dist/server/pages-document-initial-props.d.ts +89 -0
  179. package/dist/server/pages-document-initial-props.js +140 -0
  180. package/dist/server/pages-document-initial-props.js.map +1 -0
  181. package/dist/server/pages-node-compat.js +1 -1
  182. package/dist/server/pages-page-data.js +3 -0
  183. package/dist/server/pages-page-data.js.map +1 -1
  184. package/dist/server/pages-page-method.d.ts +48 -0
  185. package/dist/server/pages-page-method.js +19 -0
  186. package/dist/server/pages-page-method.js.map +1 -0
  187. package/dist/server/pages-page-response.d.ts +20 -0
  188. package/dist/server/pages-page-response.js +37 -7
  189. package/dist/server/pages-page-response.js.map +1 -1
  190. package/dist/server/pages-serializable-props.d.ts +25 -0
  191. package/dist/server/pages-serializable-props.js +69 -0
  192. package/dist/server/pages-serializable-props.js.map +1 -0
  193. package/dist/server/prod-server.js +16 -6
  194. package/dist/server/prod-server.js.map +1 -1
  195. package/dist/server/server-action-not-found.js +3 -2
  196. package/dist/server/server-action-not-found.js.map +1 -1
  197. package/dist/server/skip-cache-proof.d.ts +23 -2
  198. package/dist/server/skip-cache-proof.js +81 -12
  199. package/dist/server/skip-cache-proof.js.map +1 -1
  200. package/dist/server/static-file-cache.js +2 -1
  201. package/dist/server/static-file-cache.js.map +1 -1
  202. package/dist/server/static-layout-client-reuse-proof.d.ts +16 -0
  203. package/dist/server/static-layout-client-reuse-proof.js +35 -0
  204. package/dist/server/static-layout-client-reuse-proof.js.map +1 -0
  205. package/dist/shims/app-router-scroll-state.d.ts +4 -2
  206. package/dist/shims/app-router-scroll-state.js +16 -3
  207. package/dist/shims/app-router-scroll-state.js.map +1 -1
  208. package/dist/shims/app-router-scroll.d.ts +16 -2
  209. package/dist/shims/app-router-scroll.js +18 -3
  210. package/dist/shims/app-router-scroll.js.map +1 -1
  211. package/dist/shims/cache.d.ts +27 -1
  212. package/dist/shims/cache.js +108 -6
  213. package/dist/shims/cache.js.map +1 -1
  214. package/dist/shims/document.d.ts +6 -0
  215. package/dist/shims/document.js +7 -8
  216. package/dist/shims/document.js.map +1 -1
  217. package/dist/shims/error-boundary.d.ts +4 -4
  218. package/dist/shims/error-boundary.js +27 -28
  219. package/dist/shims/error-boundary.js.map +1 -1
  220. package/dist/shims/error.js +3 -0
  221. package/dist/shims/error.js.map +1 -1
  222. package/dist/shims/fetch-cache.d.ts +3 -1
  223. package/dist/shims/fetch-cache.js +16 -5
  224. package/dist/shims/fetch-cache.js.map +1 -1
  225. package/dist/shims/hash-scroll.d.ts +4 -1
  226. package/dist/shims/hash-scroll.js +13 -1
  227. package/dist/shims/hash-scroll.js.map +1 -1
  228. package/dist/shims/head-state.d.ts +1 -0
  229. package/dist/shims/head-state.js +18 -3
  230. package/dist/shims/head-state.js.map +1 -1
  231. package/dist/shims/head.d.ts +35 -1
  232. package/dist/shims/head.js +113 -14
  233. package/dist/shims/head.js.map +1 -1
  234. package/dist/shims/headers.d.ts +7 -0
  235. package/dist/shims/headers.js +9 -1
  236. package/dist/shims/headers.js.map +1 -1
  237. package/dist/shims/internal/app-route-detection.d.ts +37 -0
  238. package/dist/shims/internal/app-route-detection.js +69 -0
  239. package/dist/shims/internal/app-route-detection.js.map +1 -0
  240. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +56 -0
  241. package/dist/shims/internal/pages-data-fetch-dedup.js +70 -0
  242. package/dist/shims/internal/pages-data-fetch-dedup.js.map +1 -0
  243. package/dist/shims/link.d.ts +18 -2
  244. package/dist/shims/link.js +98 -8
  245. package/dist/shims/link.js.map +1 -1
  246. package/dist/shims/metadata.d.ts +7 -6
  247. package/dist/shims/metadata.js +9 -5
  248. package/dist/shims/metadata.js.map +1 -1
  249. package/dist/shims/navigation.d.ts +40 -3
  250. package/dist/shims/navigation.js +124 -25
  251. package/dist/shims/navigation.js.map +1 -1
  252. package/dist/shims/router.d.ts +5 -0
  253. package/dist/shims/router.js +51 -21
  254. package/dist/shims/router.js.map +1 -1
  255. package/dist/shims/script.d.ts +11 -1
  256. package/dist/shims/script.js +75 -6
  257. package/dist/shims/script.js.map +1 -1
  258. package/dist/shims/thenable-params.d.ts +5 -2
  259. package/dist/shims/thenable-params.js +25 -1
  260. package/dist/shims/thenable-params.js.map +1 -1
  261. package/dist/shims/unified-request-context.js +3 -0
  262. package/dist/shims/unified-request-context.js.map +1 -1
  263. package/dist/utils/client-build-manifest.d.ts +15 -0
  264. package/dist/utils/client-build-manifest.js +54 -0
  265. package/dist/utils/client-build-manifest.js.map +1 -0
  266. package/dist/utils/hash.js +1 -1
  267. package/dist/utils/hash.js.map +1 -1
  268. package/dist/utils/lazy-chunks.d.ts +1 -1
  269. package/dist/utils/lazy-chunks.js.map +1 -1
  270. package/dist/utils/path.d.ts +13 -0
  271. package/dist/utils/path.js +16 -0
  272. package/dist/utils/path.js.map +1 -0
  273. package/dist/utils/vite-version.d.ts +11 -0
  274. package/dist/utils/vite-version.js +36 -0
  275. package/dist/utils/vite-version.js.map +1 -0
  276. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-element-builder.js","names":[],"sources":["../../src/server/app-page-element-builder.ts"],"sourcesContent":["import { createElement } from \"react\";\nimport { markDynamicUsage, markRenderRequestApiUsage } from \"vinext/shims/headers\";\nimport { makeThenableParams } from \"vinext/shims/thenable-params\";\nimport { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from \"./app-page-head.js\";\nimport {\n buildAppPageElements,\n createAppPageTreePath,\n type AppPageErrorModule,\n type AppPageModule,\n type AppPageRouteWiringRoute,\n type AppPageSlotOverride,\n} from \"./app-page-route-wiring.js\";\nimport { AppElementsWire, type AppElements, type AppElementsInterception } from \"./app-elements.js\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport { DEFAULT_GLOBAL_ERROR_MODULE } from \"./default-global-error-module.js\";\nimport { matchRoutePattern } from \"../routing/route-pattern.js\";\nimport { normalizePathnameForRouteMatch } from \"../routing/utils.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport { APP_RSC_RENDER_MODE_NAVIGATION, type AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport { isInterceptionMatchedUrlPath, normalizePath } from \"./normalize-path.js\";\nimport { shouldServeStreamingMetadata } from \"./streaming-metadata.js\";\n\nexport type { AppPageErrorModule, AppPageRouteWiringRoute } from \"./app-page-route-wiring.js\";\n\n/**\n * Route shape passed from the generated entry. Extends the wiring route with\n * the page module reference (used to extract the default export for the page\n * element) and the URL pattern (used as the route path in head resolution).\n */\nexport type AppPageBuildRoute<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = AppPageRouteWiringRoute<TModule, TErrorModule> & {\n page?: TModule | null;\n pattern: string;\n /** Param names captured by the route's URL pattern, in order. */\n params?: readonly string[] | null;\n};\n\nexport type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {\n interceptionContext?: string | null;\n interceptLayouts?: readonly (TModule | null | undefined)[] | null;\n interceptPage?: TModule | null;\n interceptParams?: AppPageParams | null;\n interceptSlotId?: string | null;\n interceptSlotKey?: string | null;\n interceptSourceMatchedUrl?: string | null;\n};\n\nexport type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> = {\n /** Interception context from current-route navigation (null for direct visits). */\n opts?: AppPageInterceptOptions<TModule> | null;\n /** URL search params from the incoming request (null when unavailable). */\n searchParams?: URLSearchParams | null;\n /** Whether the incoming request is an RSC (client-side navigation) request. */\n isRscRequest: boolean;\n /** The incoming HTTP request (available but unused by this module). */\n request: Request;\n /** Normalized x-vinext-mounted-slots header value. */\n mountedSlotsHeader: string | null;\n /** Semantic RSC payload mode for this page render. */\n renderMode?: AppRscRenderMode;\n};\n\nexport type BuildPageElementsOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n route: AppPageBuildRoute<TModule, TErrorModule>;\n params: AppPageParams;\n routePath: string;\n pageRequest: AppPagePageRequest<TModule>;\n /** Root-level global-error.tsx module. Present when the app defines this file. */\n globalErrorModule?: TErrorModule | null;\n /** Root-level not-found.tsx module. Present when the app defines this file. */\n rootNotFoundModule?: TModule | null;\n /** Root-level forbidden.tsx module. Present when the app defines this file. */\n rootForbiddenModule?: TModule | null;\n /** Root-level unauthorized.tsx module. Present when the app defines this file. */\n rootUnauthorizedModule?: TModule | null;\n /** File-based metadata routes (favicon, manifest, sitemap, etc.). */\n metadataRoutes: readonly MetadataFileRoute[];\n /**\n * Configured next.config `basePath`. Threaded through `resolveAppPageHead`\n * so file-based metadata route URLs emitted in <head> are prefixed.\n */\n basePath?: string;\n /** Serialized next.config `htmlLimitedBots` regexp source. */\n htmlLimitedBots?: string;\n};\n\n/**\n * Build the App Router element tree for a matched route.\n *\n * This is the central element-construction path for the App Router RSC\n * handler. It resolves page head metadata (including parallel route metadata),\n * creates the page React element, and wires it into the nested layout +\n * boundary tree via {@link buildAppPageElements}.\n *\n * The function is extracted from the generated RSC entry template so it can\n * be unit-tested independently of the code-generation machinery.\n *\n * Next.js equivalent: the component tree construction in\n * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx|create-component-tree.tsx}\n * and the page head resolution in\n * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-metadata.tsx|create-metadata.tsx}.\n */\nexport async function buildPageElements<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n>(options: BuildPageElementsOptions<TModule, TErrorModule>): Promise<AppElements> {\n const {\n route,\n params,\n routePath,\n pageRequest,\n globalErrorModule,\n rootNotFoundModule,\n rootForbiddenModule,\n rootUnauthorizedModule,\n metadataRoutes,\n } = options;\n const {\n opts,\n searchParams,\n isRscRequest,\n mountedSlotsHeader,\n renderMode = APP_RSC_RENDER_MODE_NAVIGATION,\n } = pageRequest;\n\n const pageModule: AppPageModule | null | undefined = route.page;\n const PageComponent = pageModule?.default;\n const hasPageModule = !!pageModule;\n const interception = createAppPageInterceptionProof(routePath, opts);\n\n if (hasPageModule && !PageComponent) {\n const interceptionContext = opts?.interceptionContext ?? null;\n const noExportRouteId = AppElementsWire.encodeRouteId(routePath, interceptionContext);\n let noExportRootLayout: string | null = null;\n const noExportLayoutIds =\n route.ids?.layouts ??\n route.layouts.map((_, index) =>\n AppElementsWire.encodeLayoutId(\n createAppPageTreePath(route.routeSegments, route.layoutTreePositions?.[index] ?? 0),\n ),\n );\n if (route.layouts?.length > 0) {\n const treePosition = route.layoutTreePositions?.[0] ?? 0;\n noExportRootLayout = createAppPageTreePath(route.routeSegments, treePosition);\n }\n return {\n ...AppElementsWire.createMetadataEntries({\n interception,\n interceptionContext,\n layoutIds: noExportLayoutIds,\n rootLayoutTreePath: noExportRootLayout,\n routeId: noExportRouteId,\n }),\n [noExportRouteId]: createElement(\"div\", null, \"Page has no default export\"),\n };\n }\n\n const {\n hasSearchParams,\n hasDynamicMetadata,\n metadata: resolvedMetadata,\n pageSearchParams,\n viewport: resolvedViewport,\n } = await resolveAppPageHead({\n basePath: options.basePath ?? \"\",\n layoutModules: route.layouts,\n layoutTreePositions: route.layoutTreePositions,\n metadataRoutes,\n pageModule: route.page ?? null,\n parallelRoutes: resolveActiveParallelRouteHeadInputs({\n interceptLayouts: opts?.interceptLayouts ?? null,\n interceptPage: opts?.interceptPage ?? null,\n interceptParams: opts?.interceptParams ?? null,\n interceptSlotKey: opts?.interceptSlotKey ?? null,\n params,\n routeSegments: route.routeSegments ?? [],\n slots: route.slots ?? null,\n }),\n params,\n routePath: route.pattern,\n routeSegments: route.routeSegments ?? null,\n searchParams,\n });\n\n const pageProps: Record<string, unknown> = { params: makeThenableParams(params) };\n if (searchParams) {\n pageProps.searchParams = makeThenableParams(pageSearchParams);\n if (hasSearchParams) {\n markDynamicUsage();\n markRenderRequestApiUsage(\"searchParams\");\n }\n }\n\n const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(\" \")) : null;\n\n const slotOverrides = buildSlotOverrides(route, params, routePath, opts);\n const metadataPlacement =\n hasDynamicMetadata &&\n shouldServeStreamingMetadata(\n pageRequest.request.headers.get(\"user-agent\") ?? \"\",\n options.htmlLimitedBots,\n )\n ? \"body\"\n : \"head\";\n\n return buildAppPageElements({\n element: PageComponent ? createElement(PageComponent, pageProps) : null,\n // Fall back to vinext's built-in default global error module so that\n // uncaught client render errors are caught by the route-level\n // <ErrorBoundary> wrapper in app-page-route-wiring.tsx, mirroring\n // Next.js's behavior when the user has not defined app/global-error.tsx.\n globalErrorModule:\n globalErrorModule ?? (DEFAULT_GLOBAL_ERROR_MODULE as unknown as TErrorModule),\n isRscRequest,\n mountedSlotIds,\n makeThenableParams,\n matchedParams: params,\n metadataPlacement,\n resolvedMetadata,\n resolvedMetadataPathname: routePath,\n resolvedViewport,\n interceptionContext: opts?.interceptionContext ?? null,\n interception,\n routePath,\n rootNotFoundModule: rootNotFoundModule ?? null,\n rootForbiddenModule: rootForbiddenModule ?? null,\n rootUnauthorizedModule: rootUnauthorizedModule ?? null,\n route,\n slotOverrides,\n renderMode,\n });\n}\n\nfunction createAppPageInterceptionProof<TModule extends AppPageModule>(\n routePath: string,\n opts?: AppPageInterceptOptions<TModule> | null,\n): AppElementsInterception | null {\n const sourceMatchedUrl = normalizeInterceptionProofMatchedUrl(\n opts?.interceptSourceMatchedUrl ?? null,\n );\n const targetMatchedUrl = normalizeInterceptionProofMatchedUrl(routePath);\n const slotId = opts?.interceptSlotId ?? null;\n if (sourceMatchedUrl === null || targetMatchedUrl === null || slotId === null) return null;\n\n return {\n sourceMatchedUrl,\n sourceRouteId: AppElementsWire.encodeRouteId(sourceMatchedUrl, null),\n slotId,\n targetMatchedUrl,\n targetRouteId: AppElementsWire.encodeRouteId(targetMatchedUrl, null),\n };\n}\n\nfunction normalizeInterceptionProofMatchedUrl(value: string | null): string | null {\n if (value === null || !isInterceptionMatchedUrlPath(value)) return null;\n\n return normalizePath(normalizePathnameForRouteMatch(value));\n}\n\n/**\n * Build the per-request `slotOverrides` map. Combines:\n * - Interception overrides (existing behavior — swap in the intercepting page\n * and its layouts when the request is intercepted into this slot).\n * - Slot-specific param extraction for inherited slots whose URL pattern\n * has different param names than the route's. The runtime matches the\n * cleaned request path against `slot.slotPatternParts` to produce\n * slot-scoped params, which `app-page-route-wiring` then hands to the\n * slot page instead of the route's matched params.\n *\n * `routePath` is the already-normalized request pathname (basePath stripped,\n * RSC suffix removed). Re-parsing `request.url` here would re-introduce the\n * basePath and silently break the match for any app that configures one.\n */\nfunction buildSlotOverrides<TModule extends AppPageModule, TErrorModule extends AppPageErrorModule>(\n route: AppPageBuildRoute<TModule, TErrorModule>,\n routeParams: AppPageParams,\n routePath: string,\n opts?: AppPageInterceptOptions<TModule> | null,\n): Readonly<Record<string, AppPageSlotOverride<TModule>>> | null {\n const overrides: Record<string, AppPageSlotOverride<TModule>> = {};\n\n if (opts && opts.interceptSlotKey && opts.interceptPage) {\n overrides[opts.interceptSlotKey] = {\n layoutModules: opts.interceptLayouts || null,\n pageModule: opts.interceptPage,\n params: opts.interceptParams || routeParams,\n };\n }\n\n const slots = route.slots;\n if (slots) {\n let urlParts: string[] | null = null;\n const routeParamSet = collectParamNameSet(route.params);\n for (const [slotKey, slot] of Object.entries(slots)) {\n const patternParts = slot.slotPatternParts;\n const paramNames = slot.slotParamNames;\n if (!patternParts || patternParts.length === 0) continue;\n // Skip when every slot param is already a route param — the route's\n // matched params already carry the values the slot page expects.\n // Empty `paramNames` (slot pattern has no dynamic markers) also skips:\n // there's nothing to extract, so the route's matched params suffice.\n if (paramNames && paramNames.every((name) => routeParamSet.has(name))) continue;\n\n if (urlParts === null) {\n urlParts = routePath.split(\"/\").filter(Boolean);\n }\n const matched = matchRoutePattern(urlParts, patternParts);\n if (!matched) continue;\n\n const existing = overrides[slotKey];\n overrides[slotKey] = existing ? { ...existing, params: matched } : { params: matched };\n }\n }\n\n return Object.keys(overrides).length > 0 ? overrides : null;\n}\n\nfunction collectParamNameSet(params: readonly string[] | undefined | null): Set<string> {\n const set = new Set<string>();\n if (params) {\n for (const name of params) set.add(name);\n }\n return set;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-page-element-builder.js","names":[],"sources":["../../src/server/app-page-element-builder.ts"],"sourcesContent":["import { createElement } from \"react\";\nimport { markDynamicUsage, markRenderRequestApiUsage } from \"vinext/shims/headers\";\nimport { makeThenableParams } from \"vinext/shims/thenable-params\";\nimport { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from \"./app-page-head.js\";\nimport {\n buildAppPageElements,\n createAppPageTreePath,\n type AppPageErrorModule,\n type AppPageModule,\n type AppPageRouteWiringRoute,\n type AppPageSlotOverride,\n} from \"./app-page-route-wiring.js\";\nimport { AppElementsWire, type AppElements } from \"./app-elements.js\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport { DEFAULT_GLOBAL_ERROR_MODULE } from \"./default-global-error-module.js\";\nimport { matchRoutePattern } from \"../routing/route-pattern.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport { APP_RSC_RENDER_MODE_NAVIGATION, type AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport { createAppPageRenderIdentity } from \"./app-page-render-identity.js\";\nimport { shouldServeStreamingMetadata } from \"./streaming-metadata.js\";\n\nexport type { AppPageErrorModule, AppPageRouteWiringRoute } from \"./app-page-route-wiring.js\";\n\n/**\n * Route shape passed from the generated entry. Extends the wiring route with\n * the page module reference (used to extract the default export for the page\n * element) and the URL pattern (used as the route path in head resolution).\n */\nexport type AppPageBuildRoute<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = AppPageRouteWiringRoute<TModule, TErrorModule> & {\n page?: TModule | null;\n pattern: string;\n /** Param names captured by the route's URL pattern, in order. */\n params?: readonly string[] | null;\n};\n\nexport type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {\n interceptionContext?: string | null;\n interceptLayouts?: readonly (TModule | null | undefined)[] | null;\n interceptPage?: TModule | null;\n interceptParams?: AppPageParams | null;\n interceptSlotId?: string | null;\n interceptSlotKey?: string | null;\n interceptSourceMatchedUrl?: string | null;\n};\n\nexport type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> = {\n /** Interception context from current-route navigation (null for direct visits). */\n opts?: AppPageInterceptOptions<TModule> | null;\n /** URL search params from the incoming request (null when unavailable). */\n searchParams?: URLSearchParams | null;\n /** Whether the incoming request is an RSC (client-side navigation) request. */\n isRscRequest: boolean;\n /** The incoming HTTP request (available but unused by this module). */\n request: Request;\n /** Normalized x-vinext-mounted-slots header value. */\n mountedSlotsHeader: string | null;\n /** Semantic RSC payload mode for this page render. */\n renderMode?: AppRscRenderMode;\n};\n\nexport type BuildPageElementsOptions<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n> = {\n route: AppPageBuildRoute<TModule, TErrorModule>;\n params: AppPageParams;\n routePath: string;\n pageRequest: AppPagePageRequest<TModule>;\n /** Root-level global-error.tsx module. Present when the app defines this file. */\n globalErrorModule?: TErrorModule | null;\n /** Root-level not-found.tsx module. Present when the app defines this file. */\n rootNotFoundModule?: TModule | null;\n /** Root-level forbidden.tsx module. Present when the app defines this file. */\n rootForbiddenModule?: TModule | null;\n /** Root-level unauthorized.tsx module. Present when the app defines this file. */\n rootUnauthorizedModule?: TModule | null;\n /** File-based metadata routes (favicon, manifest, sitemap, etc.). */\n metadataRoutes: readonly MetadataFileRoute[];\n /**\n * Configured next.config `basePath`. Threaded through `resolveAppPageHead`\n * so file-based metadata route URLs emitted in <head> are prefixed.\n */\n basePath?: string;\n /** Serialized next.config `htmlLimitedBots` regexp source. */\n htmlLimitedBots?: string;\n};\n\n/**\n * Build the App Router element tree for a matched route.\n *\n * This is the central element-construction path for the App Router RSC\n * handler. It resolves page head metadata (including parallel route metadata),\n * creates the page React element, and wires it into the nested layout +\n * boundary tree via {@link buildAppPageElements}.\n *\n * The function is extracted from the generated RSC entry template so it can\n * be unit-tested independently of the code-generation machinery.\n *\n * Next.js equivalent: the component tree construction in\n * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx|create-component-tree.tsx}\n * and the page head resolution in\n * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-metadata.tsx|create-metadata.tsx}.\n */\nexport async function buildPageElements<\n TModule extends AppPageModule = AppPageModule,\n TErrorModule extends AppPageErrorModule = AppPageErrorModule,\n>(options: BuildPageElementsOptions<TModule, TErrorModule>): Promise<AppElements> {\n const {\n route,\n params,\n routePath,\n pageRequest,\n globalErrorModule,\n rootNotFoundModule,\n rootForbiddenModule,\n rootUnauthorizedModule,\n metadataRoutes,\n } = options;\n const {\n opts,\n searchParams,\n isRscRequest,\n mountedSlotsHeader,\n renderMode = APP_RSC_RENDER_MODE_NAVIGATION,\n } = pageRequest;\n\n const pageModule: AppPageModule | null | undefined = route.page;\n const PageComponent = pageModule?.default;\n const hasPageModule = !!pageModule;\n const renderIdentity = createAppPageRenderIdentity({\n displayPathname: routePath,\n interceptionContext: opts?.interceptionContext ?? null,\n interceptSourceMatchedUrl: opts?.interceptSourceMatchedUrl ?? null,\n interceptSlotId: opts?.interceptSlotId ?? null,\n });\n\n if (hasPageModule && !PageComponent) {\n let noExportRootLayout: string | null = null;\n const noExportLayoutIds =\n route.ids?.layouts ??\n route.layouts.map((_, index) =>\n AppElementsWire.encodeLayoutId(\n createAppPageTreePath(route.routeSegments, route.layoutTreePositions?.[index] ?? 0),\n ),\n );\n if (route.layouts?.length > 0) {\n const treePosition = route.layoutTreePositions?.[0] ?? 0;\n noExportRootLayout = createAppPageTreePath(route.routeSegments, treePosition);\n }\n return {\n ...AppElementsWire.createMetadataEntries({\n interception: renderIdentity.interception,\n interceptionContext: renderIdentity.interceptionContext,\n layoutIds: noExportLayoutIds,\n rootLayoutTreePath: noExportRootLayout,\n routeId: renderIdentity.routeId,\n }),\n [renderIdentity.routeId]: createElement(\"div\", null, \"Page has no default export\"),\n };\n }\n\n const {\n hasSearchParams,\n hasDynamicMetadata,\n metadata: resolvedMetadata,\n pageSearchParams,\n viewport: resolvedViewport,\n } = await resolveAppPageHead({\n basePath: options.basePath ?? \"\",\n layoutModules: route.layouts,\n layoutTreePositions: route.layoutTreePositions,\n metadataRoutes,\n pageModule: route.page ?? null,\n parallelRoutes: resolveActiveParallelRouteHeadInputs({\n interceptLayouts: opts?.interceptLayouts ?? null,\n interceptPage: opts?.interceptPage ?? null,\n interceptParams: opts?.interceptParams ?? null,\n interceptSlotKey: opts?.interceptSlotKey ?? null,\n params,\n routeSegments: route.routeSegments ?? [],\n slots: route.slots ?? null,\n }),\n params,\n routePath: route.pattern,\n routeSegments: route.routeSegments ?? null,\n searchParams,\n });\n\n const pageProps: Record<string, unknown> = { params: makeThenableParams(params) };\n if (searchParams) {\n pageProps.searchParams = makeThenableParams(pageSearchParams);\n if (hasSearchParams) {\n markDynamicUsage();\n markRenderRequestApiUsage(\"searchParams\");\n }\n }\n\n const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(\" \")) : null;\n\n const slotOverrides = buildSlotOverrides(route, params, routePath, opts);\n const metadataPlacement =\n hasDynamicMetadata &&\n shouldServeStreamingMetadata(\n pageRequest.request.headers.get(\"user-agent\") ?? \"\",\n options.htmlLimitedBots,\n )\n ? \"body\"\n : \"head\";\n\n return buildAppPageElements({\n element: PageComponent ? createElement(PageComponent, pageProps) : null,\n // Fall back to vinext's built-in default global error module so that\n // uncaught client render errors are caught by the route-level\n // <ErrorBoundary> wrapper in app-page-route-wiring.tsx, mirroring\n // Next.js's behavior when the user has not defined app/global-error.tsx.\n globalErrorModule:\n globalErrorModule ?? (DEFAULT_GLOBAL_ERROR_MODULE as unknown as TErrorModule),\n isRscRequest,\n mountedSlotIds,\n makeThenableParams,\n matchedParams: params,\n metadataPlacement,\n resolvedMetadata,\n resolvedMetadataPathname: routePath,\n resolvedViewport,\n renderIdentity,\n routePath,\n rootNotFoundModule: rootNotFoundModule ?? null,\n rootForbiddenModule: rootForbiddenModule ?? null,\n rootUnauthorizedModule: rootUnauthorizedModule ?? null,\n route,\n slotOverrides,\n renderMode,\n });\n}\n\n/**\n * Build the per-request `slotOverrides` map. Combines:\n * - Interception overrides (existing behavior — swap in the intercepting page\n * and its layouts when the request is intercepted into this slot).\n * - Slot-specific param extraction for inherited slots whose URL pattern\n * has different param names than the route's. The runtime matches the\n * cleaned request path against `slot.slotPatternParts` to produce\n * slot-scoped params, which `app-page-route-wiring` then hands to the\n * slot page instead of the route's matched params.\n *\n * `routePath` is the already-normalized request pathname (basePath stripped,\n * RSC suffix removed). Re-parsing `request.url` here would re-introduce the\n * basePath and silently break the match for any app that configures one.\n */\nfunction buildSlotOverrides<TModule extends AppPageModule, TErrorModule extends AppPageErrorModule>(\n route: AppPageBuildRoute<TModule, TErrorModule>,\n routeParams: AppPageParams,\n routePath: string,\n opts?: AppPageInterceptOptions<TModule> | null,\n): Readonly<Record<string, AppPageSlotOverride<TModule>>> | null {\n const overrides: Record<string, AppPageSlotOverride<TModule>> = {};\n\n if (opts && opts.interceptSlotKey && opts.interceptPage) {\n overrides[opts.interceptSlotKey] = {\n layoutModules: opts.interceptLayouts || null,\n pageModule: opts.interceptPage,\n params: opts.interceptParams || routeParams,\n };\n }\n\n const slots = route.slots;\n if (slots) {\n let urlParts: string[] | null = null;\n const routeParamSet = collectParamNameSet(route.params);\n for (const [slotKey, slot] of Object.entries(slots)) {\n const patternParts = slot.slotPatternParts;\n const paramNames = slot.slotParamNames;\n if (!patternParts || patternParts.length === 0) continue;\n // Skip when every slot param is already a route param — the route's\n // matched params already carry the values the slot page expects.\n // Empty `paramNames` (slot pattern has no dynamic markers) also skips:\n // there's nothing to extract, so the route's matched params suffice.\n if (paramNames && paramNames.every((name) => routeParamSet.has(name))) continue;\n\n if (urlParts === null) {\n urlParts = routePath.split(\"/\").filter(Boolean);\n }\n const matched = matchRoutePattern(urlParts, patternParts);\n if (!matched) continue;\n\n const existing = overrides[slotKey];\n overrides[slotKey] = existing ? { ...existing, params: matched } : { params: matched };\n }\n }\n\n return Object.keys(overrides).length > 0 ? overrides : null;\n}\n\nfunction collectParamNameSet(params: readonly string[] | undefined | null): Set<string> {\n const set = new Set<string>();\n if (params) {\n for (const name of params) set.add(name);\n }\n return set;\n}\n"],"mappings":"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"}
@@ -2,7 +2,8 @@ import { AppPageParams } from "./app-page-boundary.js";
2
2
 
3
3
  //#region src/server/app-page-params.d.ts
4
4
  declare function getAppPageSegmentParamName(segment: string): string | null;
5
+ declare function resolveAppPageSegmentParamScopeKeys(routeSegments: readonly string[] | null | undefined, treePosition: number): readonly string[];
5
6
  declare function resolveAppPageSegmentParams(routeSegments: readonly string[] | null | undefined, treePosition: number, matchedParams: AppPageParams): AppPageParams;
6
7
  //#endregion
7
- export { getAppPageSegmentParamName, resolveAppPageSegmentParams };
8
+ export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
8
9
  //# sourceMappingURL=app-page-params.d.ts.map
@@ -8,6 +8,19 @@ function getAppPageSegmentParamName(segment) {
8
8
  function isEmptyOptionalCatchAll(segment, paramValue) {
9
9
  return segment.startsWith("[[...") && Array.isArray(paramValue) && paramValue.length === 0;
10
10
  }
11
+ function resolveAppPageSegmentParamScopeKeys(routeSegments, treePosition) {
12
+ const paramNames = [];
13
+ const seen = /* @__PURE__ */ new Set();
14
+ const segments = routeSegments ?? [];
15
+ const end = Math.min(Math.max(treePosition, 0), segments.length);
16
+ for (let index = 0; index < end; index++) {
17
+ const paramName = getAppPageSegmentParamName(segments[index]);
18
+ if (!paramName || seen.has(paramName)) continue;
19
+ seen.add(paramName);
20
+ paramNames.push(paramName);
21
+ }
22
+ return paramNames;
23
+ }
11
24
  function resolveAppPageSegmentParams(routeSegments, treePosition, matchedParams) {
12
25
  const segmentParams = {};
13
26
  const segments = routeSegments ?? [];
@@ -23,6 +36,6 @@ function resolveAppPageSegmentParams(routeSegments, treePosition, matchedParams)
23
36
  return segmentParams;
24
37
  }
25
38
  //#endregion
26
- export { getAppPageSegmentParamName, resolveAppPageSegmentParams };
39
+ export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
27
40
 
28
41
  //# sourceMappingURL=app-page-params.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-params.js","names":[],"sources":["../../src/server/app-page-params.ts"],"sourcesContent":["import type { AppPageParams } from \"./app-page-boundary.js\";\n\nexport function getAppPageSegmentParamName(segment: string): string | null {\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\") && segment.length > 7) {\n return segment.slice(5, -2);\n }\n\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\") && segment.length > 5) {\n return segment.slice(4, -1);\n }\n\n if (\n segment.startsWith(\"[\") &&\n segment.endsWith(\"]\") &&\n !segment.includes(\".\") &&\n segment.length > 2\n ) {\n return segment.slice(1, -1);\n }\n\n return null;\n}\n\nfunction isEmptyOptionalCatchAll(segment: string, paramValue: string | string[]): boolean {\n return segment.startsWith(\"[[...\") && Array.isArray(paramValue) && paramValue.length === 0;\n}\n\nexport function resolveAppPageSegmentParams(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n matchedParams: AppPageParams,\n): AppPageParams {\n const segmentParams: AppPageParams = {};\n const segments = routeSegments ?? [];\n const end = Math.min(Math.max(treePosition, 0), segments.length);\n\n for (let index = 0; index < end; index++) {\n const segment = segments[index];\n const paramName = getAppPageSegmentParamName(segment);\n if (!paramName) {\n continue;\n }\n\n const paramValue = matchedParams[paramName];\n if (paramValue === undefined || isEmptyOptionalCatchAll(segment, paramValue)) {\n continue;\n }\n\n segmentParams[paramName] = paramValue;\n }\n\n return segmentParams;\n}\n"],"mappings":";AAEA,SAAgB,2BAA2B,SAAgC;CACzE,IAAI,QAAQ,WAAW,QAAQ,IAAI,QAAQ,SAAS,KAAK,IAAI,QAAQ,SAAS,GAC5E,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,IAAI,QAAQ,WAAW,OAAO,IAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,GAC1E,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,IACE,QAAQ,WAAW,IAAI,IACvB,QAAQ,SAAS,IAAI,IACrB,CAAC,QAAQ,SAAS,IAAI,IACtB,QAAQ,SAAS,GAEjB,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,OAAO;;AAGT,SAAS,wBAAwB,SAAiB,YAAwC;CACxF,OAAO,QAAQ,WAAW,QAAQ,IAAI,MAAM,QAAQ,WAAW,IAAI,WAAW,WAAW;;AAG3F,SAAgB,4BACd,eACA,cACA,eACe;CACf,MAAM,gBAA+B,EAAE;CACvC,MAAM,WAAW,iBAAiB,EAAE;CACpC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,cAAc,EAAE,EAAE,SAAS,OAAO;CAEhE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,SAAS;EACxC,MAAM,UAAU,SAAS;EACzB,MAAM,YAAY,2BAA2B,QAAQ;EACrD,IAAI,CAAC,WACH;EAGF,MAAM,aAAa,cAAc;EACjC,IAAI,eAAe,KAAA,KAAa,wBAAwB,SAAS,WAAW,EAC1E;EAGF,cAAc,aAAa;;CAG7B,OAAO"}
1
+ {"version":3,"file":"app-page-params.js","names":[],"sources":["../../src/server/app-page-params.ts"],"sourcesContent":["import type { AppPageParams } from \"./app-page-boundary.js\";\n\nexport function getAppPageSegmentParamName(segment: string): string | null {\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\") && segment.length > 7) {\n return segment.slice(5, -2);\n }\n\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\") && segment.length > 5) {\n return segment.slice(4, -1);\n }\n\n if (\n segment.startsWith(\"[\") &&\n segment.endsWith(\"]\") &&\n !segment.includes(\".\") &&\n segment.length > 2\n ) {\n return segment.slice(1, -1);\n }\n\n return null;\n}\n\nfunction isEmptyOptionalCatchAll(segment: string, paramValue: string | string[]): boolean {\n return segment.startsWith(\"[[...\") && Array.isArray(paramValue) && paramValue.length === 0;\n}\n\nexport function resolveAppPageSegmentParamScopeKeys(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n): readonly string[] {\n const paramNames: string[] = [];\n const seen = new Set<string>();\n const segments = routeSegments ?? [];\n const end = Math.min(Math.max(treePosition, 0), segments.length);\n\n for (let index = 0; index < end; index++) {\n const paramName = getAppPageSegmentParamName(segments[index]);\n if (!paramName || seen.has(paramName)) {\n continue;\n }\n\n seen.add(paramName);\n paramNames.push(paramName);\n }\n\n return paramNames;\n}\n\nexport function resolveAppPageSegmentParams(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n matchedParams: AppPageParams,\n): AppPageParams {\n const segmentParams: AppPageParams = {};\n const segments = routeSegments ?? [];\n const end = Math.min(Math.max(treePosition, 0), segments.length);\n\n for (let index = 0; index < end; index++) {\n const segment = segments[index];\n const paramName = getAppPageSegmentParamName(segment);\n if (!paramName) {\n continue;\n }\n\n const paramValue = matchedParams[paramName];\n if (paramValue === undefined || isEmptyOptionalCatchAll(segment, paramValue)) {\n continue;\n }\n\n segmentParams[paramName] = paramValue;\n }\n\n return segmentParams;\n}\n"],"mappings":";AAEA,SAAgB,2BAA2B,SAAgC;CACzE,IAAI,QAAQ,WAAW,QAAQ,IAAI,QAAQ,SAAS,KAAK,IAAI,QAAQ,SAAS,GAC5E,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,IAAI,QAAQ,WAAW,OAAO,IAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,GAC1E,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,IACE,QAAQ,WAAW,IAAI,IACvB,QAAQ,SAAS,IAAI,IACrB,CAAC,QAAQ,SAAS,IAAI,IACtB,QAAQ,SAAS,GAEjB,OAAO,QAAQ,MAAM,GAAG,GAAG;CAG7B,OAAO;;AAGT,SAAS,wBAAwB,SAAiB,YAAwC;CACxF,OAAO,QAAQ,WAAW,QAAQ,IAAI,MAAM,QAAQ,WAAW,IAAI,WAAW,WAAW;;AAG3F,SAAgB,oCACd,eACA,cACmB;CACnB,MAAM,aAAuB,EAAE;CAC/B,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,WAAW,iBAAiB,EAAE;CACpC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,cAAc,EAAE,EAAE,SAAS,OAAO;CAEhE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,SAAS;EACxC,MAAM,YAAY,2BAA2B,SAAS,OAAO;EAC7D,IAAI,CAAC,aAAa,KAAK,IAAI,UAAU,EACnC;EAGF,KAAK,IAAI,UAAU;EACnB,WAAW,KAAK,UAAU;;CAG5B,OAAO;;AAGT,SAAgB,4BACd,eACA,cACA,eACe;CACf,MAAM,gBAA+B,EAAE;CACvC,MAAM,WAAW,iBAAiB,EAAE;CACpC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,cAAc,EAAE,EAAE,SAAS,OAAO;CAEhE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,SAAS;EACxC,MAAM,UAAU,SAAS;EACzB,MAAM,YAAY,2BAA2B,QAAQ;EACrD,IAAI,CAAC,WACH;EAGF,MAAM,aAAa,cAAc;EACjC,IAAI,eAAe,KAAA,KAAa,wBAAwB,SAAS,WAAW,EAC1E;EAGF,cAAc,aAAa;;CAG7B,OAAO"}
@@ -2,6 +2,17 @@ import { LayoutFlags } from "./app-elements-wire.js";
2
2
  import { AppPageSpecialError, LayoutClassificationOptions } from "./app-page-execution.js";
3
3
 
4
4
  //#region src/server/app-page-probe.d.ts
5
+ type ProbeReactServerSubtreeOptions = Readonly<{
6
+ maxDepth?: number;
7
+ maxNodes?: number;
8
+ }>;
9
+ /**
10
+ * Invokes server-component children returned by a layout probe so per-layout
11
+ * skip eligibility observes data dependencies created below the layout's
12
+ * immediate function body. The real RSC render remains authoritative; probe
13
+ * failures only make static-layout skip fall back to render-and-send.
14
+ */
15
+ declare function probeReactServerSubtree(node: unknown, options?: ProbeReactServerSubtreeOptions): Promise<void>;
5
16
  /**
6
17
  * Build a probePage() invocation for the App Router request lifecycle.
7
18
  *
@@ -41,5 +52,5 @@ type ProbeAppPageBeforeRenderOptions = {
41
52
  };
42
53
  declare function probeAppPageBeforeRender(options: ProbeAppPageBeforeRenderOptions): Promise<ProbeAppPageBeforeRenderResult>;
43
54
  //#endregion
44
- export { probeAppPage, probeAppPageBeforeRender };
55
+ export { probeAppPage, probeAppPageBeforeRender, probeReactServerSubtree };
45
56
  //# sourceMappingURL=app-page-probe.d.ts.map
@@ -1,7 +1,122 @@
1
1
  import { makeThenableParams } from "../shims/thenable-params.js";
2
2
  import { probeAppPageComponent, probeAppPageLayouts } from "./app-page-execution.js";
3
3
  import { collectAppPageSearchParams } from "./app-page-head.js";
4
+ import { Fragment, isValidElement } from "react";
4
5
  //#region src/server/app-page-probe.ts
6
+ const DEFAULT_SUBTREE_PROBE_MAX_DEPTH = 32;
7
+ const DEFAULT_SUBTREE_PROBE_MAX_NODES = 1e3;
8
+ const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
9
+ const REACT_LAZY_TYPE = Symbol.for("react.lazy");
10
+ const REACT_MEMO_TYPE = Symbol.for("react.memo");
11
+ var AppPageSubtreeProbeLimitError = class extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "AppPageSubtreeProbeLimitError";
15
+ }
16
+ };
17
+ var AppPageSubtreeProbeUnsupportedIterableError = class extends Error {
18
+ constructor() {
19
+ super("App page layout subtree probe cannot safely inspect iterable children");
20
+ this.name = "AppPageSubtreeProbeUnsupportedIterableError";
21
+ }
22
+ };
23
+ function isPromiseLike(value) {
24
+ return Boolean(value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function");
25
+ }
26
+ function isIterable(value) {
27
+ return Boolean(value && typeof value !== "string" && typeof value === "object" && Symbol.iterator in value && typeof value[Symbol.iterator] === "function");
28
+ }
29
+ function isProbeReactElement(value) {
30
+ return isValidElement(value);
31
+ }
32
+ function isObjectLike(value) {
33
+ return (typeof value === "object" || typeof value === "function") && value !== null;
34
+ }
35
+ function isUnknownFunction(value) {
36
+ return typeof value === "function";
37
+ }
38
+ function readReactMemoType(value) {
39
+ if (!isObjectLike(value) || Reflect.get(value, "$$typeof") !== REACT_MEMO_TYPE) return null;
40
+ return { innerType: Reflect.get(value, "type") };
41
+ }
42
+ function readReactLazyType(value) {
43
+ if (!isObjectLike(value) || Reflect.get(value, "$$typeof") !== REACT_LAZY_TYPE) return null;
44
+ const init = Reflect.get(value, "_init");
45
+ if (!isUnknownFunction(init)) return null;
46
+ return {
47
+ init,
48
+ payload: Reflect.get(value, "_payload")
49
+ };
50
+ }
51
+ function readReactForwardRefRender(value) {
52
+ if (!isObjectLike(value) || Reflect.get(value, "$$typeof") !== REACT_FORWARD_REF_TYPE) return null;
53
+ const render = Reflect.get(value, "render");
54
+ return isUnknownFunction(render) ? render : null;
55
+ }
56
+ async function resolveReactLazyType(lazyType) {
57
+ try {
58
+ return lazyType.init(lazyType.payload);
59
+ } catch (error) {
60
+ if (!isPromiseLike(error)) throw error;
61
+ await error;
62
+ return lazyType.init(lazyType.payload);
63
+ }
64
+ }
65
+ /**
66
+ * Invokes server-component children returned by a layout probe so per-layout
67
+ * skip eligibility observes data dependencies created below the layout's
68
+ * immediate function body. The real RSC render remains authoritative; probe
69
+ * failures only make static-layout skip fall back to render-and-send.
70
+ */
71
+ async function probeReactServerSubtree(node, options = {}) {
72
+ const maxDepth = options.maxDepth ?? DEFAULT_SUBTREE_PROBE_MAX_DEPTH;
73
+ const maxNodes = options.maxNodes ?? DEFAULT_SUBTREE_PROBE_MAX_NODES;
74
+ let visitedNodes = 0;
75
+ const enterProbeNode = (depth) => {
76
+ if (depth > maxDepth) throw new AppPageSubtreeProbeLimitError("App page layout subtree probe exceeded max depth");
77
+ visitedNodes += 1;
78
+ if (visitedNodes > maxNodes) throw new AppPageSubtreeProbeLimitError("App page layout subtree probe exceeded max nodes");
79
+ };
80
+ const renderElementType = async (type, props, depth, wrapperDepth = 0) => {
81
+ if (wrapperDepth > maxDepth) throw new AppPageSubtreeProbeLimitError("App page layout subtree probe exceeded max depth");
82
+ if (isUnknownFunction(type)) {
83
+ await visit(type(props), depth + 1);
84
+ return true;
85
+ }
86
+ const memoType = readReactMemoType(type);
87
+ if (memoType) return renderElementType(memoType.innerType, props, depth, wrapperDepth + 1);
88
+ const lazyType = readReactLazyType(type);
89
+ if (lazyType) return renderElementType(await resolveReactLazyType(lazyType), props, depth, wrapperDepth + 1);
90
+ const forwardRefRender = readReactForwardRefRender(type);
91
+ if (forwardRefRender) {
92
+ await visit(forwardRefRender(props, null), depth + 1);
93
+ return true;
94
+ }
95
+ return false;
96
+ };
97
+ const visit = async (value, depth) => {
98
+ enterProbeNode(depth);
99
+ if (value == null || typeof value === "boolean" || typeof value === "number") return;
100
+ if (typeof value === "string" || typeof value === "bigint") return;
101
+ if (isPromiseLike(value)) {
102
+ await visit(await value, depth);
103
+ return;
104
+ }
105
+ if (Array.isArray(value)) {
106
+ for (const child of value) await visit(child, depth + 1);
107
+ return;
108
+ }
109
+ if (isIterable(value) && !isProbeReactElement(value)) throw new AppPageSubtreeProbeUnsupportedIterableError();
110
+ if (!isProbeReactElement(value)) return;
111
+ if (value.type === Fragment || typeof value.type === "string") {
112
+ await visit(value.props.children, depth + 1);
113
+ return;
114
+ }
115
+ if (await renderElementType(value.type, value.props, depth)) return;
116
+ await visit(value.props.children, depth + 1);
117
+ };
118
+ await visit(node, 0);
119
+ }
5
120
  /**
6
121
  * Build a probePage() invocation for the App Router request lifecycle.
7
122
  *
@@ -71,6 +186,6 @@ async function probeAppPageBeforeRender(options) {
71
186
  };
72
187
  }
73
188
  //#endregion
74
- export { probeAppPage, probeAppPageBeforeRender };
189
+ export { probeAppPage, probeAppPageBeforeRender, probeReactServerSubtree };
75
190
 
76
191
  //# sourceMappingURL=app-page-probe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-probe.js","names":[],"sources":["../../src/server/app-page-probe.ts"],"sourcesContent":["import { makeThenableParams } from \"vinext/shims/thenable-params\";\nimport { collectAppPageSearchParams } from \"./app-page-head.js\";\nimport {\n probeAppPageComponent,\n probeAppPageLayouts,\n type AppPageSpecialError,\n type LayoutClassificationOptions,\n type LayoutFlags,\n} from \"./app-page-execution.js\";\n\n/**\n * Build a probePage() invocation for the App Router request lifecycle.\n *\n * The generated RSC entry calls this once per request after route matching to\n * eagerly invoke the page component. Surfacing redirect()/notFound() throws\n * here lets the probe lifecycle turn them into proper HTTP responses before\n * RSC streaming begins (see `probeAppPageBeforeRender`).\n *\n * The helper exists to keep the generated entry thin (a single delegation\n * call) and to make the search-params wiring directly unit-testable. A bug\n * here previously slipped through because the entry hand-rolled the call and\n * read a non-existent key off `collectAppPageSearchParams`'s return value\n * (see https://github.com/cloudflare/vinext/issues/1235).\n *\n * Returns `null` when the route has no page component (eg. interception-only\n * routes), matching the caller contract on `probePage`.\n */\nexport function probeAppPage(options: {\n pageComponent: unknown;\n asyncRouteParams: unknown;\n searchParams: URLSearchParams | null | undefined;\n}): unknown {\n const { pageComponent, asyncRouteParams, searchParams } = options;\n if (typeof pageComponent !== \"function\") {\n return null;\n }\n const { pageSearchParams } = collectAppPageSearchParams(searchParams);\n const asyncSearchParams = makeThenableParams(pageSearchParams);\n return (pageComponent as (props: Record<string, unknown>) => unknown)({\n params: asyncRouteParams,\n searchParams: asyncSearchParams,\n });\n}\n\ntype ProbeAppPageBeforeRenderResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\ntype ProbeAppPageBeforeRenderOptions = {\n hasLoadingBoundary: boolean;\n layoutCount: number;\n probeLayoutAt: (layoutIndex: number) => unknown;\n probePage: () => unknown;\n renderLayoutSpecialError: (\n specialError: AppPageSpecialError,\n layoutIndex: number,\n ) => Promise<Response>;\n renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;\n resolveSpecialError: (error: unknown) => AppPageSpecialError | null;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\nexport async function probeAppPageBeforeRender(\n options: ProbeAppPageBeforeRenderOptions,\n): Promise<ProbeAppPageBeforeRenderResult> {\n let layoutFlags: LayoutFlags = {};\n\n // Layouts render before their children in Next.js, so layout-level special\n // errors must be handled before probing the page component itself.\n if (options.layoutCount > 0) {\n const layoutProbeResult = await probeAppPageLayouts({\n layoutCount: options.layoutCount,\n async onLayoutError(layoutError, layoutIndex) {\n const specialError = options.resolveSpecialError(layoutError);\n if (!specialError) {\n return null;\n }\n\n return options.renderLayoutSpecialError(specialError, layoutIndex);\n },\n probeLayoutAt: options.probeLayoutAt,\n runWithSuppressedHookWarning(probe) {\n return options.runWithSuppressedHookWarning(probe);\n },\n classification: options.classification,\n });\n\n layoutFlags = layoutProbeResult.layoutFlags;\n\n if (layoutProbeResult.response) {\n return { response: layoutProbeResult.response, layoutFlags };\n }\n }\n\n // When a route-level loading.tsx is present, the page renders inside a\n // route-level Suspense boundary, so a thrown redirect()/notFound() during\n // page render becomes an error inside that boundary. We can't catch it\n // here without serializing on the page promise — which would defeat the\n // streaming benefit of loading.tsx for slow non-redirecting pages.\n //\n // Recovery for the redirect/notFound case happens later in\n // renderAppPageLifecycle: rscErrorTracker captures the digest from React's\n // onError callback, and a short race window after shell-ready lets the\n // lifecycle swap the response to a 307/404 before bytes are flushed.\n // This mirrors Next.js's \"until-first-byte-is-flushed\" swap behavior.\n if (options.hasLoadingBoundary) {\n return { response: null, layoutFlags };\n }\n\n // Server Components are functions, so we can probe the page ahead of stream\n // creation and only turn special throws into immediate responses.\n const pageResponse = await probeAppPageComponent({\n awaitAsyncResult: true,\n async onError(pageError) {\n const specialError = options.resolveSpecialError(pageError);\n if (specialError) {\n return options.renderPageSpecialError(specialError);\n }\n\n // Non-special probe failures (for example use() outside React's render\n // cycle or client references executing on the server) are expected here.\n // The real RSC/SSR render path will surface those properly below.\n return null;\n },\n probePage: options.probePage,\n runWithSuppressedHookWarning(probe) {\n return options.runWithSuppressedHookWarning(probe);\n },\n });\n\n return { response: pageResponse, layoutFlags };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,aAAa,SAIjB;CACV,MAAM,EAAE,eAAe,kBAAkB,iBAAiB;CAC1D,IAAI,OAAO,kBAAkB,YAC3B,OAAO;CAET,MAAM,EAAE,qBAAqB,2BAA2B,aAAa;CAErE,OAAQ,cAA8D;EACpE,QAAQ;EACR,cAHwB,mBAAmB,iBAGZ;EAChC,CAAC;;AAwBJ,eAAsB,yBACpB,SACyC;CACzC,IAAI,cAA2B,EAAE;CAIjC,IAAI,QAAQ,cAAc,GAAG;EAC3B,MAAM,oBAAoB,MAAM,oBAAoB;GAClD,aAAa,QAAQ;GACrB,MAAM,cAAc,aAAa,aAAa;IAC5C,MAAM,eAAe,QAAQ,oBAAoB,YAAY;IAC7D,IAAI,CAAC,cACH,OAAO;IAGT,OAAO,QAAQ,yBAAyB,cAAc,YAAY;;GAEpE,eAAe,QAAQ;GACvB,6BAA6B,OAAO;IAClC,OAAO,QAAQ,6BAA6B,MAAM;;GAEpD,gBAAgB,QAAQ;GACzB,CAAC;EAEF,cAAc,kBAAkB;EAEhC,IAAI,kBAAkB,UACpB,OAAO;GAAE,UAAU,kBAAkB;GAAU;GAAa;;CAehE,IAAI,QAAQ,oBACV,OAAO;EAAE,UAAU;EAAM;EAAa;CAwBxC,OAAO;EAAE,UAAU,MAnBQ,sBAAsB;GAC/C,kBAAkB;GAClB,MAAM,QAAQ,WAAW;IACvB,MAAM,eAAe,QAAQ,oBAAoB,UAAU;IAC3D,IAAI,cACF,OAAO,QAAQ,uBAAuB,aAAa;IAMrD,OAAO;;GAET,WAAW,QAAQ;GACnB,6BAA6B,OAAO;IAClC,OAAO,QAAQ,6BAA6B,MAAM;;GAErD,CAAC;EAE+B;EAAa"}
1
+ {"version":3,"file":"app-page-probe.js","names":[],"sources":["../../src/server/app-page-probe.ts"],"sourcesContent":["import { Fragment, isValidElement, type ReactElement, type ReactNode } from \"react\";\nimport { makeThenableParams } from \"vinext/shims/thenable-params\";\nimport { collectAppPageSearchParams } from \"./app-page-head.js\";\nimport {\n probeAppPageComponent,\n probeAppPageLayouts,\n type AppPageSpecialError,\n type LayoutClassificationOptions,\n type LayoutFlags,\n} from \"./app-page-execution.js\";\n\nconst DEFAULT_SUBTREE_PROBE_MAX_DEPTH = 32;\nconst DEFAULT_SUBTREE_PROBE_MAX_NODES = 1000;\nconst REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\");\nconst REACT_LAZY_TYPE = Symbol.for(\"react.lazy\");\nconst REACT_MEMO_TYPE = Symbol.for(\"react.memo\");\n\ntype ProbeReactServerSubtreeOptions = Readonly<{\n maxDepth?: number;\n maxNodes?: number;\n}>;\n\ntype ProbeReactElementProps = Readonly<{\n children?: ReactNode;\n}>;\n\ntype UnknownFunction = (...args: unknown[]) => unknown;\n\ntype ReactMemoType = Readonly<{\n innerType: unknown;\n}>;\n\ntype ReactLazyType = Readonly<{\n init: UnknownFunction;\n payload: unknown;\n}>;\n\nclass AppPageSubtreeProbeLimitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AppPageSubtreeProbeLimitError\";\n }\n}\n\nclass AppPageSubtreeProbeUnsupportedIterableError extends Error {\n constructor() {\n super(\"App page layout subtree probe cannot safely inspect iterable children\");\n this.name = \"AppPageSubtreeProbeUnsupportedIterableError\";\n }\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return Boolean(\n value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\",\n );\n}\n\nfunction isIterable(value: unknown): value is Iterable<unknown> {\n return Boolean(\n value &&\n typeof value !== \"string\" &&\n typeof value === \"object\" &&\n Symbol.iterator in value &&\n typeof value[Symbol.iterator] === \"function\",\n );\n}\n\nfunction isProbeReactElement(value: unknown): value is ReactElement<ProbeReactElementProps> {\n return isValidElement<ProbeReactElementProps>(value);\n}\n\nfunction isObjectLike(value: unknown): value is object {\n return (typeof value === \"object\" || typeof value === \"function\") && value !== null;\n}\n\nfunction isUnknownFunction(value: unknown): value is UnknownFunction {\n return typeof value === \"function\";\n}\n\nfunction readReactMemoType(value: unknown): ReactMemoType | null {\n if (!isObjectLike(value) || Reflect.get(value, \"$$typeof\") !== REACT_MEMO_TYPE) {\n return null;\n }\n return { innerType: Reflect.get(value, \"type\") };\n}\n\nfunction readReactLazyType(value: unknown): ReactLazyType | null {\n if (!isObjectLike(value) || Reflect.get(value, \"$$typeof\") !== REACT_LAZY_TYPE) {\n return null;\n }\n const init = Reflect.get(value, \"_init\");\n if (!isUnknownFunction(init)) {\n return null;\n }\n return { init, payload: Reflect.get(value, \"_payload\") };\n}\n\nfunction readReactForwardRefRender(value: unknown): UnknownFunction | null {\n if (!isObjectLike(value) || Reflect.get(value, \"$$typeof\") !== REACT_FORWARD_REF_TYPE) {\n return null;\n }\n const render = Reflect.get(value, \"render\");\n return isUnknownFunction(render) ? render : null;\n}\n\nasync function resolveReactLazyType(lazyType: ReactLazyType): Promise<unknown> {\n try {\n return lazyType.init(lazyType.payload);\n } catch (error) {\n if (!isPromiseLike(error)) {\n throw error;\n }\n await error;\n return lazyType.init(lazyType.payload);\n }\n}\n\n/**\n * Invokes server-component children returned by a layout probe so per-layout\n * skip eligibility observes data dependencies created below the layout's\n * immediate function body. The real RSC render remains authoritative; probe\n * failures only make static-layout skip fall back to render-and-send.\n */\nexport async function probeReactServerSubtree(\n node: unknown,\n options: ProbeReactServerSubtreeOptions = {},\n): Promise<void> {\n const maxDepth = options.maxDepth ?? DEFAULT_SUBTREE_PROBE_MAX_DEPTH;\n const maxNodes = options.maxNodes ?? DEFAULT_SUBTREE_PROBE_MAX_NODES;\n let visitedNodes = 0;\n\n const enterProbeNode = (depth: number): void => {\n if (depth > maxDepth) {\n throw new AppPageSubtreeProbeLimitError(\"App page layout subtree probe exceeded max depth\");\n }\n visitedNodes += 1;\n if (visitedNodes > maxNodes) {\n throw new AppPageSubtreeProbeLimitError(\"App page layout subtree probe exceeded max nodes\");\n }\n };\n\n const renderElementType = async (\n type: unknown,\n props: ProbeReactElementProps,\n depth: number,\n wrapperDepth = 0,\n ): Promise<boolean> => {\n if (wrapperDepth > maxDepth) {\n throw new AppPageSubtreeProbeLimitError(\"App page layout subtree probe exceeded max depth\");\n }\n\n if (isUnknownFunction(type)) {\n await visit(type(props), depth + 1);\n return true;\n }\n\n const memoType = readReactMemoType(type);\n if (memoType) {\n return renderElementType(memoType.innerType, props, depth, wrapperDepth + 1);\n }\n\n const lazyType = readReactLazyType(type);\n if (lazyType) {\n return renderElementType(\n await resolveReactLazyType(lazyType),\n props,\n depth,\n wrapperDepth + 1,\n );\n }\n\n const forwardRefRender = readReactForwardRefRender(type);\n if (forwardRefRender) {\n await visit(forwardRefRender(props, null), depth + 1);\n return true;\n }\n\n return false;\n };\n\n const visit = async (value: unknown, depth: number): Promise<void> => {\n enterProbeNode(depth);\n if (value == null || typeof value === \"boolean\" || typeof value === \"number\") return;\n if (typeof value === \"string\" || typeof value === \"bigint\") return;\n if (isPromiseLike(value)) {\n await visit(await value, depth);\n return;\n }\n if (Array.isArray(value)) {\n for (const child of value) {\n await visit(child, depth + 1);\n }\n return;\n }\n if (isIterable(value) && !isProbeReactElement(value)) {\n throw new AppPageSubtreeProbeUnsupportedIterableError();\n }\n if (!isProbeReactElement(value)) return;\n\n if (value.type === Fragment || typeof value.type === \"string\") {\n await visit(value.props.children, depth + 1);\n return;\n }\n\n if (await renderElementType(value.type, value.props, depth)) {\n return;\n }\n\n await visit(value.props.children, depth + 1);\n };\n\n await visit(node, 0);\n}\n\n/**\n * Build a probePage() invocation for the App Router request lifecycle.\n *\n * The generated RSC entry calls this once per request after route matching to\n * eagerly invoke the page component. Surfacing redirect()/notFound() throws\n * here lets the probe lifecycle turn them into proper HTTP responses before\n * RSC streaming begins (see `probeAppPageBeforeRender`).\n *\n * The helper exists to keep the generated entry thin (a single delegation\n * call) and to make the search-params wiring directly unit-testable. A bug\n * here previously slipped through because the entry hand-rolled the call and\n * read a non-existent key off `collectAppPageSearchParams`'s return value\n * (see https://github.com/cloudflare/vinext/issues/1235).\n *\n * Returns `null` when the route has no page component (eg. interception-only\n * routes), matching the caller contract on `probePage`.\n */\nexport function probeAppPage(options: {\n pageComponent: unknown;\n asyncRouteParams: unknown;\n searchParams: URLSearchParams | null | undefined;\n}): unknown {\n const { pageComponent, asyncRouteParams, searchParams } = options;\n if (typeof pageComponent !== \"function\") {\n return null;\n }\n const { pageSearchParams } = collectAppPageSearchParams(searchParams);\n const asyncSearchParams = makeThenableParams(pageSearchParams);\n return (pageComponent as (props: Record<string, unknown>) => unknown)({\n params: asyncRouteParams,\n searchParams: asyncSearchParams,\n });\n}\n\ntype ProbeAppPageBeforeRenderResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\ntype ProbeAppPageBeforeRenderOptions = {\n hasLoadingBoundary: boolean;\n layoutCount: number;\n probeLayoutAt: (layoutIndex: number) => unknown;\n probePage: () => unknown;\n renderLayoutSpecialError: (\n specialError: AppPageSpecialError,\n layoutIndex: number,\n ) => Promise<Response>;\n renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;\n resolveSpecialError: (error: unknown) => AppPageSpecialError | null;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\nexport async function probeAppPageBeforeRender(\n options: ProbeAppPageBeforeRenderOptions,\n): Promise<ProbeAppPageBeforeRenderResult> {\n let layoutFlags: LayoutFlags = {};\n\n // Layouts render before their children in Next.js, so layout-level special\n // errors must be handled before probing the page component itself.\n if (options.layoutCount > 0) {\n const layoutProbeResult = await probeAppPageLayouts({\n layoutCount: options.layoutCount,\n async onLayoutError(layoutError, layoutIndex) {\n const specialError = options.resolveSpecialError(layoutError);\n if (!specialError) {\n return null;\n }\n\n return options.renderLayoutSpecialError(specialError, layoutIndex);\n },\n probeLayoutAt: options.probeLayoutAt,\n runWithSuppressedHookWarning(probe) {\n return options.runWithSuppressedHookWarning(probe);\n },\n classification: options.classification,\n });\n\n layoutFlags = layoutProbeResult.layoutFlags;\n\n if (layoutProbeResult.response) {\n return { response: layoutProbeResult.response, layoutFlags };\n }\n }\n\n // When a route-level loading.tsx is present, the page renders inside a\n // route-level Suspense boundary, so a thrown redirect()/notFound() during\n // page render becomes an error inside that boundary. We can't catch it\n // here without serializing on the page promise — which would defeat the\n // streaming benefit of loading.tsx for slow non-redirecting pages.\n //\n // Recovery for the redirect/notFound case happens later in\n // renderAppPageLifecycle: rscErrorTracker captures the digest from React's\n // onError callback, and a short race window after shell-ready lets the\n // lifecycle swap the response to a 307/404 before bytes are flushed.\n // This mirrors Next.js's \"until-first-byte-is-flushed\" swap behavior.\n if (options.hasLoadingBoundary) {\n return { response: null, layoutFlags };\n }\n\n // Server Components are functions, so we can probe the page ahead of stream\n // creation and only turn special throws into immediate responses.\n const pageResponse = await probeAppPageComponent({\n awaitAsyncResult: true,\n async onError(pageError) {\n const specialError = options.resolveSpecialError(pageError);\n if (specialError) {\n return options.renderPageSpecialError(specialError);\n }\n\n // Non-special probe failures (for example use() outside React's render\n // cycle or client references executing on the server) are expected here.\n // The real RSC/SSR render path will surface those properly below.\n return null;\n },\n probePage: options.probePage,\n runWithSuppressedHookWarning(probe) {\n return options.runWithSuppressedHookWarning(probe);\n },\n });\n\n return { response: pageResponse, layoutFlags };\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { AppElementsInterception } from "./app-elements-wire.js";
2
+ //#region src/server/app-page-render-identity.d.ts
3
+ type AppPageRenderIdentityInput = {
4
+ displayPathname: string;
5
+ interceptionContext?: string | null;
6
+ interceptSourceMatchedUrl?: string | null;
7
+ interceptSlotId?: string | null;
8
+ };
9
+ type AppPageRenderIdentity = {
10
+ displayPathname: string;
11
+ interception: AppElementsInterception | null;
12
+ interceptionContext: string | null;
13
+ matchedRoutePathname: string;
14
+ pageId: string;
15
+ routeId: string;
16
+ targetMatchedPathname: string;
17
+ };
18
+ declare function normalizeAppPageInterceptionProofPathname(pathname: string | null): string | null;
19
+ declare function createAppPageRenderIdentity(input: AppPageRenderIdentityInput): AppPageRenderIdentity;
20
+ //#endregion
21
+ export { AppPageRenderIdentity, createAppPageRenderIdentity, normalizeAppPageInterceptionProofPathname };
22
+ //# sourceMappingURL=app-page-render-identity.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
+ import { isInterceptionMatchedUrlPath, normalizePath } from "./normalize-path.js";
3
+ import { AppElementsWire } from "./app-elements-wire.js";
4
+ import "./app-elements.js";
5
+ //#region src/server/app-page-render-identity.ts
6
+ function normalizeAppPageRenderMatchedPathname(pathname) {
7
+ if (!pathname.startsWith("/")) throw new Error(`[vinext] App Router render pathname must be absolute: ${pathname}`);
8
+ return normalizePath(normalizePathnameForRouteMatch(pathname));
9
+ }
10
+ function normalizeAppPageInterceptionProofPathname(pathname) {
11
+ if (pathname === null || !isInterceptionMatchedUrlPath(pathname)) return null;
12
+ return normalizeAppPageRenderMatchedPathname(pathname);
13
+ }
14
+ function createAppPageRenderIdentity(input) {
15
+ const interceptionContext = input.interceptionContext ?? null;
16
+ const targetMatchedPathname = normalizeAppPageRenderMatchedPathname(input.displayPathname);
17
+ const sourceMatchedPathname = normalizeAppPageInterceptionProofPathname(input.interceptSourceMatchedUrl ?? null);
18
+ const slotId = input.interceptSlotId ?? null;
19
+ const matchedRoutePathname = sourceMatchedPathname ?? targetMatchedPathname;
20
+ const routeId = AppElementsWire.encodeRouteId(matchedRoutePathname, null);
21
+ const pageId = AppElementsWire.encodePageId(matchedRoutePathname, null);
22
+ const interception = sourceMatchedPathname === null || slotId === null ? null : {
23
+ sourceMatchedUrl: sourceMatchedPathname,
24
+ sourceRouteId: AppElementsWire.encodeRouteId(sourceMatchedPathname, null),
25
+ slotId,
26
+ targetMatchedUrl: targetMatchedPathname,
27
+ targetRouteId: AppElementsWire.encodeRouteId(targetMatchedPathname, null)
28
+ };
29
+ return {
30
+ displayPathname: input.displayPathname,
31
+ interception,
32
+ interceptionContext,
33
+ matchedRoutePathname,
34
+ pageId,
35
+ routeId,
36
+ targetMatchedPathname
37
+ };
38
+ }
39
+ //#endregion
40
+ export { createAppPageRenderIdentity, normalizeAppPageInterceptionProofPathname };
41
+
42
+ //# sourceMappingURL=app-page-render-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-page-render-identity.js","names":[],"sources":["../../src/server/app-page-render-identity.ts"],"sourcesContent":["import { normalizePathnameForRouteMatch } from \"../routing/utils.js\";\nimport { AppElementsWire, type AppElementsInterception } from \"./app-elements.js\";\nimport { isInterceptionMatchedUrlPath, normalizePath } from \"./normalize-path.js\";\n\ntype AppPageRenderIdentityInput = {\n displayPathname: string;\n interceptionContext?: string | null;\n interceptSourceMatchedUrl?: string | null;\n interceptSlotId?: string | null;\n};\n\nexport type AppPageRenderIdentity = {\n displayPathname: string;\n interception: AppElementsInterception | null;\n interceptionContext: string | null;\n matchedRoutePathname: string;\n pageId: string;\n routeId: string;\n targetMatchedPathname: string;\n};\n\nfunction normalizeAppPageRenderMatchedPathname(pathname: string): string {\n if (!pathname.startsWith(\"/\")) {\n throw new Error(`[vinext] App Router render pathname must be absolute: ${pathname}`);\n }\n return normalizePath(normalizePathnameForRouteMatch(pathname));\n}\n\nexport function normalizeAppPageInterceptionProofPathname(pathname: string | null): string | null {\n if (pathname === null || !isInterceptionMatchedUrlPath(pathname)) return null;\n return normalizeAppPageRenderMatchedPathname(pathname);\n}\n\nexport function createAppPageRenderIdentity(\n input: AppPageRenderIdentityInput,\n): AppPageRenderIdentity {\n const interceptionContext = input.interceptionContext ?? null;\n const targetMatchedPathname = normalizeAppPageRenderMatchedPathname(input.displayPathname);\n const sourceMatchedPathname = normalizeAppPageInterceptionProofPathname(\n input.interceptSourceMatchedUrl ?? null,\n );\n const slotId = input.interceptSlotId ?? null;\n const matchedRoutePathname = sourceMatchedPathname ?? targetMatchedPathname;\n const routeId = AppElementsWire.encodeRouteId(matchedRoutePathname, null);\n const pageId = AppElementsWire.encodePageId(matchedRoutePathname, null);\n const interception =\n sourceMatchedPathname === null || slotId === null\n ? null\n : {\n sourceMatchedUrl: sourceMatchedPathname,\n sourceRouteId: AppElementsWire.encodeRouteId(sourceMatchedPathname, null),\n slotId,\n targetMatchedUrl: targetMatchedPathname,\n targetRouteId: AppElementsWire.encodeRouteId(targetMatchedPathname, null),\n };\n\n return {\n displayPathname: input.displayPathname,\n interception,\n interceptionContext,\n matchedRoutePathname,\n pageId,\n routeId,\n targetMatchedPathname,\n };\n}\n"],"mappings":";;;;;AAqBA,SAAS,sCAAsC,UAA0B;CACvE,IAAI,CAAC,SAAS,WAAW,IAAI,EAC3B,MAAM,IAAI,MAAM,yDAAyD,WAAW;CAEtF,OAAO,cAAc,+BAA+B,SAAS,CAAC;;AAGhE,SAAgB,0CAA0C,UAAwC;CAChG,IAAI,aAAa,QAAQ,CAAC,6BAA6B,SAAS,EAAE,OAAO;CACzE,OAAO,sCAAsC,SAAS;;AAGxD,SAAgB,4BACd,OACuB;CACvB,MAAM,sBAAsB,MAAM,uBAAuB;CACzD,MAAM,wBAAwB,sCAAsC,MAAM,gBAAgB;CAC1F,MAAM,wBAAwB,0CAC5B,MAAM,6BAA6B,KACpC;CACD,MAAM,SAAS,MAAM,mBAAmB;CACxC,MAAM,uBAAuB,yBAAyB;CACtD,MAAM,UAAU,gBAAgB,cAAc,sBAAsB,KAAK;CACzE,MAAM,SAAS,gBAAgB,aAAa,sBAAsB,KAAK;CACvE,MAAM,eACJ,0BAA0B,QAAQ,WAAW,OACzC,OACA;EACE,kBAAkB;EAClB,eAAe,gBAAgB,cAAc,uBAAuB,KAAK;EACzE;EACA,kBAAkB;EAClB,eAAe,gBAAgB,cAAc,uBAAuB,KAAK;EAC1E;CAEP,OAAO;EACL,iBAAiB,MAAM;EACvB;EACA;EACA;EACA;EACA;EACA;EACD"}
@@ -19,6 +19,12 @@ type AppPageRequestCacheLife = {
19
19
  };
20
20
  type RenderAppPageLifecycleOptions = {
21
21
  basePath?: string;
22
+ /**
23
+ * Allow-list of OpenTelemetry propagation keys to emit as `<meta>` tags in
24
+ * the SSR head. From `experimental.clientTraceMetadata` in `next.config`.
25
+ * Undefined or empty disables emission.
26
+ */
27
+ clientTraceMetadata?: readonly string[];
22
28
  cleanPathname: string;
23
29
  clearRequestContext: () => void;
24
30
  consumeDynamicUsage: () => boolean;
@@ -46,8 +52,9 @@ type RenderAppPageLifecycleOptions = {
46
52
  isRscRequest: boolean;
47
53
  isrDebug?: AppPageDebugLogger;
48
54
  isrHtmlKey: (pathname: string) => string;
49
- isrRscKey: (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode) => string;
55
+ isrRscKey: (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode, interceptionContext?: string | null) => string;
50
56
  isrSet: AppPageCacheSetter;
57
+ interceptionContext?: string | null;
51
58
  layoutCount: number;
52
59
  loadSsrHandler: () => Promise<AppPageSsrHandler>;
53
60
  middlewareContext: AppPageMiddlewareContext;
@@ -1,7 +1,7 @@
1
1
  import { createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion } from "./artifact-compatibility.js";
2
2
  import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
3
- import { runWithFetchDedupe } from "../shims/fetch-cache.js";
4
3
  import "./app-elements.js";
4
+ import { runWithFetchDedupe } from "../shims/fetch-cache.js";
5
5
  import { buildAppPageHtmlResponse, buildAppPageRscResponse, resolveAppPageHtmlResponsePolicy, resolveAppPageRscResponsePolicy } from "./app-page-response.js";
6
6
  import { buildAppPageFontLinkHeader, readAppPageBinaryStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
7
7
  import { createAppPageFontData, createAppPageRscErrorTracker, deferUntilStreamConsumed, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery, shouldRerenderAppPageWithGlobalError } from "./app-page-stream.js";
@@ -227,6 +227,7 @@ async function renderAppPageLifecycle(options) {
227
227
  isrDebug: options.isrDebug,
228
228
  isrRscKey: options.isrRscKey,
229
229
  isrSet: options.isrSet,
230
+ interceptionContext: options.interceptionContext,
230
231
  mountedSlotsHeader: options.mountedSlotsHeader,
231
232
  renderMode: options.renderMode,
232
233
  preserveClientResponseHeaders: rscResponsePolicy.cacheState !== "MISS",
@@ -258,6 +259,7 @@ async function renderAppPageLifecycle(options) {
258
259
  fontData,
259
260
  navigationContext: options.getNavigationContext(),
260
261
  basePath: options.basePath,
262
+ clientTraceMetadata: options.clientTraceMetadata,
261
263
  rootParams: options.rootParams,
262
264
  formState: options.formState ?? null,
263
265
  rscStream: rscForResponse,
@@ -379,6 +381,7 @@ async function renderAppPageLifecycle(options) {
379
381
  isrHtmlKey: options.isrHtmlKey,
380
382
  isrRscKey: options.isrRscKey,
381
383
  isrSet: options.isrSet,
384
+ interceptionContext: options.interceptionContext,
382
385
  preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
383
386
  expireSeconds,
384
387
  revalidateSeconds,