vinext 0.0.46 → 0.0.48

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 (351) hide show
  1. package/README.md +8 -6
  2. package/dist/build/layout-classification.js +3 -1
  3. package/dist/build/layout-classification.js.map +1 -1
  4. package/dist/build/prerender.d.ts +2 -1
  5. package/dist/build/prerender.js +80 -24
  6. package/dist/build/prerender.js.map +1 -1
  7. package/dist/build/report.d.ts +9 -5
  8. package/dist/build/report.js +17 -7
  9. package/dist/build/report.js.map +1 -1
  10. package/dist/build/route-classification-injector.d.ts +35 -0
  11. package/dist/build/route-classification-injector.js +61 -0
  12. package/dist/build/route-classification-injector.js.map +1 -0
  13. package/dist/build/route-classification-manifest.d.ts +1 -1
  14. package/dist/build/run-prerender.d.ts +5 -0
  15. package/dist/build/run-prerender.js +4 -1
  16. package/dist/build/run-prerender.js.map +1 -1
  17. package/dist/build/server-manifest.js +2 -7
  18. package/dist/build/server-manifest.js.map +1 -1
  19. package/dist/build/standalone.js +3 -5
  20. package/dist/build/standalone.js.map +1 -1
  21. package/dist/build/static-export.d.ts +1 -1
  22. package/dist/check.js +45 -29
  23. package/dist/check.js.map +1 -1
  24. package/dist/cli-args.d.ts +33 -0
  25. package/dist/cli-args.js +121 -0
  26. package/dist/cli-args.js.map +1 -0
  27. package/dist/cli.js +11 -20
  28. package/dist/cli.js.map +1 -1
  29. package/dist/cloudflare/kv-cache-handler.js +29 -9
  30. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  31. package/dist/config/config-matchers.js +46 -37
  32. package/dist/config/config-matchers.js.map +1 -1
  33. package/dist/config/next-config.d.ts +4 -2
  34. package/dist/config/next-config.js +3 -0
  35. package/dist/config/next-config.js.map +1 -1
  36. package/dist/deploy.d.ts +18 -2
  37. package/dist/deploy.js +47 -4
  38. package/dist/deploy.js.map +1 -1
  39. package/dist/entries/app-rsc-entry.d.ts +4 -3
  40. package/dist/entries/app-rsc-entry.js +379 -858
  41. package/dist/entries/app-rsc-entry.js.map +1 -1
  42. package/dist/entries/app-rsc-manifest.d.ts +1 -1
  43. package/dist/entries/app-rsc-manifest.js +6 -1
  44. package/dist/entries/app-rsc-manifest.js.map +1 -1
  45. package/dist/entries/pages-client-entry.js +3 -2
  46. package/dist/entries/pages-client-entry.js.map +1 -1
  47. package/dist/entries/pages-server-entry.js +19 -61
  48. package/dist/entries/pages-server-entry.js.map +1 -1
  49. package/dist/entries/runtime-entry-module.d.ts +12 -3
  50. package/dist/entries/runtime-entry-module.js +15 -4
  51. package/dist/entries/runtime-entry-module.js.map +1 -1
  52. package/dist/index.js +40 -58
  53. package/dist/index.js.map +1 -1
  54. package/dist/plugins/fonts.js +54 -32
  55. package/dist/plugins/fonts.js.map +1 -1
  56. package/dist/plugins/og-assets.js +15 -16
  57. package/dist/plugins/og-assets.js.map +1 -1
  58. package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
  59. package/dist/plugins/rsc-client-shim-excludes.js +11 -1
  60. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  61. package/dist/routing/app-route-graph.d.ts +195 -0
  62. package/dist/routing/app-route-graph.js +1022 -0
  63. package/dist/routing/app-route-graph.js.map +1 -0
  64. package/dist/routing/app-router.d.ts +14 -88
  65. package/dist/routing/app-router.js +21 -712
  66. package/dist/routing/app-router.js.map +1 -1
  67. package/dist/routing/file-matcher.d.ts +3 -1
  68. package/dist/routing/file-matcher.js +6 -1
  69. package/dist/routing/file-matcher.js.map +1 -1
  70. package/dist/routing/pages-router.js +10 -19
  71. package/dist/routing/pages-router.js.map +1 -1
  72. package/dist/routing/route-matching.d.ts +28 -0
  73. package/dist/routing/route-matching.js +44 -0
  74. package/dist/routing/route-matching.js.map +1 -0
  75. package/dist/routing/route-pattern.js +4 -1
  76. package/dist/routing/route-pattern.js.map +1 -1
  77. package/dist/routing/route-trie.d.ts +8 -0
  78. package/dist/routing/route-trie.js +12 -1
  79. package/dist/routing/route-trie.js.map +1 -1
  80. package/dist/routing/route-validation.js +3 -4
  81. package/dist/routing/route-validation.js.map +1 -1
  82. package/dist/routing/utils.d.ts +8 -1
  83. package/dist/routing/utils.js +25 -2
  84. package/dist/routing/utils.js.map +1 -1
  85. package/dist/server/app-browser-entry.js +145 -294
  86. package/dist/server/app-browser-entry.js.map +1 -1
  87. package/dist/server/app-browser-error.d.ts +3 -4
  88. package/dist/server/app-browser-error.js +8 -4
  89. package/dist/server/app-browser-error.js.map +1 -1
  90. package/dist/server/app-browser-navigation-controller.d.ts +75 -0
  91. package/dist/server/app-browser-navigation-controller.js +290 -0
  92. package/dist/server/app-browser-navigation-controller.js.map +1 -0
  93. package/dist/server/app-browser-state.d.ts +33 -15
  94. package/dist/server/app-browser-state.js +52 -59
  95. package/dist/server/app-browser-state.js.map +1 -1
  96. package/dist/server/app-browser-visible-commit.d.ts +68 -0
  97. package/dist/server/app-browser-visible-commit.js +182 -0
  98. package/dist/server/app-browser-visible-commit.js.map +1 -0
  99. package/dist/server/app-client-reference-preloader.d.ts +15 -0
  100. package/dist/server/app-client-reference-preloader.js +46 -0
  101. package/dist/server/app-client-reference-preloader.js.map +1 -0
  102. package/dist/server/app-elements-wire.d.ts +130 -0
  103. package/dist/server/app-elements-wire.js +205 -0
  104. package/dist/server/app-elements-wire.js.map +1 -0
  105. package/dist/server/app-elements.d.ts +2 -84
  106. package/dist/server/app-elements.js +4 -107
  107. package/dist/server/app-elements.js.map +1 -1
  108. package/dist/server/app-fallback-renderer.d.ts +57 -0
  109. package/dist/server/app-fallback-renderer.js +79 -0
  110. package/dist/server/app-fallback-renderer.js.map +1 -0
  111. package/dist/server/app-hook-warning-suppression.d.ts +7 -0
  112. package/dist/server/app-hook-warning-suppression.js +12 -0
  113. package/dist/server/app-hook-warning-suppression.js.map +1 -0
  114. package/dist/server/app-middleware.d.ts +2 -1
  115. package/dist/server/app-middleware.js +34 -11
  116. package/dist/server/app-middleware.js.map +1 -1
  117. package/dist/server/app-mounted-slots-header.d.ts +17 -0
  118. package/dist/server/app-mounted-slots-header.js +21 -0
  119. package/dist/server/app-mounted-slots-header.js.map +1 -0
  120. package/dist/server/app-page-boundary-render.d.ts +3 -3
  121. package/dist/server/app-page-boundary-render.js +8 -5
  122. package/dist/server/app-page-boundary-render.js.map +1 -1
  123. package/dist/server/app-page-boundary.js +2 -1
  124. package/dist/server/app-page-boundary.js.map +1 -1
  125. package/dist/server/app-page-cache.d.ts +19 -4
  126. package/dist/server/app-page-cache.js +60 -22
  127. package/dist/server/app-page-cache.js.map +1 -1
  128. package/dist/server/app-page-dispatch.d.ts +9 -5
  129. package/dist/server/app-page-dispatch.js +41 -17
  130. package/dist/server/app-page-dispatch.js.map +1 -1
  131. package/dist/server/app-page-element-builder.d.ts +61 -0
  132. package/dist/server/app-page-element-builder.js +142 -0
  133. package/dist/server/app-page-element-builder.js.map +1 -0
  134. package/dist/server/app-page-execution.d.ts +23 -5
  135. package/dist/server/app-page-execution.js +39 -24
  136. package/dist/server/app-page-execution.js.map +1 -1
  137. package/dist/server/app-page-head.js +2 -1
  138. package/dist/server/app-page-head.js.map +1 -1
  139. package/dist/server/app-page-method.js +2 -5
  140. package/dist/server/app-page-method.js.map +1 -1
  141. package/dist/server/app-page-params.d.ts +2 -1
  142. package/dist/server/app-page-params.js +3 -3
  143. package/dist/server/app-page-params.js.map +1 -1
  144. package/dist/server/app-page-probe.d.ts +1 -1
  145. package/dist/server/app-page-probe.js +5 -1
  146. package/dist/server/app-page-probe.js.map +1 -1
  147. package/dist/server/app-page-render.d.ts +6 -2
  148. package/dist/server/app-page-render.js +118 -30
  149. package/dist/server/app-page-render.js.map +1 -1
  150. package/dist/server/app-page-request.d.ts +19 -5
  151. package/dist/server/app-page-request.js +49 -7
  152. package/dist/server/app-page-request.js.map +1 -1
  153. package/dist/server/app-page-response.d.ts +1 -0
  154. package/dist/server/app-page-response.js +6 -9
  155. package/dist/server/app-page-response.js.map +1 -1
  156. package/dist/server/app-page-route-wiring.d.ts +20 -4
  157. package/dist/server/app-page-route-wiring.js +15 -12
  158. package/dist/server/app-page-route-wiring.js.map +1 -1
  159. package/dist/server/app-page-stream.d.ts +7 -0
  160. package/dist/server/app-page-stream.js +9 -2
  161. package/dist/server/app-page-stream.js.map +1 -1
  162. package/dist/server/app-post-middleware-context.d.ts +16 -0
  163. package/dist/server/app-post-middleware-context.js +28 -0
  164. package/dist/server/app-post-middleware-context.js.map +1 -0
  165. package/dist/server/app-prerender-endpoints.js +3 -2
  166. package/dist/server/app-prerender-endpoints.js.map +1 -1
  167. package/dist/server/app-request-context.d.ts +22 -0
  168. package/dist/server/app-request-context.js +30 -0
  169. package/dist/server/app-request-context.js.map +1 -0
  170. package/dist/server/app-route-handler-cache.d.ts +1 -0
  171. package/dist/server/app-route-handler-cache.js +7 -2
  172. package/dist/server/app-route-handler-cache.js.map +1 -1
  173. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  174. package/dist/server/app-route-handler-dispatch.js +8 -5
  175. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  176. package/dist/server/app-route-handler-execution.d.ts +2 -1
  177. package/dist/server/app-route-handler-execution.js +2 -2
  178. package/dist/server/app-route-handler-execution.js.map +1 -1
  179. package/dist/server/app-route-handler-policy.js +13 -13
  180. package/dist/server/app-route-handler-policy.js.map +1 -1
  181. package/dist/server/app-route-handler-response.d.ts +4 -2
  182. package/dist/server/app-route-handler-response.js +9 -7
  183. package/dist/server/app-route-handler-response.js.map +1 -1
  184. package/dist/server/app-route-handler-runtime.d.ts +9 -1
  185. package/dist/server/app-route-handler-runtime.js +11 -1
  186. package/dist/server/app-route-handler-runtime.js.map +1 -1
  187. package/dist/server/app-router-entry.js +9 -4
  188. package/dist/server/app-router-entry.js.map +1 -1
  189. package/dist/server/app-rsc-cache-busting.d.ts +34 -0
  190. package/dist/server/app-rsc-cache-busting.js +137 -0
  191. package/dist/server/app-rsc-cache-busting.js.map +1 -0
  192. package/dist/server/app-rsc-error-handler.d.ts +21 -0
  193. package/dist/server/app-rsc-error-handler.js +30 -0
  194. package/dist/server/app-rsc-error-handler.js.map +1 -0
  195. package/dist/server/app-rsc-handler.d.ts +117 -0
  196. package/dist/server/app-rsc-handler.js +271 -0
  197. package/dist/server/app-rsc-handler.js.map +1 -0
  198. package/dist/server/app-rsc-request-normalization.d.ts +42 -0
  199. package/dist/server/app-rsc-request-normalization.js +67 -0
  200. package/dist/server/app-rsc-request-normalization.js.map +1 -0
  201. package/dist/server/app-rsc-response-finalizer.d.ts +30 -0
  202. package/dist/server/app-rsc-response-finalizer.js +38 -0
  203. package/dist/server/app-rsc-response-finalizer.js.map +1 -0
  204. package/dist/server/app-rsc-route-matching.js +8 -4
  205. package/dist/server/app-rsc-route-matching.js.map +1 -1
  206. package/dist/server/app-segment-config.d.ts +33 -0
  207. package/dist/server/app-segment-config.js +90 -0
  208. package/dist/server/app-segment-config.js.map +1 -0
  209. package/dist/server/app-server-action-execution.d.ts +2 -0
  210. package/dist/server/app-server-action-execution.js +45 -51
  211. package/dist/server/app-server-action-execution.js.map +1 -1
  212. package/dist/server/app-ssr-entry.js +21 -20
  213. package/dist/server/app-ssr-entry.js.map +1 -1
  214. package/dist/server/artifact-compatibility.d.ts +44 -0
  215. package/dist/server/artifact-compatibility.js +82 -0
  216. package/dist/server/artifact-compatibility.js.map +1 -0
  217. package/dist/server/cache-control.d.ts +24 -0
  218. package/dist/server/cache-control.js +33 -0
  219. package/dist/server/cache-control.js.map +1 -0
  220. package/dist/server/cache-proof.d.ts +200 -0
  221. package/dist/server/cache-proof.js +342 -0
  222. package/dist/server/cache-proof.js.map +1 -0
  223. package/dist/server/dev-error-overlay-store.d.ts +23 -0
  224. package/dist/server/dev-error-overlay-store.js +67 -0
  225. package/dist/server/dev-error-overlay-store.js.map +1 -0
  226. package/dist/server/dev-error-overlay.d.ts +15 -0
  227. package/dist/server/dev-error-overlay.js +548 -0
  228. package/dist/server/dev-error-overlay.js.map +1 -0
  229. package/dist/server/dev-origin-check.js +8 -4
  230. package/dist/server/dev-origin-check.js.map +1 -1
  231. package/dist/server/dev-server.js +1 -6
  232. package/dist/server/dev-server.js.map +1 -1
  233. package/dist/server/http-error-responses.d.ts +67 -0
  234. package/dist/server/http-error-responses.js +77 -0
  235. package/dist/server/http-error-responses.js.map +1 -0
  236. package/dist/server/image-optimization.js +2 -1
  237. package/dist/server/image-optimization.js.map +1 -1
  238. package/dist/server/instrumentation-runtime.d.ts +44 -0
  239. package/dist/server/instrumentation-runtime.js +29 -0
  240. package/dist/server/instrumentation-runtime.js.map +1 -0
  241. package/dist/server/isr-cache.d.ts +2 -7
  242. package/dist/server/isr-cache.js +7 -10
  243. package/dist/server/isr-cache.js.map +1 -1
  244. package/dist/server/metadata-route-response.js +6 -5
  245. package/dist/server/metadata-route-response.js.map +1 -1
  246. package/dist/server/metadata-routes.d.ts +1 -0
  247. package/dist/server/metadata-routes.js +6 -0
  248. package/dist/server/metadata-routes.js.map +1 -1
  249. package/dist/server/middleware-matcher.js +2 -2
  250. package/dist/server/middleware-matcher.js.map +1 -1
  251. package/dist/server/middleware-response-headers.js +21 -0
  252. package/dist/server/middleware-response-headers.js.map +1 -1
  253. package/dist/server/middleware-runtime.js +3 -3
  254. package/dist/server/middleware-runtime.js.map +1 -1
  255. package/dist/server/navigation-trace.d.ts +33 -0
  256. package/dist/server/navigation-trace.js +35 -0
  257. package/dist/server/navigation-trace.js.map +1 -0
  258. package/dist/server/next-error-digest.d.ts +44 -0
  259. package/dist/server/next-error-digest.js +40 -0
  260. package/dist/server/next-error-digest.js.map +1 -0
  261. package/dist/server/pages-api-route.js +2 -1
  262. package/dist/server/pages-api-route.js.map +1 -1
  263. package/dist/server/pages-node-compat.js +4 -16
  264. package/dist/server/pages-node-compat.js.map +1 -1
  265. package/dist/server/pages-page-data.d.ts +2 -1
  266. package/dist/server/pages-page-data.js +6 -5
  267. package/dist/server/pages-page-data.js.map +1 -1
  268. package/dist/server/pages-page-response.d.ts +3 -8
  269. package/dist/server/pages-page-response.js +46 -15
  270. package/dist/server/pages-page-response.js.map +1 -1
  271. package/dist/server/prod-server.d.ts +6 -0
  272. package/dist/server/prod-server.js +28 -21
  273. package/dist/server/prod-server.js.map +1 -1
  274. package/dist/server/request-pipeline.d.ts +42 -1
  275. package/dist/server/request-pipeline.js +97 -17
  276. package/dist/server/request-pipeline.js.map +1 -1
  277. package/dist/server/rsc-stream-hints.d.ts +3 -1
  278. package/dist/server/rsc-stream-hints.js +4 -1
  279. package/dist/server/rsc-stream-hints.js.map +1 -1
  280. package/dist/server/seed-cache.js +19 -8
  281. package/dist/server/seed-cache.js.map +1 -1
  282. package/dist/shims/cache-runtime.d.ts +2 -2
  283. package/dist/shims/cache-runtime.js +31 -17
  284. package/dist/shims/cache-runtime.js.map +1 -1
  285. package/dist/shims/cache.d.ts +15 -3
  286. package/dist/shims/cache.js +45 -20
  287. package/dist/shims/cache.js.map +1 -1
  288. package/dist/shims/error-boundary.d.ts +17 -1
  289. package/dist/shims/error-boundary.js +31 -1
  290. package/dist/shims/error-boundary.js.map +1 -1
  291. package/dist/shims/fetch-cache.d.ts +4 -1
  292. package/dist/shims/fetch-cache.js +57 -16
  293. package/dist/shims/fetch-cache.js.map +1 -1
  294. package/dist/shims/head-state.js +2 -3
  295. package/dist/shims/head-state.js.map +1 -1
  296. package/dist/shims/headers.js +4 -44
  297. package/dist/shims/headers.js.map +1 -1
  298. package/dist/shims/i18n-state.js +2 -3
  299. package/dist/shims/i18n-state.js.map +1 -1
  300. package/dist/shims/image.js +93 -5
  301. package/dist/shims/image.js.map +1 -1
  302. package/dist/shims/internal/als-registry.d.ts +15 -0
  303. package/dist/shims/internal/als-registry.js +55 -0
  304. package/dist/shims/internal/als-registry.js.map +1 -0
  305. package/dist/shims/internal/cookie-serialize.d.ts +46 -0
  306. package/dist/shims/internal/cookie-serialize.js +51 -0
  307. package/dist/shims/internal/cookie-serialize.js.map +1 -0
  308. package/dist/shims/link.js +31 -26
  309. package/dist/shims/link.js.map +1 -1
  310. package/dist/shims/metadata.d.ts +26 -1
  311. package/dist/shims/metadata.js +94 -4
  312. package/dist/shims/metadata.js.map +1 -1
  313. package/dist/shims/navigation-state.js +2 -3
  314. package/dist/shims/navigation-state.js.map +1 -1
  315. package/dist/shims/navigation.d.ts +2 -7
  316. package/dist/shims/navigation.js +44 -36
  317. package/dist/shims/navigation.js.map +1 -1
  318. package/dist/shims/request-context.js +2 -4
  319. package/dist/shims/request-context.js.map +1 -1
  320. package/dist/shims/request-state-types.d.ts +1 -1
  321. package/dist/shims/router-state.js +2 -3
  322. package/dist/shims/router-state.js.map +1 -1
  323. package/dist/shims/router.js +2 -2
  324. package/dist/shims/router.js.map +1 -1
  325. package/dist/shims/server.js +5 -30
  326. package/dist/shims/server.js.map +1 -1
  327. package/dist/shims/slot.d.ts +1 -1
  328. package/dist/shims/slot.js +5 -4
  329. package/dist/shims/slot.js.map +1 -1
  330. package/dist/shims/thenable-params.d.ts +5 -2
  331. package/dist/shims/thenable-params.js +26 -6
  332. package/dist/shims/thenable-params.js.map +1 -1
  333. package/dist/shims/unified-request-context.d.ts +1 -1
  334. package/dist/shims/unified-request-context.js +3 -14
  335. package/dist/shims/unified-request-context.js.map +1 -1
  336. package/dist/shims/use-merged-ref.d.ts +7 -0
  337. package/dist/shims/use-merged-ref.js +40 -0
  338. package/dist/shims/use-merged-ref.js.map +1 -0
  339. package/dist/utils/base-path.d.ts +7 -1
  340. package/dist/utils/base-path.js +12 -1
  341. package/dist/utils/base-path.js.map +1 -1
  342. package/dist/utils/cache-control-metadata.d.ts +6 -0
  343. package/dist/utils/cache-control-metadata.js +16 -0
  344. package/dist/utils/cache-control-metadata.js.map +1 -0
  345. package/dist/utils/safe-json-file.d.ts +18 -0
  346. package/dist/utils/safe-json-file.js +25 -0
  347. package/dist/utils/safe-json-file.js.map +1 -0
  348. package/dist/utils/text-stream.d.ts +29 -0
  349. package/dist/utils/text-stream.js +66 -0
  350. package/dist/utils/text-stream.js.map +1 -0
  351. package/package.json +5 -5
@@ -0,0 +1,61 @@
1
+ import { MetadataFileRoute } from "./metadata-routes.js";
2
+ import { AppElements } from "./app-elements-wire.js";
3
+ import { AppPageParams } from "./app-page-boundary.js";
4
+ import { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute } from "./app-page-route-wiring.js";
5
+
6
+ //#region src/server/app-page-element-builder.d.ts
7
+ /**
8
+ * Route shape passed from the generated entry. Extends the wiring route with
9
+ * the page module reference (used to extract the default export for the page
10
+ * element) and the URL pattern (used as the route path in head resolution).
11
+ */
12
+ type AppPageBuildRoute<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = AppPageRouteWiringRoute<TModule, TErrorModule> & {
13
+ page?: TModule | null;
14
+ pattern: string; /** Param names captured by the route's URL pattern, in order. */
15
+ params?: readonly string[] | null;
16
+ };
17
+ type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {
18
+ interceptionContext?: string | null;
19
+ interceptLayouts?: readonly (TModule | null | undefined)[] | null;
20
+ interceptPage?: TModule | null;
21
+ interceptParams?: AppPageParams | null;
22
+ interceptSlotKey?: string | null;
23
+ };
24
+ type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> = {
25
+ /** Interception context from current-route navigation (null for direct visits). */opts?: AppPageInterceptOptions<TModule> | null; /** URL search params from the incoming request (null when unavailable). */
26
+ searchParams?: URLSearchParams | null; /** Whether the incoming request is an RSC (client-side navigation) request. */
27
+ isRscRequest: boolean; /** The incoming HTTP request (available but unused by this module). */
28
+ request: Request; /** Normalized x-vinext-mounted-slots header value. */
29
+ mountedSlotsHeader: string | null;
30
+ };
31
+ type BuildPageElementsOptions<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = {
32
+ route: AppPageBuildRoute<TModule, TErrorModule>;
33
+ params: AppPageParams;
34
+ routePath: string;
35
+ pageRequest: AppPagePageRequest<TModule>; /** Root-level global-error.tsx module. Present when the app defines this file. */
36
+ globalErrorModule?: TErrorModule | null; /** Root-level not-found.tsx module. Present when the app defines this file. */
37
+ rootNotFoundModule?: TModule | null; /** Root-level forbidden.tsx module. Present when the app defines this file. */
38
+ rootForbiddenModule?: TModule | null; /** Root-level unauthorized.tsx module. Present when the app defines this file. */
39
+ rootUnauthorizedModule?: TModule | null; /** File-based metadata routes (favicon, manifest, sitemap, etc.). */
40
+ metadataRoutes: readonly MetadataFileRoute[];
41
+ };
42
+ /**
43
+ * Build the App Router element tree for a matched route.
44
+ *
45
+ * This is the central element-construction path for the App Router RSC
46
+ * handler. It resolves page head metadata (including parallel route metadata),
47
+ * creates the page React element, and wires it into the nested layout +
48
+ * boundary tree via {@link buildAppPageElements}.
49
+ *
50
+ * The function is extracted from the generated RSC entry template so it can
51
+ * be unit-tested independently of the code-generation machinery.
52
+ *
53
+ * Next.js equivalent: the component tree construction in
54
+ * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx|create-component-tree.tsx}
55
+ * and the page head resolution in
56
+ * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-metadata.tsx|create-metadata.tsx}.
57
+ */
58
+ declare function buildPageElements<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule>(options: BuildPageElementsOptions<TModule, TErrorModule>): Promise<AppElements>;
59
+ //#endregion
60
+ export { AppPageBuildRoute, type AppPageErrorModule, AppPageInterceptOptions, AppPagePageRequest, type AppPageRouteWiringRoute, BuildPageElementsOptions, buildPageElements };
61
+ //# sourceMappingURL=app-page-element-builder.d.ts.map
@@ -0,0 +1,142 @@
1
+ import { markDynamicUsage } from "../shims/headers.js";
2
+ import { AppElementsWire } from "./app-elements-wire.js";
3
+ import "./app-elements.js";
4
+ import { matchRoutePattern } from "../routing/route-pattern.js";
5
+ import { makeThenableParams } from "../shims/thenable-params.js";
6
+ import { buildAppPageElements, createAppPageTreePath } from "./app-page-route-wiring.js";
7
+ import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
8
+ import { createElement } from "react";
9
+ //#region src/server/app-page-element-builder.ts
10
+ /**
11
+ * Build the App Router element tree for a matched route.
12
+ *
13
+ * This is the central element-construction path for the App Router RSC
14
+ * handler. It resolves page head metadata (including parallel route metadata),
15
+ * creates the page React element, and wires it into the nested layout +
16
+ * boundary tree via {@link buildAppPageElements}.
17
+ *
18
+ * The function is extracted from the generated RSC entry template so it can
19
+ * be unit-tested independently of the code-generation machinery.
20
+ *
21
+ * Next.js equivalent: the component tree construction in
22
+ * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx|create-component-tree.tsx}
23
+ * and the page head resolution in
24
+ * {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-metadata.tsx|create-metadata.tsx}.
25
+ */
26
+ async function buildPageElements(options) {
27
+ const { route, params, routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
28
+ const { opts, searchParams, isRscRequest, mountedSlotsHeader } = pageRequest;
29
+ const pageModule = route.page;
30
+ const PageComponent = pageModule?.default;
31
+ if (!!pageModule && !PageComponent) {
32
+ const interceptionContext = opts?.interceptionContext ?? null;
33
+ const noExportRouteId = AppElementsWire.encodeRouteId(routePath, interceptionContext);
34
+ let noExportRootLayout = null;
35
+ if (route.layouts?.length > 0) {
36
+ const treePosition = route.layoutTreePositions?.[0] ?? 0;
37
+ noExportRootLayout = createAppPageTreePath(route.routeSegments, treePosition);
38
+ }
39
+ return {
40
+ ...AppElementsWire.createMetadataEntries({
41
+ interceptionContext,
42
+ rootLayoutTreePath: noExportRootLayout,
43
+ routeId: noExportRouteId
44
+ }),
45
+ [noExportRouteId]: createElement("div", null, "Page has no default export")
46
+ };
47
+ }
48
+ const { hasSearchParams, metadata: resolvedMetadata, pageSearchParams, viewport: resolvedViewport } = await resolveAppPageHead({
49
+ layoutModules: route.layouts,
50
+ layoutTreePositions: route.layoutTreePositions,
51
+ metadataRoutes,
52
+ pageModule: route.page ?? null,
53
+ parallelRoutes: resolveActiveParallelRouteHeadInputs({
54
+ interceptLayouts: opts?.interceptLayouts ?? null,
55
+ interceptPage: opts?.interceptPage ?? null,
56
+ interceptParams: opts?.interceptParams ?? null,
57
+ interceptSlotKey: opts?.interceptSlotKey ?? null,
58
+ params,
59
+ routeSegments: route.routeSegments ?? [],
60
+ slots: route.slots ?? null
61
+ }),
62
+ params,
63
+ routePath: route.pattern,
64
+ routeSegments: route.routeSegments ?? null,
65
+ searchParams
66
+ });
67
+ const pageProps = { params: makeThenableParams(params) };
68
+ if (searchParams) {
69
+ pageProps.searchParams = makeThenableParams(pageSearchParams);
70
+ if (hasSearchParams) markDynamicUsage();
71
+ }
72
+ const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
73
+ const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
74
+ return buildAppPageElements({
75
+ element: PageComponent ? createElement(PageComponent, pageProps) : null,
76
+ globalErrorModule: globalErrorModule ?? null,
77
+ isRscRequest,
78
+ mountedSlotIds,
79
+ makeThenableParams,
80
+ matchedParams: params,
81
+ resolvedMetadata,
82
+ resolvedViewport,
83
+ interceptionContext: opts?.interceptionContext ?? null,
84
+ routePath,
85
+ rootNotFoundModule: rootNotFoundModule ?? null,
86
+ rootForbiddenModule: rootForbiddenModule ?? null,
87
+ rootUnauthorizedModule: rootUnauthorizedModule ?? null,
88
+ route,
89
+ slotOverrides
90
+ });
91
+ }
92
+ /**
93
+ * Build the per-request `slotOverrides` map. Combines:
94
+ * - Interception overrides (existing behavior — swap in the intercepting page
95
+ * and its layouts when the request is intercepted into this slot).
96
+ * - Slot-specific param extraction for inherited slots whose URL pattern
97
+ * has different param names than the route's. The runtime matches the
98
+ * cleaned request path against `slot.slotPatternParts` to produce
99
+ * slot-scoped params, which `app-page-route-wiring` then hands to the
100
+ * slot page instead of the route's matched params.
101
+ *
102
+ * `routePath` is the already-normalized request pathname (basePath stripped,
103
+ * RSC suffix removed). Re-parsing `request.url` here would re-introduce the
104
+ * basePath and silently break the match for any app that configures one.
105
+ */
106
+ function buildSlotOverrides(route, routeParams, routePath, opts) {
107
+ const overrides = {};
108
+ if (opts && opts.interceptSlotKey && opts.interceptPage) overrides[opts.interceptSlotKey] = {
109
+ layoutModules: opts.interceptLayouts || null,
110
+ pageModule: opts.interceptPage,
111
+ params: opts.interceptParams || routeParams
112
+ };
113
+ const slots = route.slots;
114
+ if (slots) {
115
+ let urlParts = null;
116
+ const routeParamSet = collectParamNameSet(route.params);
117
+ for (const [slotKey, slot] of Object.entries(slots)) {
118
+ const patternParts = slot.slotPatternParts;
119
+ const paramNames = slot.slotParamNames;
120
+ if (!patternParts || patternParts.length === 0) continue;
121
+ if (paramNames && paramNames.every((name) => routeParamSet.has(name))) continue;
122
+ if (urlParts === null) urlParts = routePath.split("/").filter(Boolean);
123
+ const matched = matchRoutePattern(urlParts, patternParts);
124
+ if (!matched) continue;
125
+ const existing = overrides[slotKey];
126
+ overrides[slotKey] = existing ? {
127
+ ...existing,
128
+ params: matched
129
+ } : { params: matched };
130
+ }
131
+ }
132
+ return Object.keys(overrides).length > 0 ? overrides : null;
133
+ }
134
+ function collectParamNameSet(params) {
135
+ const set = /* @__PURE__ */ new Set();
136
+ if (params) for (const name of params) set.add(name);
137
+ return set;
138
+ }
139
+ //#endregion
140
+ export { buildPageElements };
141
+
142
+ //# sourceMappingURL=app-page-element-builder.js.map
@@ -0,0 +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 } 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 { matchRoutePattern } from \"../routing/route-pattern.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.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 interceptSlotKey?: 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};\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\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 { opts, searchParams, isRscRequest, mountedSlotsHeader } = pageRequest;\n\n const pageModule: AppPageModule | null | undefined = route.page;\n const PageComponent = pageModule?.default;\n const hasPageModule = !!pageModule;\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 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 interceptionContext,\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 metadata: resolvedMetadata,\n pageSearchParams,\n viewport: resolvedViewport,\n } = await resolveAppPageHead({\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) markDynamicUsage();\n }\n\n const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(\" \")) : null;\n\n const slotOverrides = buildSlotOverrides(route, params, routePath, opts);\n\n return buildAppPageElements({\n element: PageComponent ? createElement(PageComponent, pageProps) : null,\n globalErrorModule: globalErrorModule ?? null,\n isRscRequest,\n mountedSlotIds,\n makeThenableParams,\n matchedParams: params,\n resolvedMetadata,\n resolvedViewport,\n interceptionContext: opts?.interceptionContext ?? null,\n routePath,\n rootNotFoundModule: rootNotFoundModule ?? null,\n rootForbiddenModule: rootForbiddenModule ?? null,\n rootUnauthorizedModule: rootUnauthorizedModule ?? null,\n route,\n slotOverrides,\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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"}
@@ -1,6 +1,5 @@
1
1
  import { ClassificationReason } from "../build/layout-classification-types.js";
2
- import { LayoutFlags } from "./app-elements.js";
3
-
2
+ import { LayoutFlags } from "./app-elements-wire.js";
4
3
  //#region src/server/app-page-execution.d.ts
5
4
  type AppPageSpecialError = {
6
5
  kind: "redirect";
@@ -19,12 +18,32 @@ type AppPageRscStreamCapture = {
19
18
  sideStream?: ReadableStream<Uint8Array>;
20
19
  };
21
20
  type BuildAppPageSpecialErrorResponseOptions = {
21
+ /**
22
+ * Optional configured basePath (e.g. "/blog"). When set, redirect Locations
23
+ * pointing at app-internal paths get prefixed so callers see e.g.
24
+ * `Location: /blog/about` for `redirect("/about")`. Mirrors Next.js's
25
+ * `addPathPrefix(getURLFromRedirectError(err), basePath)` in app-render.tsx.
26
+ * External URLs (those that resolve to a different origin than the request)
27
+ * are left untouched.
28
+ */
29
+ basePath?: string;
22
30
  clearRequestContext: () => void;
31
+ /**
32
+ * Drains and returns Set-Cookie header values that were accumulated during
33
+ * this render via cookies().set() / cookies().delete(). Appended to redirect
34
+ * responses so an auth flow that does `cookies().set("session", "...");
35
+ * redirect("/")` preserves the cookie on the 307. Mirrors Next.js's
36
+ * `appendMutableCookies(headers, requestStore.mutableCookies)` in
37
+ * app-render.tsx. Only applied to redirect responses to match Next.js;
38
+ * the http-access-fallback path leaves cookies to the rendered boundary.
39
+ */
40
+ getAndClearPendingCookies?: () => string[];
41
+ isRscRequest: boolean;
23
42
  middlewareContext?: {
24
43
  headers: Headers | null;
25
44
  };
26
45
  renderFallbackPage?: (statusCode: number) => Promise<Response | null>;
27
- requestUrl: string;
46
+ request: Request;
28
47
  specialError: AppPageSpecialError;
29
48
  };
30
49
  type ProbeAppPageLayoutsResult = {
@@ -73,10 +92,9 @@ declare function buildAppPageSpecialErrorResponse(options: BuildAppPageSpecialEr
73
92
  /** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */
74
93
  declare function probeAppPageLayouts(options: ProbeAppPageLayoutsOptions): Promise<ProbeAppPageLayoutsResult>;
75
94
  declare function probeAppPageComponent(options: ProbeAppPageComponentOptions): Promise<Response | null>;
76
- declare function readAppPageTextStream(stream: ReadableStream<Uint8Array>): Promise<string>;
77
95
  declare function readAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer>;
78
96
  declare function teeAppPageRscStreamForCapture(stream: ReadableStream<Uint8Array>, shouldCapture: boolean): AppPageRscStreamCapture;
79
97
  declare function buildAppPageFontLinkHeader(preloads: readonly AppPageFontPreload[] | null | undefined): string;
80
98
  //#endregion
81
- export { AppPageFontPreload, AppPageSpecialError, type ClassificationReason, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
99
+ export { AppPageFontPreload, AppPageSpecialError, type ClassificationReason, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
82
100
  //# sourceMappingURL=app-page-execution.d.ts.map
@@ -1,4 +1,7 @@
1
+ import { hasBasePath } from "../utils/base-path.js";
2
+ import { createRscRedirectLocation } from "./app-rsc-cache-busting.js";
1
3
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
4
+ import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
2
5
  //#region src/server/app-page-execution.ts
3
6
  function isPromiseLike(value) {
4
7
  return Boolean(value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function");
@@ -18,25 +21,49 @@ function mergeAppPageSpecialErrorHeaders(response, middlewareContext) {
18
21
  function resolveAppPageSpecialError(error) {
19
22
  if (!(error && typeof error === "object" && "digest" in error)) return null;
20
23
  const digest = String(error.digest);
21
- if (digest.startsWith("NEXT_REDIRECT;")) {
22
- const parts = digest.split(";");
23
- return {
24
- kind: "redirect",
25
- location: decodeURIComponent(parts[2]),
26
- statusCode: parts[3] ? parseInt(parts[3], 10) : 307
27
- };
28
- }
29
- if (digest === "NEXT_NOT_FOUND" || digest.startsWith("NEXT_HTTP_ERROR_FALLBACK;")) return {
24
+ const redirect = parseNextRedirectDigest(digest);
25
+ if (redirect) return {
26
+ kind: "redirect",
27
+ location: redirect.url,
28
+ statusCode: redirect.status
29
+ };
30
+ const httpError = parseNextHttpErrorDigest(digest);
31
+ if (httpError) return {
30
32
  kind: "http-access-fallback",
31
- statusCode: digest === "NEXT_NOT_FOUND" ? 404 : parseInt(digest.split(";")[1], 10)
33
+ statusCode: httpError.status
32
34
  };
33
35
  return null;
34
36
  }
37
+ /**
38
+ * Resolves a redirect() target against the request URL and prepends the
39
+ * configured basePath when the target is an app-internal absolute path.
40
+ *
41
+ * Mirrors Next.js's `addPathPrefix(getURLFromRedirectError(err), basePath)`
42
+ * in `app-render.tsx`: a `redirect("/about")` call from a page mounted at
43
+ * `/blog` (basePath) produces `Location: /blog/about`.
44
+ *
45
+ * Skips prefixing when:
46
+ * - basePath is unset / empty
47
+ * - the target is a full URL pointing at a different origin (external redirect)
48
+ * - the target already starts with the basePath (caller did the work themselves)
49
+ */
50
+ function applyAppPageRedirectBasePath(location, requestUrl, basePath) {
51
+ const resolved = new URL(location, requestUrl);
52
+ const requestOrigin = new URL(requestUrl).origin;
53
+ if (!basePath || resolved.origin !== requestOrigin) return resolved.toString();
54
+ if (hasBasePath(resolved.pathname, basePath)) return resolved.toString();
55
+ resolved.pathname = resolved.pathname === "/" ? basePath : `${basePath}${resolved.pathname}`;
56
+ return resolved.toString();
57
+ }
35
58
  async function buildAppPageSpecialErrorResponse(options) {
36
59
  if (options.specialError.kind === "redirect") {
37
60
  options.clearRequestContext();
38
- const headers = new Headers({ Location: new URL(options.specialError.location, options.requestUrl).toString() });
61
+ const prefixedLocation = applyAppPageRedirectBasePath(options.specialError.location, options.request.url, options.basePath);
62
+ const location = options.isRscRequest ? await createRscRedirectLocation(prefixedLocation, options.request) : prefixedLocation;
63
+ const headers = new Headers({ Location: location });
39
64
  mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);
65
+ const pendingCookies = options.getAndClearPendingCookies?.() ?? [];
66
+ for (const cookie of pendingCookies) headers.append("Set-Cookie", cookie);
40
67
  return new Response(null, {
41
68
  headers,
42
69
  status: options.specialError.statusCode
@@ -113,18 +140,6 @@ async function probeAppPageComponent(options) {
113
140
  return null;
114
141
  });
115
142
  }
116
- async function readAppPageTextStream(stream) {
117
- const reader = stream.getReader();
118
- const decoder = new TextDecoder();
119
- const chunks = [];
120
- for (;;) {
121
- const { done, value } = await reader.read();
122
- if (done) break;
123
- chunks.push(decoder.decode(value, { stream: true }));
124
- }
125
- chunks.push(decoder.decode());
126
- return chunks.join("");
127
- }
128
143
  async function readAppPageBinaryStream(stream) {
129
144
  const reader = stream.getReader();
130
145
  const chunks = [];
@@ -156,6 +171,6 @@ function buildAppPageFontLinkHeader(preloads) {
156
171
  return preloads.map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`).join(", ");
157
172
  }
158
173
  //#endregion
159
- export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
174
+ export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
160
175
 
161
176
  //# sourceMappingURL=app-page-execution.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-execution.js","names":[],"sources":["../../src/server/app-page-execution.ts"],"sourcesContent":["import type { LayoutFlags } from \"./app-elements.js\";\nimport type { ClassificationReason } from \"../build/layout-classification-types.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\nexport type { LayoutFlags };\nexport type { ClassificationReason };\n\nexport type AppPageSpecialError =\n | { kind: \"redirect\"; location: string; statusCode: number }\n | { kind: \"http-access-fallback\"; statusCode: number };\n\nexport type AppPageFontPreload = {\n href: string;\n type: string;\n};\n\ntype AppPageRscStreamCapture = {\n /** Stream for createFromReadableStream (SSR). Always set. */\n ssrStream: ReadableStream<Uint8Array>;\n /** When capturing, the combined embed+capture stream. handleSsr consumes this. */\n sideStream?: ReadableStream<Uint8Array>;\n};\n\ntype BuildAppPageSpecialErrorResponseOptions = {\n clearRequestContext: () => void;\n middlewareContext?: { headers: Headers | null };\n renderFallbackPage?: (statusCode: number) => Promise<Response | null>;\n requestUrl: string;\n specialError: AppPageSpecialError;\n};\n\ntype ProbeAppPageLayoutsResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\nexport type LayoutClassificationOptions = {\n /** Build-time classifications from segment config or module graph, keyed by layout index. */\n buildTimeClassifications?: ReadonlyMap<number, \"static\" | \"dynamic\"> | null;\n /**\n * Per-layout classification reasons keyed by layout index. Requires\n * `VINEXT_DEBUG_CLASSIFICATION` at BOTH lifecycle points: at build time so\n * the plugin patches the `__VINEXT_CLASS_REASONS` dispatch stub, and at\n * runtime so the route object actually calls it. Setting the flag only at\n * runtime leaves the stub returning `null`, and every build-time classified\n * layout will fall through to `{ layer: \"no-classifier\" }` in the debug\n * channel. The hot path never reads this and the wire payload is unchanged.\n */\n buildTimeReasons?: ReadonlyMap<number, ClassificationReason> | null;\n /**\n * Emits one log line per layout with the classification reason, keyed by\n * layout ID. Set by the generator when `VINEXT_DEBUG_CLASSIFICATION` is\n * active. When undefined, the probe loop skips debug emission entirely.\n */\n debugClassification?: (layoutId: string, reason: ClassificationReason) => void;\n /** Maps layout index to its layout ID (e.g. \"layout:/blog\"). */\n getLayoutId: (layoutIndex: number) => string;\n /** Runs a function with isolated dynamic usage tracking per layout. */\n runWithIsolatedDynamicScope: <T>(fn: () => T) => Promise<{ result: T; dynamicDetected: boolean }>;\n};\n\ntype ProbeAppPageLayoutsOptions = {\n layoutCount: number;\n onLayoutError: (error: unknown, layoutIndex: number) => Promise<Response | null>;\n probeLayoutAt: (layoutIndex: number) => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\ntype ProbeAppPageComponentOptions = {\n awaitAsyncResult: boolean;\n onError: (error: unknown) => Promise<Response | null>;\n probePage: () => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\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 getAppPageStatusText(statusCode: number): string {\n return statusCode === 403 ? \"Forbidden\" : statusCode === 401 ? \"Unauthorized\" : \"Not Found\";\n}\n\nfunction mergeAppPageSpecialErrorHeaders(\n response: Response,\n middlewareContext: { headers: Headers | null } | undefined,\n): Response {\n const headers = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareContext?.headers ?? null);\n\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nexport function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null {\n if (!(error && typeof error === \"object\" && \"digest\" in error)) {\n return null;\n }\n\n const digest = String(error.digest);\n\n if (digest.startsWith(\"NEXT_REDIRECT;\")) {\n const parts = digest.split(\";\");\n return {\n kind: \"redirect\",\n location: decodeURIComponent(parts[2]),\n statusCode: parts[3] ? parseInt(parts[3], 10) : 307,\n };\n }\n\n if (digest === \"NEXT_NOT_FOUND\" || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n return {\n kind: \"http-access-fallback\",\n statusCode: digest === \"NEXT_NOT_FOUND\" ? 404 : parseInt(digest.split(\";\")[1], 10),\n };\n }\n\n return null;\n}\n\nexport async function buildAppPageSpecialErrorResponse(\n options: BuildAppPageSpecialErrorResponseOptions,\n): Promise<Response> {\n if (options.specialError.kind === \"redirect\") {\n options.clearRequestContext();\n const headers = new Headers({\n Location: new URL(options.specialError.location, options.requestUrl).toString(),\n });\n // Middleware may contribute response headers here, but redirect() owns the\n // status. Do not apply middlewareContext.status on special-error responses.\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);\n\n return new Response(null, {\n headers,\n status: options.specialError.statusCode,\n });\n }\n\n if (options.renderFallbackPage) {\n const fallbackResponse = await options.renderFallbackPage(options.specialError.statusCode);\n if (fallbackResponse) {\n return mergeAppPageSpecialErrorHeaders(fallbackResponse, options.middlewareContext);\n }\n }\n\n options.clearRequestContext();\n return mergeAppPageSpecialErrorHeaders(\n new Response(getAppPageStatusText(options.specialError.statusCode), {\n status: options.specialError.statusCode,\n }),\n options.middlewareContext,\n );\n}\n\n/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */\nexport async function probeAppPageLayouts(\n options: ProbeAppPageLayoutsOptions,\n): Promise<ProbeAppPageLayoutsResult> {\n const layoutFlags: Record<string, \"s\" | \"d\"> = {};\n const cls = options.classification ?? null;\n\n const response = await options.runWithSuppressedHookWarning(async () => {\n for (let layoutIndex = options.layoutCount - 1; layoutIndex >= 0; layoutIndex--) {\n const buildTimeResult = cls?.buildTimeClassifications?.get(layoutIndex);\n\n if (cls && buildTimeResult) {\n // Build-time classified (Layer 1 or Layer 2): skip dynamic isolation,\n // but still probe for special errors (redirects, not-found).\n layoutFlags[cls.getLayoutId(layoutIndex)] = buildTimeResult === \"static\" ? \"s\" : \"d\";\n if (cls.debugClassification) {\n // `no-classifier` is the documented fallback for a layout that was\n // build-time classified but whose reason payload is absent — either\n // because the build was run without `VINEXT_DEBUG_CLASSIFICATION` or\n // because no Layer 1/2 classifier attached a reason. This is the sole\n // producer of the variant; see `layout-classification-types.ts`.\n cls.debugClassification(\n cls.getLayoutId(layoutIndex),\n cls.buildTimeReasons?.get(layoutIndex) ?? { layer: \"no-classifier\" },\n );\n }\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n continue;\n }\n\n if (cls) {\n // Layer 3: probe with isolated dynamic scope to detect per-layout\n // dynamic API usage (headers(), cookies(), connection(), etc.)\n try {\n const { dynamicDetected } = await cls.runWithIsolatedDynamicScope(() =>\n options.probeLayoutAt(layoutIndex),\n );\n layoutFlags[cls.getLayoutId(layoutIndex)] = dynamicDetected ? \"d\" : \"s\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: dynamicDetected ? \"dynamic\" : \"static\",\n });\n }\n } catch (error) {\n // Probe failed — conservatively treat as dynamic.\n layoutFlags[cls.getLayoutId(layoutIndex)] = \"d\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: \"dynamic\",\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const errorResponse = await options.onLayoutError(error, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n continue;\n }\n\n // No classification options — original behavior\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n\n return null;\n });\n\n return { response, layoutFlags };\n}\n\nasync function probeLayoutForErrors(\n options: ProbeAppPageLayoutsOptions,\n layoutIndex: number,\n): Promise<Response | null> {\n try {\n const layoutResult = options.probeLayoutAt(layoutIndex);\n if (isPromiseLike(layoutResult)) {\n await layoutResult;\n }\n } catch (error) {\n return options.onLayoutError(error, layoutIndex);\n }\n return null;\n}\n\nexport async function probeAppPageComponent(\n options: ProbeAppPageComponentOptions,\n): Promise<Response | null> {\n return options.runWithSuppressedHookWarning(async () => {\n try {\n const pageResult = options.probePage();\n if (isPromiseLike(pageResult)) {\n if (options.awaitAsyncResult) {\n await pageResult;\n } else {\n void Promise.resolve(pageResult).catch(() => {});\n }\n }\n } catch (error) {\n return options.onError(error);\n }\n\n return null;\n });\n}\n\nexport async function readAppPageTextStream(stream: ReadableStream<Uint8Array>): Promise<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n}\n\nexport async function readAppPageBinaryStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<ArrayBuffer> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(value);\n totalLength += value.byteLength;\n }\n\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return buffer.buffer;\n}\n\nexport function teeAppPageRscStreamForCapture(\n stream: ReadableStream<Uint8Array>,\n shouldCapture: boolean,\n): AppPageRscStreamCapture {\n if (!shouldCapture) {\n return {\n ssrStream: stream,\n };\n }\n\n const [ssrStream, sideStream] = stream.tee();\n return {\n ssrStream,\n sideStream,\n };\n}\n\nexport function buildAppPageFontLinkHeader(\n preloads: readonly AppPageFontPreload[] | null | undefined,\n): string {\n if (!preloads || preloads.length === 0) {\n return \"\";\n }\n\n return preloads\n .map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`)\n .join(\", \");\n}\n"],"mappings":";;AA6EA,SAAS,cAAc,OAA+C;AACpE,QAAO,QACL,UACC,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,UAAU,SACV,OAAO,MAAM,SAAS,WACvB;;AAGH,SAAS,qBAAqB,YAA4B;AACxD,QAAO,eAAe,MAAM,cAAc,eAAe,MAAM,iBAAiB;;AAGlF,SAAS,gCACP,UACA,mBACU;CACV,MAAM,UAAU,IAAI,QAAQ,SAAS,QAAQ;AAC7C,gCAA+B,SAAS,mBAAmB,WAAW,KAAK;AAE3E,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC;EACA,QAAQ,SAAS;EACjB,YAAY,SAAS;EACtB,CAAC;;AAGJ,SAAgB,2BAA2B,OAA4C;AACrF,KAAI,EAAE,SAAS,OAAO,UAAU,YAAY,YAAY,OACtD,QAAO;CAGT,MAAM,SAAS,OAAO,MAAM,OAAO;AAEnC,KAAI,OAAO,WAAW,iBAAiB,EAAE;EACvC,MAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,SAAO;GACL,MAAM;GACN,UAAU,mBAAmB,MAAM,GAAG;GACtC,YAAY,MAAM,KAAK,SAAS,MAAM,IAAI,GAAG,GAAG;GACjD;;AAGH,KAAI,WAAW,oBAAoB,OAAO,WAAW,4BAA4B,CAC/E,QAAO;EACL,MAAM;EACN,YAAY,WAAW,mBAAmB,MAAM,SAAS,OAAO,MAAM,IAAI,CAAC,IAAI,GAAG;EACnF;AAGH,QAAO;;AAGT,eAAsB,iCACpB,SACmB;AACnB,KAAI,QAAQ,aAAa,SAAS,YAAY;AAC5C,UAAQ,qBAAqB;EAC7B,MAAM,UAAU,IAAI,QAAQ,EAC1B,UAAU,IAAI,IAAI,QAAQ,aAAa,UAAU,QAAQ,WAAW,CAAC,UAAU,EAChF,CAAC;AAGF,iCAA+B,SAAS,QAAQ,mBAAmB,WAAW,KAAK;AAEnF,SAAO,IAAI,SAAS,MAAM;GACxB;GACA,QAAQ,QAAQ,aAAa;GAC9B,CAAC;;AAGJ,KAAI,QAAQ,oBAAoB;EAC9B,MAAM,mBAAmB,MAAM,QAAQ,mBAAmB,QAAQ,aAAa,WAAW;AAC1F,MAAI,iBACF,QAAO,gCAAgC,kBAAkB,QAAQ,kBAAkB;;AAIvF,SAAQ,qBAAqB;AAC7B,QAAO,gCACL,IAAI,SAAS,qBAAqB,QAAQ,aAAa,WAAW,EAAE,EAClE,QAAQ,QAAQ,aAAa,YAC9B,CAAC,EACF,QAAQ,kBACT;;;AAIH,eAAsB,oBACpB,SACoC;CACpC,MAAM,cAAyC,EAAE;CACjD,MAAM,MAAM,QAAQ,kBAAkB;AAgEtC,QAAO;EAAE,UA9DQ,MAAM,QAAQ,6BAA6B,YAAY;AACtE,QAAK,IAAI,cAAc,QAAQ,cAAc,GAAG,eAAe,GAAG,eAAe;IAC/E,MAAM,kBAAkB,KAAK,0BAA0B,IAAI,YAAY;AAEvE,QAAI,OAAO,iBAAiB;AAG1B,iBAAY,IAAI,YAAY,YAAY,IAAI,oBAAoB,WAAW,MAAM;AACjF,SAAI,IAAI,oBAMN,KAAI,oBACF,IAAI,YAAY,YAAY,EAC5B,IAAI,kBAAkB,IAAI,YAAY,IAAI,EAAE,OAAO,iBAAiB,CACrE;KAEH,MAAM,gBAAgB,MAAM,qBAAqB,SAAS,YAAY;AACtE,SAAI,cAAe,QAAO;AAC1B;;AAGF,QAAI,KAAK;AAGP,SAAI;MACF,MAAM,EAAE,oBAAoB,MAAM,IAAI,kCACpC,QAAQ,cAAc,YAAY,CACnC;AACD,kBAAY,IAAI,YAAY,YAAY,IAAI,kBAAkB,MAAM;AACpE,UAAI,IAAI,oBACN,KAAI,oBAAoB,IAAI,YAAY,YAAY,EAAE;OACpD,OAAO;OACP,SAAS,kBAAkB,YAAY;OACxC,CAAC;cAEG,OAAO;AAEd,kBAAY,IAAI,YAAY,YAAY,IAAI;AAC5C,UAAI,IAAI,oBACN,KAAI,oBAAoB,IAAI,YAAY,YAAY,EAAE;OACpD,OAAO;OACP,SAAS;OACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;OAC9D,CAAC;MAEJ,MAAM,gBAAgB,MAAM,QAAQ,cAAc,OAAO,YAAY;AACrE,UAAI,cAAe,QAAO;;AAE5B;;IAIF,MAAM,gBAAgB,MAAM,qBAAqB,SAAS,YAAY;AACtE,QAAI,cAAe,QAAO;;AAG5B,UAAO;IACP;EAEiB;EAAa;;AAGlC,eAAe,qBACb,SACA,aAC0B;AAC1B,KAAI;EACF,MAAM,eAAe,QAAQ,cAAc,YAAY;AACvD,MAAI,cAAc,aAAa,CAC7B,OAAM;UAED,OAAO;AACd,SAAO,QAAQ,cAAc,OAAO,YAAY;;AAElD,QAAO;;AAGT,eAAsB,sBACpB,SAC0B;AAC1B,QAAO,QAAQ,6BAA6B,YAAY;AACtD,MAAI;GACF,MAAM,aAAa,QAAQ,WAAW;AACtC,OAAI,cAAc,WAAW,CAC3B,KAAI,QAAQ,iBACV,OAAM;OAED,SAAQ,QAAQ,WAAW,CAAC,YAAY,GAAG;WAG7C,OAAO;AACd,UAAO,QAAQ,QAAQ,MAAM;;AAG/B,SAAO;GACP;;AAGJ,eAAsB,sBAAsB,QAAqD;CAC/F,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,SAAmB,EAAE;AAE3B,UAAS;EACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,KACF;AAEF,SAAO,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC;;AAGtD,QAAO,KAAK,QAAQ,QAAQ,CAAC;AAC7B,QAAO,OAAO,KAAK,GAAG;;AAGxB,eAAsB,wBACpB,QACsB;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,SAAuB,EAAE;CAC/B,IAAI,cAAc;AAElB,UAAS;EACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,KACF;AAEF,SAAO,KAAK,MAAM;AAClB,iBAAe,MAAM;;CAGvB,MAAM,SAAS,IAAI,WAAW,YAAY;CAC1C,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,SAAO,IAAI,OAAO,OAAO;AACzB,YAAU,MAAM;;AAGlB,QAAO,OAAO;;AAGhB,SAAgB,8BACd,QACA,eACyB;AACzB,KAAI,CAAC,cACH,QAAO,EACL,WAAW,QACZ;CAGH,MAAM,CAAC,WAAW,cAAc,OAAO,KAAK;AAC5C,QAAO;EACL;EACA;EACD;;AAGH,SAAgB,2BACd,UACQ;AACR,KAAI,CAAC,YAAY,SAAS,WAAW,EACnC,QAAO;AAGT,QAAO,SACJ,KAAK,YAAY,IAAI,QAAQ,KAAK,gCAAgC,QAAQ,KAAK,eAAe,CAC9F,KAAK,KAAK"}
1
+ {"version":3,"file":"app-page-execution.js","names":[],"sources":["../../src/server/app-page-execution.ts"],"sourcesContent":["import type { LayoutFlags } from \"./app-elements.js\";\nimport type { ClassificationReason } from \"../build/layout-classification-types.js\";\nimport { createRscRedirectLocation } from \"./app-rsc-cache-busting.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { parseNextHttpErrorDigest, parseNextRedirectDigest } from \"./next-error-digest.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\n\nexport type { LayoutFlags };\nexport type { ClassificationReason };\n\nexport type AppPageSpecialError =\n | { kind: \"redirect\"; location: string; statusCode: number }\n | { kind: \"http-access-fallback\"; statusCode: number };\n\nexport type AppPageFontPreload = {\n href: string;\n type: string;\n};\n\ntype AppPageRscStreamCapture = {\n /** Stream for createFromReadableStream (SSR). Always set. */\n ssrStream: ReadableStream<Uint8Array>;\n /** When capturing, the combined embed+capture stream. handleSsr consumes this. */\n sideStream?: ReadableStream<Uint8Array>;\n};\n\ntype BuildAppPageSpecialErrorResponseOptions = {\n /**\n * Optional configured basePath (e.g. \"/blog\"). When set, redirect Locations\n * pointing at app-internal paths get prefixed so callers see e.g.\n * `Location: /blog/about` for `redirect(\"/about\")`. Mirrors Next.js's\n * `addPathPrefix(getURLFromRedirectError(err), basePath)` in app-render.tsx.\n * External URLs (those that resolve to a different origin than the request)\n * are left untouched.\n */\n basePath?: string;\n clearRequestContext: () => void;\n /**\n * Drains and returns Set-Cookie header values that were accumulated during\n * this render via cookies().set() / cookies().delete(). Appended to redirect\n * responses so an auth flow that does `cookies().set(\"session\", \"...\");\n * redirect(\"/\")` preserves the cookie on the 307. Mirrors Next.js's\n * `appendMutableCookies(headers, requestStore.mutableCookies)` in\n * app-render.tsx. Only applied to redirect responses to match Next.js;\n * the http-access-fallback path leaves cookies to the rendered boundary.\n */\n getAndClearPendingCookies?: () => string[];\n isRscRequest: boolean;\n middlewareContext?: { headers: Headers | null };\n renderFallbackPage?: (statusCode: number) => Promise<Response | null>;\n request: Request;\n specialError: AppPageSpecialError;\n};\n\ntype ProbeAppPageLayoutsResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\nexport type LayoutClassificationOptions = {\n /** Build-time classifications from segment config or module graph, keyed by layout index. */\n buildTimeClassifications?: ReadonlyMap<number, \"static\" | \"dynamic\"> | null;\n /**\n * Per-layout classification reasons keyed by layout index. Requires\n * `VINEXT_DEBUG_CLASSIFICATION` at BOTH lifecycle points: at build time so\n * the plugin patches the `__VINEXT_CLASS_REASONS` dispatch stub, and at\n * runtime so the route object actually calls it. Setting the flag only at\n * runtime leaves the stub returning `null`, and every build-time classified\n * layout will fall through to `{ layer: \"no-classifier\" }` in the debug\n * channel. The hot path never reads this and the wire payload is unchanged.\n */\n buildTimeReasons?: ReadonlyMap<number, ClassificationReason> | null;\n /**\n * Emits one log line per layout with the classification reason, keyed by\n * layout ID. Set by the generator when `VINEXT_DEBUG_CLASSIFICATION` is\n * active. When undefined, the probe loop skips debug emission entirely.\n */\n debugClassification?: (layoutId: string, reason: ClassificationReason) => void;\n /** Maps layout index to its layout ID (e.g. \"layout:/blog\"). */\n getLayoutId: (layoutIndex: number) => string;\n /** Runs a function with isolated dynamic usage tracking per layout. */\n runWithIsolatedDynamicScope: <T>(fn: () => T) => Promise<{ result: T; dynamicDetected: boolean }>;\n};\n\ntype ProbeAppPageLayoutsOptions = {\n layoutCount: number;\n onLayoutError: (error: unknown, layoutIndex: number) => Promise<Response | null>;\n probeLayoutAt: (layoutIndex: number) => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\ntype ProbeAppPageComponentOptions = {\n awaitAsyncResult: boolean;\n onError: (error: unknown) => Promise<Response | null>;\n probePage: () => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\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 getAppPageStatusText(statusCode: number): string {\n return statusCode === 403 ? \"Forbidden\" : statusCode === 401 ? \"Unauthorized\" : \"Not Found\";\n}\n\nfunction mergeAppPageSpecialErrorHeaders(\n response: Response,\n middlewareContext: { headers: Headers | null } | undefined,\n): Response {\n const headers = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareContext?.headers ?? null);\n\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nexport function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null {\n if (!(error && typeof error === \"object\" && \"digest\" in error)) {\n return null;\n }\n\n const digest = String(error.digest);\n\n const redirect = parseNextRedirectDigest(digest);\n if (redirect) {\n return {\n kind: \"redirect\",\n location: redirect.url,\n statusCode: redirect.status,\n };\n }\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (httpError) {\n return {\n kind: \"http-access-fallback\",\n statusCode: httpError.status,\n };\n }\n\n return null;\n}\n\n/**\n * Resolves a redirect() target against the request URL and prepends the\n * configured basePath when the target is an app-internal absolute path.\n *\n * Mirrors Next.js's `addPathPrefix(getURLFromRedirectError(err), basePath)`\n * in `app-render.tsx`: a `redirect(\"/about\")` call from a page mounted at\n * `/blog` (basePath) produces `Location: /blog/about`.\n *\n * Skips prefixing when:\n * - basePath is unset / empty\n * - the target is a full URL pointing at a different origin (external redirect)\n * - the target already starts with the basePath (caller did the work themselves)\n */\nfunction applyAppPageRedirectBasePath(\n location: string,\n requestUrl: string,\n basePath: string | undefined,\n): string {\n const resolved = new URL(location, requestUrl);\n const requestOrigin = new URL(requestUrl).origin;\n if (!basePath || resolved.origin !== requestOrigin) {\n return resolved.toString();\n }\n if (hasBasePath(resolved.pathname, basePath)) {\n return resolved.toString();\n }\n resolved.pathname = resolved.pathname === \"/\" ? basePath : `${basePath}${resolved.pathname}`;\n return resolved.toString();\n}\n\nexport async function buildAppPageSpecialErrorResponse(\n options: BuildAppPageSpecialErrorResponseOptions,\n): Promise<Response> {\n if (options.specialError.kind === \"redirect\") {\n options.clearRequestContext();\n // Apply configured basePath first so app-internal targets land at\n // /<basePath>/<target> before the RSC cache-busting transform sees them.\n const prefixedLocation = applyAppPageRedirectBasePath(\n options.specialError.location,\n options.request.url,\n options.basePath,\n );\n const location = options.isRscRequest\n ? await createRscRedirectLocation(prefixedLocation, options.request)\n : prefixedLocation;\n const headers = new Headers({\n Location: location,\n });\n // Middleware may contribute response headers here, but redirect() owns the\n // status. Do not apply middlewareContext.status on special-error responses.\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);\n // Preserve cookies set via cookies().set() / cookies().delete() during the\n // page render — auth flows commonly set a session cookie and immediately\n // redirect, and those Set-Cookie values must ride on the 307.\n const pendingCookies = options.getAndClearPendingCookies?.() ?? [];\n for (const cookie of pendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n\n return new Response(null, {\n headers,\n status: options.specialError.statusCode,\n });\n }\n\n if (options.renderFallbackPage) {\n const fallbackResponse = await options.renderFallbackPage(options.specialError.statusCode);\n if (fallbackResponse) {\n return mergeAppPageSpecialErrorHeaders(fallbackResponse, options.middlewareContext);\n }\n }\n\n options.clearRequestContext();\n return mergeAppPageSpecialErrorHeaders(\n new Response(getAppPageStatusText(options.specialError.statusCode), {\n status: options.specialError.statusCode,\n }),\n options.middlewareContext,\n );\n}\n\n/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */\nexport async function probeAppPageLayouts(\n options: ProbeAppPageLayoutsOptions,\n): Promise<ProbeAppPageLayoutsResult> {\n const layoutFlags: Record<string, \"s\" | \"d\"> = {};\n const cls = options.classification ?? null;\n\n const response = await options.runWithSuppressedHookWarning(async () => {\n for (let layoutIndex = options.layoutCount - 1; layoutIndex >= 0; layoutIndex--) {\n const buildTimeResult = cls?.buildTimeClassifications?.get(layoutIndex);\n\n if (cls && buildTimeResult) {\n // Build-time classified (Layer 1 or Layer 2): skip dynamic isolation,\n // but still probe for special errors (redirects, not-found).\n layoutFlags[cls.getLayoutId(layoutIndex)] = buildTimeResult === \"static\" ? \"s\" : \"d\";\n if (cls.debugClassification) {\n // `no-classifier` is the documented fallback for a layout that was\n // build-time classified but whose reason payload is absent — either\n // because the build was run without `VINEXT_DEBUG_CLASSIFICATION` or\n // because no Layer 1/2 classifier attached a reason. This is the sole\n // producer of the variant; see `layout-classification-types.ts`.\n cls.debugClassification(\n cls.getLayoutId(layoutIndex),\n cls.buildTimeReasons?.get(layoutIndex) ?? { layer: \"no-classifier\" },\n );\n }\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n continue;\n }\n\n if (cls) {\n // Layer 3: probe with isolated dynamic scope to detect per-layout\n // dynamic API usage (headers(), cookies(), connection(), etc.)\n try {\n const { dynamicDetected } = await cls.runWithIsolatedDynamicScope(() =>\n options.probeLayoutAt(layoutIndex),\n );\n layoutFlags[cls.getLayoutId(layoutIndex)] = dynamicDetected ? \"d\" : \"s\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: dynamicDetected ? \"dynamic\" : \"static\",\n });\n }\n } catch (error) {\n // Probe failed — conservatively treat as dynamic.\n layoutFlags[cls.getLayoutId(layoutIndex)] = \"d\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: \"dynamic\",\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const errorResponse = await options.onLayoutError(error, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n continue;\n }\n\n // No classification options — original behavior\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n\n return null;\n });\n\n return { response, layoutFlags };\n}\n\nasync function probeLayoutForErrors(\n options: ProbeAppPageLayoutsOptions,\n layoutIndex: number,\n): Promise<Response | null> {\n try {\n const layoutResult = options.probeLayoutAt(layoutIndex);\n if (isPromiseLike(layoutResult)) {\n await layoutResult;\n }\n } catch (error) {\n return options.onLayoutError(error, layoutIndex);\n }\n return null;\n}\n\nexport async function probeAppPageComponent(\n options: ProbeAppPageComponentOptions,\n): Promise<Response | null> {\n return options.runWithSuppressedHookWarning(async () => {\n try {\n const pageResult = options.probePage();\n if (isPromiseLike(pageResult)) {\n if (options.awaitAsyncResult) {\n await pageResult;\n } else {\n void Promise.resolve(pageResult).catch(() => {});\n }\n }\n } catch (error) {\n return options.onError(error);\n }\n\n return null;\n });\n}\n\nexport async function readAppPageBinaryStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<ArrayBuffer> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(value);\n totalLength += value.byteLength;\n }\n\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return buffer.buffer;\n}\n\nexport function teeAppPageRscStreamForCapture(\n stream: ReadableStream<Uint8Array>,\n shouldCapture: boolean,\n): AppPageRscStreamCapture {\n if (!shouldCapture) {\n return {\n ssrStream: stream,\n };\n }\n\n const [ssrStream, sideStream] = stream.tee();\n return {\n ssrStream,\n sideStream,\n };\n}\n\nexport function buildAppPageFontLinkHeader(\n preloads: readonly AppPageFontPreload[] | null | undefined,\n): string {\n if (!preloads || preloads.length === 0) {\n return \"\";\n }\n\n return preloads\n .map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`)\n .join(\", \");\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { mergeMetadataEntries, mergeViewport, resolveModuleMetadata, resolveModuleViewport } from "../shims/metadata.js";
1
+ import { mergeMetadataEntries, mergeViewport, postProcessMetadata, resolveModuleMetadata, resolveModuleViewport } from "../shims/metadata.js";
2
2
  import { resolveAppPageSegmentParams } from "./app-page-params.js";
3
3
  import { applyFileBasedMetadata } from "./file-based-metadata.js";
4
4
  //#region src/server/app-page-head.ts
@@ -183,6 +183,7 @@ async function resolveAppPageHead(options) {
183
183
  if (!options.fallbackOnFileMetadataError) throw error;
184
184
  console.error(`[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`, error);
185
185
  }
186
+ if (metadata) metadata = postProcessMetadata(metadata);
186
187
  return {
187
188
  hasSearchParams,
188
189
  metadata,
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-head.js","names":[],"sources":["../../src/server/app-page-head.ts"],"sourcesContent":["import {\n mergeMetadataEntries,\n mergeViewport,\n resolveModuleMetadata,\n resolveModuleViewport,\n type Metadata,\n type MetadataMergeEntry,\n type Viewport,\n} from \"vinext/shims/metadata\";\nimport { applyFileBasedMetadata } from \"./file-based-metadata.js\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\n\ntype AppPageSearchParams = Record<string, string | string[]>;\n\ntype AppPageHeadModule = Record<string, unknown>;\n\ntype AppPageHeadSource = {\n metadata: Metadata | null;\n routeSegments: readonly string[];\n};\n\ntype AppPageHeadLayout<TModule extends AppPageHeadModule> = {\n module: TModule;\n treePosition: number;\n};\n\ntype AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layoutModule?: TModule | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n pageModule?: TModule | null;\n params?: AppPageParams | null;\n routeSegments?: readonly string[] | null;\n};\n\ntype AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layout?: TModule | null;\n page?: TModule | null;\n};\n\ntype ResolveActiveParallelRouteHeadInputsOptions<\n TModule extends AppPageHeadModule = AppPageHeadModule,\n> = {\n interceptLayouts?: readonly (TModule | null | undefined)[] | null;\n interceptPage?: TModule | null;\n interceptParams?: AppPageParams | null;\n interceptSlotKey?: string | null;\n params: AppPageParams;\n routeSegments: readonly string[];\n slots?: Record<string, AppPageHeadSlot<TModule>> | null;\n};\n\ntype ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n fallbackOnFileMetadataError?: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n metadataRoutes: readonly MetadataFileRoute[];\n pageModule?: TModule | null;\n parallelRoutes?: readonly AppPageHeadParallelRoute<TModule>[] | null;\n params: AppPageParams;\n routePath: string;\n routeSegments?: readonly string[] | null;\n searchParams?: URLSearchParams | null;\n};\n\ntype ResolveAppPageHeadResult = {\n hasSearchParams: boolean;\n metadata: Metadata | null;\n pageSearchParams: AppPageSearchParams;\n viewport: Viewport;\n};\n\ntype AppPageSearchParamsCollection = {\n hasSearchParams: boolean;\n pageSearchParams: AppPageSearchParams;\n};\n\ntype ResolvedParallelRouteHead = {\n metadataResults: (Metadata | null)[];\n metadataSources: AppPageHeadSource[];\n viewportResults: (Viewport | null)[];\n};\n\nexport function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(\n options: ResolveActiveParallelRouteHeadInputsOptions<TModule>,\n): AppPageHeadParallelRoute<TModule>[] {\n return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {\n if (options.interceptSlotKey === slotKey && options.interceptPage) {\n return {\n layoutModules: options.interceptLayouts ?? [],\n pageModule: options.interceptPage,\n params: options.interceptParams ?? options.params,\n routeSegments: options.routeSegments,\n };\n }\n\n return {\n layoutModules: slot.layout ? [slot.layout] : [],\n pageModule: slot.page,\n params: options.params,\n routeSegments: options.routeSegments,\n };\n });\n}\n\nfunction isPresent<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined;\n}\n\nexport function collectAppPageSearchParams(\n searchParams: URLSearchParams | null | undefined,\n): AppPageSearchParamsCollection {\n const pageSearchParams: AppPageSearchParams = Object.create(null);\n let hasSearchParams = false;\n\n searchParams?.forEach((value, key) => {\n hasSearchParams = true;\n const currentValue = pageSearchParams[key];\n if (Array.isArray(currentValue)) {\n pageSearchParams[key] = [...currentValue, value];\n return;\n }\n if (currentValue !== undefined) {\n pageSearchParams[key] = [currentValue, value];\n return;\n }\n pageSearchParams[key] = value;\n });\n\n return { hasSearchParams, pageSearchParams };\n}\n\nfunction createMetadataSources(\n metadataResults: readonly (Metadata | null)[],\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n pageMetadata: Metadata | null,\n includePageSource: boolean,\n): AppPageHeadSource[] {\n const metadataSources: AppPageHeadSource[] = metadataResults.map((metadata, index) => ({\n routeSegments: routeSegments.slice(0, layoutTreePositions[index] ?? 0),\n metadata,\n }));\n\n if (includePageSource) {\n metadataSources.push({\n routeSegments,\n metadata: pageMetadata,\n });\n }\n\n return metadataSources;\n}\n\nfunction createLayoutInputs<TModule extends AppPageHeadModule>(\n layoutModules: readonly (TModule | null | undefined)[],\n layoutTreePositions: readonly number[],\n): AppPageHeadLayout<TModule>[] {\n const layoutInputs: AppPageHeadLayout<TModule>[] = [];\n\n for (let index = 0; index < layoutModules.length; index++) {\n const layoutModule = layoutModules[index];\n if (!isPresent(layoutModule)) {\n continue;\n }\n layoutInputs.push({\n module: layoutModule,\n treePosition: layoutTreePositions[index] ?? 0,\n });\n }\n\n return layoutInputs;\n}\n\nasync function resolveLayoutMetadata<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Metadata | null)[]> {\n const layoutMetadataPromises: Promise<Metadata | null>[] = [];\n let accumulatedMetadata = Promise.resolve<Metadata>({});\n\n for (const layoutInput of layoutInputs) {\n const parentForLayout = accumulatedMetadata;\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n const metadataPromise = resolveModuleMetadata(\n layoutInput.module,\n layoutParams,\n undefined,\n parentForLayout,\n );\n layoutMetadataPromises.push(metadataPromise);\n void metadataPromise.catch(() => null);\n\n accumulatedMetadata = metadataPromise.then(async (metadataResult) => {\n if (metadataResult) {\n return mergeMetadataEntries([\n { metadata: await parentForLayout },\n { metadata: metadataResult },\n ]);\n }\n return parentForLayout;\n });\n void accumulatedMetadata.catch(() => null);\n }\n\n return Promise.all(layoutMetadataPromises);\n}\n\nasync function resolveLayoutViewport<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Viewport | null)[]> {\n return Promise.all(\n layoutInputs.map((layoutInput) => {\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n return resolveModuleViewport(layoutInput.module, layoutParams);\n }),\n );\n}\n\nasync function resolveParallelRouteHead<TModule extends AppPageHeadModule>(\n parallelRoute: AppPageHeadParallelRoute<TModule>,\n fallbackParams: AppPageParams,\n fallbackRouteSegments: readonly string[],\n pageSearchParams: AppPageSearchParams,\n parent: Promise<Metadata>,\n): Promise<ResolvedParallelRouteHead> {\n const params = parallelRoute.params ?? fallbackParams;\n const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;\n const metadataResults: (Metadata | null)[] = [];\n const viewportResults: (Viewport | null)[] = [];\n const metadataSources: AppPageHeadSource[] = [];\n let accumulatedMetadata = parent;\n const layoutModules = [...(parallelRoute.layoutModules ?? []), parallelRoute.layoutModule].filter(\n isPresent,\n );\n const layoutViewportPromises = layoutModules.map((layoutModule) =>\n resolveModuleViewport(layoutModule, params),\n );\n const pageViewportPromise = parallelRoute.pageModule\n ? resolveModuleViewport(parallelRoute.pageModule, params)\n : Promise.resolve(null);\n for (const layoutViewportPromise of layoutViewportPromises) {\n void layoutViewportPromise.catch(() => null);\n }\n void pageViewportPromise.catch(() => null);\n\n for (const layoutModule of layoutModules) {\n const layoutMetadata = await resolveModuleMetadata(\n layoutModule,\n params,\n undefined,\n accumulatedMetadata,\n );\n metadataResults.push(layoutMetadata);\n // Parallel route metadata sources are scoped to the active slot branch because\n // the route tree input does not carry per-layout segment positions inside that branch.\n metadataSources.push({ metadata: layoutMetadata, routeSegments });\n if (layoutMetadata) {\n const parentForLayout = accumulatedMetadata;\n accumulatedMetadata = parentForLayout.then(async (parentMetadata) =>\n mergeMetadataEntries([{ metadata: parentMetadata }, { metadata: layoutMetadata }]),\n );\n void accumulatedMetadata.catch(() => null);\n }\n }\n\n if (parallelRoute.pageModule) {\n const pageMetadata = await resolveModuleMetadata(\n parallelRoute.pageModule,\n params,\n pageSearchParams,\n accumulatedMetadata,\n );\n metadataResults.push(pageMetadata);\n // Keep the page source scoped to the same active slot branch as its layouts.\n metadataSources.push({ metadata: pageMetadata, routeSegments });\n }\n\n viewportResults.push(...(await Promise.all(layoutViewportPromises)));\n const pageViewport = await pageViewportPromise;\n if (parallelRoute.pageModule) {\n viewportResults.push(pageViewport);\n }\n\n return { metadataResults, metadataSources, viewportResults };\n}\n\nexport async function resolveAppPageHead<TModule extends AppPageHeadModule>(\n options: ResolveAppPageHeadOptions<TModule>,\n): Promise<ResolveAppPageHeadResult> {\n const routeSegments = options.routeSegments ?? [];\n const layoutTreePositions = options.layoutTreePositions ?? [];\n const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);\n const layoutSourcePositions = layoutInputs.map((input) => input.treePosition);\n const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);\n const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);\n const layoutViewportPromise = resolveLayoutViewport(layoutInputs, options.params, routeSegments);\n\n const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) =>\n metadataResults.filter(isPresent),\n );\n void layoutMetadataResultsForParent.catch(() => null);\n const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) =>\n metadataResults.length > 0\n ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata })))\n : {},\n );\n void pageParentPromise.catch(() => null);\n const pageMetadataPromise = options.pageModule\n ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise)\n : Promise.resolve(null);\n const pageViewportPromise = options.pageModule\n ? resolveModuleViewport(options.pageModule, options.params)\n : Promise.resolve(null);\n const parallelRouteHeadPromise = Promise.all(\n (options.parallelRoutes ?? []).map((parallelRoute) =>\n resolveParallelRouteHead(\n parallelRoute,\n options.params,\n routeSegments,\n pageSearchParams,\n pageParentPromise,\n ),\n ),\n );\n\n const [\n layoutMetadataResults,\n layoutViewportResults,\n pageMetadata,\n pageViewport,\n parallelRouteHeads,\n ] = await Promise.all([\n layoutMetadataPromise,\n layoutViewportPromise,\n pageMetadataPromise,\n pageViewportPromise,\n parallelRouteHeadPromise,\n ]);\n const parallelMetadataResults = parallelRouteHeads.flatMap((head) => head.metadataResults);\n const parallelViewportResults = parallelRouteHeads.flatMap((head) => head.viewportResults);\n const parallelMetadataSources = parallelRouteHeads.flatMap((head) => head.metadataSources);\n\n const metadataEntries: MetadataMergeEntry[] = [\n ...layoutMetadataResults.filter(isPresent).map((metadata) => ({ metadata })),\n ...(pageMetadata ? [{ isPage: true, metadata: pageMetadata }] : []),\n ...parallelMetadataResults\n .filter(isPresent)\n .map((metadata) => ({ contributesTitle: false, metadata })),\n ];\n const viewportList = [\n ...layoutViewportResults.filter(isPresent),\n ...(pageViewport ? [pageViewport] : []),\n ...parallelViewportResults.filter(isPresent),\n ];\n\n const resolvedMetadataBase =\n metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;\n const metadataSources = createMetadataSources(\n layoutMetadataResults,\n routeSegments,\n layoutSourcePositions,\n pageMetadata,\n Boolean(options.pageModule),\n );\n metadataSources.push(...parallelMetadataSources);\n let metadata = resolvedMetadataBase;\n\n try {\n metadata = await applyFileBasedMetadata(\n resolvedMetadataBase,\n options.routePath,\n options.params,\n options.metadataRoutes,\n {\n routeSegments,\n metadataSources,\n },\n );\n } catch (error) {\n if (!options.fallbackOnFileMetadataError) {\n throw error;\n }\n console.error(\n `[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`,\n error,\n );\n }\n\n return {\n hasSearchParams,\n metadata,\n pageSearchParams,\n viewport: mergeViewport(viewportList),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-page-head.js","names":[],"sources":["../../src/server/app-page-head.ts"],"sourcesContent":["import {\n mergeMetadataEntries,\n mergeViewport,\n postProcessMetadata,\n resolveModuleMetadata,\n resolveModuleViewport,\n type Metadata,\n type MetadataMergeEntry,\n type Viewport,\n} from \"vinext/shims/metadata\";\nimport { applyFileBasedMetadata } from \"./file-based-metadata.js\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\n\ntype AppPageSearchParams = Record<string, string | string[]>;\n\ntype AppPageHeadModule = Record<string, unknown>;\n\ntype AppPageHeadSource = {\n metadata: Metadata | null;\n routeSegments: readonly string[];\n};\n\ntype AppPageHeadLayout<TModule extends AppPageHeadModule> = {\n module: TModule;\n treePosition: number;\n};\n\ntype AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layoutModule?: TModule | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n pageModule?: TModule | null;\n params?: AppPageParams | null;\n routeSegments?: readonly string[] | null;\n};\n\ntype AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layout?: TModule | null;\n page?: TModule | null;\n};\n\ntype ResolveActiveParallelRouteHeadInputsOptions<\n TModule extends AppPageHeadModule = AppPageHeadModule,\n> = {\n interceptLayouts?: readonly (TModule | null | undefined)[] | null;\n interceptPage?: TModule | null;\n interceptParams?: AppPageParams | null;\n interceptSlotKey?: string | null;\n params: AppPageParams;\n routeSegments: readonly string[];\n slots?: Record<string, AppPageHeadSlot<TModule>> | null;\n};\n\ntype ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n fallbackOnFileMetadataError?: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n metadataRoutes: readonly MetadataFileRoute[];\n pageModule?: TModule | null;\n parallelRoutes?: readonly AppPageHeadParallelRoute<TModule>[] | null;\n params: AppPageParams;\n routePath: string;\n routeSegments?: readonly string[] | null;\n searchParams?: URLSearchParams | null;\n};\n\ntype ResolveAppPageHeadResult = {\n hasSearchParams: boolean;\n metadata: Metadata | null;\n pageSearchParams: AppPageSearchParams;\n viewport: Viewport;\n};\n\ntype AppPageSearchParamsCollection = {\n hasSearchParams: boolean;\n pageSearchParams: AppPageSearchParams;\n};\n\ntype ResolvedParallelRouteHead = {\n metadataResults: (Metadata | null)[];\n metadataSources: AppPageHeadSource[];\n viewportResults: (Viewport | null)[];\n};\n\nexport function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(\n options: ResolveActiveParallelRouteHeadInputsOptions<TModule>,\n): AppPageHeadParallelRoute<TModule>[] {\n return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {\n if (options.interceptSlotKey === slotKey && options.interceptPage) {\n return {\n layoutModules: options.interceptLayouts ?? [],\n pageModule: options.interceptPage,\n params: options.interceptParams ?? options.params,\n routeSegments: options.routeSegments,\n };\n }\n\n return {\n layoutModules: slot.layout ? [slot.layout] : [],\n pageModule: slot.page,\n params: options.params,\n routeSegments: options.routeSegments,\n };\n });\n}\n\nfunction isPresent<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined;\n}\n\nexport function collectAppPageSearchParams(\n searchParams: URLSearchParams | null | undefined,\n): AppPageSearchParamsCollection {\n const pageSearchParams: AppPageSearchParams = Object.create(null);\n let hasSearchParams = false;\n\n searchParams?.forEach((value, key) => {\n hasSearchParams = true;\n const currentValue = pageSearchParams[key];\n if (Array.isArray(currentValue)) {\n pageSearchParams[key] = [...currentValue, value];\n return;\n }\n if (currentValue !== undefined) {\n pageSearchParams[key] = [currentValue, value];\n return;\n }\n pageSearchParams[key] = value;\n });\n\n return { hasSearchParams, pageSearchParams };\n}\n\nfunction createMetadataSources(\n metadataResults: readonly (Metadata | null)[],\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n pageMetadata: Metadata | null,\n includePageSource: boolean,\n): AppPageHeadSource[] {\n const metadataSources: AppPageHeadSource[] = metadataResults.map((metadata, index) => ({\n routeSegments: routeSegments.slice(0, layoutTreePositions[index] ?? 0),\n metadata,\n }));\n\n if (includePageSource) {\n metadataSources.push({\n routeSegments,\n metadata: pageMetadata,\n });\n }\n\n return metadataSources;\n}\n\nfunction createLayoutInputs<TModule extends AppPageHeadModule>(\n layoutModules: readonly (TModule | null | undefined)[],\n layoutTreePositions: readonly number[],\n): AppPageHeadLayout<TModule>[] {\n const layoutInputs: AppPageHeadLayout<TModule>[] = [];\n\n for (let index = 0; index < layoutModules.length; index++) {\n const layoutModule = layoutModules[index];\n if (!isPresent(layoutModule)) {\n continue;\n }\n layoutInputs.push({\n module: layoutModule,\n treePosition: layoutTreePositions[index] ?? 0,\n });\n }\n\n return layoutInputs;\n}\n\nasync function resolveLayoutMetadata<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Metadata | null)[]> {\n const layoutMetadataPromises: Promise<Metadata | null>[] = [];\n let accumulatedMetadata = Promise.resolve<Metadata>({});\n\n for (const layoutInput of layoutInputs) {\n const parentForLayout = accumulatedMetadata;\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n const metadataPromise = resolveModuleMetadata(\n layoutInput.module,\n layoutParams,\n undefined,\n parentForLayout,\n );\n layoutMetadataPromises.push(metadataPromise);\n void metadataPromise.catch(() => null);\n\n accumulatedMetadata = metadataPromise.then(async (metadataResult) => {\n if (metadataResult) {\n return mergeMetadataEntries([\n { metadata: await parentForLayout },\n { metadata: metadataResult },\n ]);\n }\n return parentForLayout;\n });\n void accumulatedMetadata.catch(() => null);\n }\n\n return Promise.all(layoutMetadataPromises);\n}\n\nasync function resolveLayoutViewport<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Viewport | null)[]> {\n return Promise.all(\n layoutInputs.map((layoutInput) => {\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n return resolveModuleViewport(layoutInput.module, layoutParams);\n }),\n );\n}\n\nasync function resolveParallelRouteHead<TModule extends AppPageHeadModule>(\n parallelRoute: AppPageHeadParallelRoute<TModule>,\n fallbackParams: AppPageParams,\n fallbackRouteSegments: readonly string[],\n pageSearchParams: AppPageSearchParams,\n parent: Promise<Metadata>,\n): Promise<ResolvedParallelRouteHead> {\n const params = parallelRoute.params ?? fallbackParams;\n const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;\n const metadataResults: (Metadata | null)[] = [];\n const viewportResults: (Viewport | null)[] = [];\n const metadataSources: AppPageHeadSource[] = [];\n let accumulatedMetadata = parent;\n const layoutModules = [...(parallelRoute.layoutModules ?? []), parallelRoute.layoutModule].filter(\n isPresent,\n );\n const layoutViewportPromises = layoutModules.map((layoutModule) =>\n resolveModuleViewport(layoutModule, params),\n );\n const pageViewportPromise = parallelRoute.pageModule\n ? resolveModuleViewport(parallelRoute.pageModule, params)\n : Promise.resolve(null);\n for (const layoutViewportPromise of layoutViewportPromises) {\n void layoutViewportPromise.catch(() => null);\n }\n void pageViewportPromise.catch(() => null);\n\n for (const layoutModule of layoutModules) {\n const layoutMetadata = await resolveModuleMetadata(\n layoutModule,\n params,\n undefined,\n accumulatedMetadata,\n );\n metadataResults.push(layoutMetadata);\n // Parallel route metadata sources are scoped to the active slot branch because\n // the route tree input does not carry per-layout segment positions inside that branch.\n metadataSources.push({ metadata: layoutMetadata, routeSegments });\n if (layoutMetadata) {\n const parentForLayout = accumulatedMetadata;\n accumulatedMetadata = parentForLayout.then(async (parentMetadata) =>\n mergeMetadataEntries([{ metadata: parentMetadata }, { metadata: layoutMetadata }]),\n );\n void accumulatedMetadata.catch(() => null);\n }\n }\n\n if (parallelRoute.pageModule) {\n const pageMetadata = await resolveModuleMetadata(\n parallelRoute.pageModule,\n params,\n pageSearchParams,\n accumulatedMetadata,\n );\n metadataResults.push(pageMetadata);\n // Keep the page source scoped to the same active slot branch as its layouts.\n metadataSources.push({ metadata: pageMetadata, routeSegments });\n }\n\n viewportResults.push(...(await Promise.all(layoutViewportPromises)));\n const pageViewport = await pageViewportPromise;\n if (parallelRoute.pageModule) {\n viewportResults.push(pageViewport);\n }\n\n return { metadataResults, metadataSources, viewportResults };\n}\n\nexport async function resolveAppPageHead<TModule extends AppPageHeadModule>(\n options: ResolveAppPageHeadOptions<TModule>,\n): Promise<ResolveAppPageHeadResult> {\n const routeSegments = options.routeSegments ?? [];\n const layoutTreePositions = options.layoutTreePositions ?? [];\n const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);\n const layoutSourcePositions = layoutInputs.map((input) => input.treePosition);\n const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);\n const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);\n const layoutViewportPromise = resolveLayoutViewport(layoutInputs, options.params, routeSegments);\n\n const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) =>\n metadataResults.filter(isPresent),\n );\n void layoutMetadataResultsForParent.catch(() => null);\n const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) =>\n metadataResults.length > 0\n ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata })))\n : {},\n );\n void pageParentPromise.catch(() => null);\n const pageMetadataPromise = options.pageModule\n ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise)\n : Promise.resolve(null);\n const pageViewportPromise = options.pageModule\n ? resolveModuleViewport(options.pageModule, options.params)\n : Promise.resolve(null);\n const parallelRouteHeadPromise = Promise.all(\n (options.parallelRoutes ?? []).map((parallelRoute) =>\n resolveParallelRouteHead(\n parallelRoute,\n options.params,\n routeSegments,\n pageSearchParams,\n pageParentPromise,\n ),\n ),\n );\n\n const [\n layoutMetadataResults,\n layoutViewportResults,\n pageMetadata,\n pageViewport,\n parallelRouteHeads,\n ] = await Promise.all([\n layoutMetadataPromise,\n layoutViewportPromise,\n pageMetadataPromise,\n pageViewportPromise,\n parallelRouteHeadPromise,\n ]);\n const parallelMetadataResults = parallelRouteHeads.flatMap((head) => head.metadataResults);\n const parallelViewportResults = parallelRouteHeads.flatMap((head) => head.viewportResults);\n const parallelMetadataSources = parallelRouteHeads.flatMap((head) => head.metadataSources);\n\n const metadataEntries: MetadataMergeEntry[] = [\n ...layoutMetadataResults.filter(isPresent).map((metadata) => ({ metadata })),\n ...(pageMetadata ? [{ isPage: true, metadata: pageMetadata }] : []),\n ...parallelMetadataResults\n .filter(isPresent)\n .map((metadata) => ({ contributesTitle: false, metadata })),\n ];\n const viewportList = [\n ...layoutViewportResults.filter(isPresent),\n ...(pageViewport ? [pageViewport] : []),\n ...parallelViewportResults.filter(isPresent),\n ];\n\n const resolvedMetadataBase =\n metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;\n const metadataSources = createMetadataSources(\n layoutMetadataResults,\n routeSegments,\n layoutSourcePositions,\n pageMetadata,\n Boolean(options.pageModule),\n );\n metadataSources.push(...parallelMetadataSources);\n let metadata = resolvedMetadataBase;\n\n try {\n metadata = await applyFileBasedMetadata(\n resolvedMetadataBase,\n options.routePath,\n options.params,\n options.metadataRoutes,\n {\n routeSegments,\n metadataSources,\n },\n );\n } catch (error) {\n if (!options.fallbackOnFileMetadataError) {\n throw error;\n }\n console.error(\n `[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`,\n error,\n );\n }\n\n if (metadata) {\n metadata = postProcessMetadata(metadata);\n }\n\n return {\n hasSearchParams,\n metadata,\n pageSearchParams,\n viewport: mergeViewport(viewportList),\n };\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { methodNotAllowedResponse } from "./http-error-responses.js";
1
2
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
2
3
  import { isPossibleAppRouteActionRequest } from "./app-route-handler-policy.js";
3
4
  //#region src/server/app-page-method.ts
@@ -18,11 +19,7 @@ function resolveAppPageMethodResponse(options) {
18
19
  if (!isStaticOrSsgAppPageCandidate(options)) return null;
19
20
  const headers = new Headers();
20
21
  mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
21
- headers.set("Allow", "GET, HEAD");
22
- return new Response("Method Not Allowed", {
23
- headers,
24
- status: 405
25
- });
22
+ return methodNotAllowedResponse("GET, HEAD", { headers });
26
23
  }
27
24
  //#endregion
28
25
  export { isStaticOrSsgAppPageCandidate, resolveAppPageMethodResponse };
@@ -1 +1 @@
1
- {"version":3,"file":"app-page-method.js","names":[],"sources":["../../src/server/app-page-method.ts"],"sourcesContent":["import { isPossibleAppRouteActionRequest } from \"./app-route-handler-policy.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\ntype AppPageMethodPolicyOptions = {\n dynamicConfig?: string;\n hasGenerateStaticParams: boolean;\n isDynamicRoute: boolean;\n revalidateSeconds: number | null;\n};\n\ntype ResolveAppPageMethodResponseOptions = {\n middlewareHeaders?: Headers | null;\n request: Pick<Request, \"headers\" | \"method\">;\n} & AppPageMethodPolicyOptions;\n\nfunction isNonGetOrHead(method: string): boolean {\n const normalizedMethod = method.toUpperCase();\n return normalizedMethod !== \"GET\" && normalizedMethod !== \"HEAD\";\n}\n\nexport function isStaticOrSsgAppPageCandidate(options: AppPageMethodPolicyOptions): boolean {\n if (options.dynamicConfig === \"force-dynamic\" || options.revalidateSeconds === 0) {\n return false;\n }\n\n if (options.dynamicConfig === \"force-static\" || options.dynamicConfig === \"error\") {\n return true;\n }\n\n if (options.revalidateSeconds !== null && options.revalidateSeconds > 0) {\n return true;\n }\n\n if (options.hasGenerateStaticParams) {\n return true;\n }\n\n return !options.isDynamicRoute;\n}\n\nexport function resolveAppPageMethodResponse(\n options: ResolveAppPageMethodResponseOptions,\n): Response | null {\n if (!isNonGetOrHead(options.request.method)) {\n return null;\n }\n\n if (isPossibleAppRouteActionRequest(options.request)) {\n return null;\n }\n\n if (!isStaticOrSsgAppPageCandidate(options)) {\n return null;\n }\n\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n headers.set(\"Allow\", \"GET, HEAD\");\n\n return new Response(\"Method Not Allowed\", {\n headers,\n status: 405,\n });\n}\n"],"mappings":";;;AAeA,SAAS,eAAe,QAAyB;CAC/C,MAAM,mBAAmB,OAAO,aAAa;AAC7C,QAAO,qBAAqB,SAAS,qBAAqB;;AAG5D,SAAgB,8BAA8B,SAA8C;AAC1F,KAAI,QAAQ,kBAAkB,mBAAmB,QAAQ,sBAAsB,EAC7E,QAAO;AAGT,KAAI,QAAQ,kBAAkB,kBAAkB,QAAQ,kBAAkB,QACxE,QAAO;AAGT,KAAI,QAAQ,sBAAsB,QAAQ,QAAQ,oBAAoB,EACpE,QAAO;AAGT,KAAI,QAAQ,wBACV,QAAO;AAGT,QAAO,CAAC,QAAQ;;AAGlB,SAAgB,6BACd,SACiB;AACjB,KAAI,CAAC,eAAe,QAAQ,QAAQ,OAAO,CACzC,QAAO;AAGT,KAAI,gCAAgC,QAAQ,QAAQ,CAClD,QAAO;AAGT,KAAI,CAAC,8BAA8B,QAAQ,CACzC,QAAO;CAGT,MAAM,UAAU,IAAI,SAAS;AAC7B,gCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAC1E,SAAQ,IAAI,SAAS,YAAY;AAEjC,QAAO,IAAI,SAAS,sBAAsB;EACxC;EACA,QAAQ;EACT,CAAC"}
1
+ {"version":3,"file":"app-page-method.js","names":[],"sources":["../../src/server/app-page-method.ts"],"sourcesContent":["import { isPossibleAppRouteActionRequest } from \"./app-route-handler-policy.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { methodNotAllowedResponse } from \"./http-error-responses.js\";\n\ntype AppPageMethodPolicyOptions = {\n dynamicConfig?: string;\n hasGenerateStaticParams: boolean;\n isDynamicRoute: boolean;\n revalidateSeconds: number | null;\n};\n\ntype ResolveAppPageMethodResponseOptions = {\n middlewareHeaders?: Headers | null;\n request: Pick<Request, \"headers\" | \"method\">;\n} & AppPageMethodPolicyOptions;\n\nfunction isNonGetOrHead(method: string): boolean {\n const normalizedMethod = method.toUpperCase();\n return normalizedMethod !== \"GET\" && normalizedMethod !== \"HEAD\";\n}\n\nexport function isStaticOrSsgAppPageCandidate(options: AppPageMethodPolicyOptions): boolean {\n if (options.dynamicConfig === \"force-dynamic\" || options.revalidateSeconds === 0) {\n return false;\n }\n\n if (options.dynamicConfig === \"force-static\" || options.dynamicConfig === \"error\") {\n return true;\n }\n\n if (options.revalidateSeconds !== null && options.revalidateSeconds > 0) {\n return true;\n }\n\n if (options.hasGenerateStaticParams) {\n return true;\n }\n\n return !options.isDynamicRoute;\n}\n\nexport function resolveAppPageMethodResponse(\n options: ResolveAppPageMethodResponseOptions,\n): Response | null {\n if (!isNonGetOrHead(options.request.method)) {\n return null;\n }\n\n if (isPossibleAppRouteActionRequest(options.request)) {\n return null;\n }\n\n if (!isStaticOrSsgAppPageCandidate(options)) {\n return null;\n }\n\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return methodNotAllowedResponse(\"GET, HEAD\", { headers });\n}\n"],"mappings":";;;;AAgBA,SAAS,eAAe,QAAyB;CAC/C,MAAM,mBAAmB,OAAO,aAAa;AAC7C,QAAO,qBAAqB,SAAS,qBAAqB;;AAG5D,SAAgB,8BAA8B,SAA8C;AAC1F,KAAI,QAAQ,kBAAkB,mBAAmB,QAAQ,sBAAsB,EAC7E,QAAO;AAGT,KAAI,QAAQ,kBAAkB,kBAAkB,QAAQ,kBAAkB,QACxE,QAAO;AAGT,KAAI,QAAQ,sBAAsB,QAAQ,QAAQ,oBAAoB,EACpE,QAAO;AAGT,KAAI,QAAQ,wBACV,QAAO;AAGT,QAAO,CAAC,QAAQ;;AAGlB,SAAgB,6BACd,SACiB;AACjB,KAAI,CAAC,eAAe,QAAQ,QAAQ,OAAO,CACzC,QAAO;AAGT,KAAI,gCAAgC,QAAQ,QAAQ,CAClD,QAAO;AAGT,KAAI,CAAC,8BAA8B,QAAQ,CACzC,QAAO;CAGT,MAAM,UAAU,IAAI,SAAS;AAC7B,gCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAE1E,QAAO,yBAAyB,aAAa,EAAE,SAAS,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { AppPageParams } from "./app-page-boundary.js";
2
2
 
3
3
  //#region src/server/app-page-params.d.ts
4
+ declare function getAppPageSegmentParamName(segment: string): string | null;
4
5
  declare function resolveAppPageSegmentParams(routeSegments: readonly string[] | null | undefined, treePosition: number, matchedParams: AppPageParams): AppPageParams;
5
6
  //#endregion
6
- export { resolveAppPageSegmentParams };
7
+ export { getAppPageSegmentParamName, resolveAppPageSegmentParams };
7
8
  //# sourceMappingURL=app-page-params.d.ts.map