vinext 0.0.48 → 0.0.50

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 (396) hide show
  1. package/dist/build/client-build-config.js.map +1 -1
  2. package/dist/build/google-fonts/build-url.js.map +1 -1
  3. package/dist/build/google-fonts/get-axes.js.map +1 -1
  4. package/dist/build/google-fonts/sort-variants.js.map +1 -1
  5. package/dist/build/google-fonts/validate.js.map +1 -1
  6. package/dist/build/layout-classification.js.map +1 -1
  7. package/dist/build/nitro-route-rules.js.map +1 -1
  8. package/dist/build/precompress.js.map +1 -1
  9. package/dist/build/prerender.d.ts +17 -1
  10. package/dist/build/prerender.js +77 -16
  11. package/dist/build/prerender.js.map +1 -1
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/route-classification-injector.js.map +1 -1
  14. package/dist/build/route-classification-manifest.js.map +1 -1
  15. package/dist/build/run-prerender.js.map +1 -1
  16. package/dist/build/server-manifest.js.map +1 -1
  17. package/dist/build/ssr-manifest.js.map +1 -1
  18. package/dist/build/standalone.js.map +1 -1
  19. package/dist/build/static-export.js.map +1 -1
  20. package/dist/check.js +1 -1
  21. package/dist/check.js.map +1 -1
  22. package/dist/cli-args.js.map +1 -1
  23. package/dist/cli.js +8 -4
  24. package/dist/cli.js.map +1 -1
  25. package/dist/client/instrumentation-client-state.js.map +1 -1
  26. package/dist/client/validate-module-path.js.map +1 -1
  27. package/dist/client/vinext-next-data.d.ts +5 -1
  28. package/dist/client/window-next.d.ts +149 -0
  29. package/dist/client/window-next.js +48 -0
  30. package/dist/client/window-next.js.map +1 -0
  31. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  32. package/dist/cloudflare/tpr.js +2 -1
  33. package/dist/cloudflare/tpr.js.map +1 -1
  34. package/dist/config/config-matchers.d.ts +3 -1
  35. package/dist/config/config-matchers.js +5 -4
  36. package/dist/config/config-matchers.js.map +1 -1
  37. package/dist/config/dotenv.js.map +1 -1
  38. package/dist/config/next-config.d.ts +6 -3
  39. package/dist/config/next-config.js +13 -2
  40. package/dist/config/next-config.js.map +1 -1
  41. package/dist/deploy.js +13 -5
  42. package/dist/deploy.js.map +1 -1
  43. package/dist/entries/app-browser-entry.d.ts +3 -1
  44. package/dist/entries/app-browser-entry.js +11 -2
  45. package/dist/entries/app-browser-entry.js.map +1 -1
  46. package/dist/entries/app-rsc-entry.js +11 -0
  47. package/dist/entries/app-rsc-entry.js.map +1 -1
  48. package/dist/entries/app-rsc-manifest.js +4 -0
  49. package/dist/entries/app-rsc-manifest.js.map +1 -1
  50. package/dist/entries/app-ssr-entry.js.map +1 -1
  51. package/dist/entries/pages-client-entry.js.map +1 -1
  52. package/dist/entries/pages-entry-helpers.js.map +1 -1
  53. package/dist/entries/pages-server-entry.js +22 -3
  54. package/dist/entries/pages-server-entry.js.map +1 -1
  55. package/dist/entries/runtime-entry-module.js.map +1 -1
  56. package/dist/index.js +76 -18
  57. package/dist/index.js.map +1 -1
  58. package/dist/init.d.ts +1 -1
  59. package/dist/init.js +2 -2
  60. package/dist/init.js.map +1 -1
  61. package/dist/plugins/async-hooks-stub.js.map +1 -1
  62. package/dist/plugins/client-reference-dedup.js.map +1 -1
  63. package/dist/plugins/fonts.js.map +1 -1
  64. package/dist/plugins/instrumentation-client.js.map +1 -1
  65. package/dist/plugins/og-assets.js.map +1 -1
  66. package/dist/plugins/optimize-imports.js.map +1 -1
  67. package/dist/plugins/postcss.js.map +1 -1
  68. package/dist/plugins/rsc-client-reference-loaders.d.ts +7 -0
  69. package/dist/plugins/rsc-client-reference-loaders.js +48 -0
  70. package/dist/plugins/rsc-client-reference-loaders.js.map +1 -0
  71. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  72. package/dist/plugins/server-externals-manifest.js.map +1 -1
  73. package/dist/plugins/strip-server-exports.js.map +1 -1
  74. package/dist/routing/app-route-graph.d.ts +48 -5
  75. package/dist/routing/app-route-graph.js +159 -15
  76. package/dist/routing/app-route-graph.js.map +1 -1
  77. package/dist/routing/app-router.js.map +1 -1
  78. package/dist/routing/file-matcher.js.map +1 -1
  79. package/dist/routing/pages-router.js.map +1 -1
  80. package/dist/routing/route-matching.js.map +1 -1
  81. package/dist/routing/route-pattern.js.map +1 -1
  82. package/dist/routing/route-trie.js.map +1 -1
  83. package/dist/routing/route-validation.js.map +1 -1
  84. package/dist/routing/utils.js.map +1 -1
  85. package/dist/server/api-handler.js +2 -8
  86. package/dist/server/api-handler.js.map +1 -1
  87. package/dist/server/app-browser-action-result.d.ts +19 -0
  88. package/dist/server/app-browser-action-result.js +18 -0
  89. package/dist/server/app-browser-action-result.js.map +1 -0
  90. package/dist/server/app-browser-entry.js +91 -48
  91. package/dist/server/app-browser-entry.js.map +1 -1
  92. package/dist/server/app-browser-error.js.map +1 -1
  93. package/dist/server/app-browser-hydration.d.ts +19 -0
  94. package/dist/server/app-browser-hydration.js +22 -0
  95. package/dist/server/app-browser-hydration.js.map +1 -0
  96. package/dist/server/app-browser-navigation-controller.d.ts +6 -3
  97. package/dist/server/app-browser-navigation-controller.js +67 -19
  98. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  99. package/dist/server/app-browser-state.d.ts +17 -17
  100. package/dist/server/app-browser-state.js +122 -36
  101. package/dist/server/app-browser-state.js.map +1 -1
  102. package/dist/server/app-browser-stream.d.ts +4 -0
  103. package/dist/server/app-browser-stream.js +24 -2
  104. package/dist/server/app-browser-stream.js.map +1 -1
  105. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  106. package/dist/server/app-browser-visible-commit.js +34 -19
  107. package/dist/server/app-browser-visible-commit.js.map +1 -1
  108. package/dist/server/app-client-reference-preloader.js.map +1 -1
  109. package/dist/server/app-elements-wire.d.ts +6 -1
  110. package/dist/server/app-elements-wire.js +17 -1
  111. package/dist/server/app-elements-wire.js.map +1 -1
  112. package/dist/server/app-elements.d.ts +2 -2
  113. package/dist/server/app-elements.js +2 -2
  114. package/dist/server/app-elements.js.map +1 -1
  115. package/dist/server/app-fallback-renderer.js.map +1 -1
  116. package/dist/server/app-hook-warning-suppression.js.map +1 -1
  117. package/dist/server/app-middleware.d.ts +1 -1
  118. package/dist/server/app-middleware.js +4 -9
  119. package/dist/server/app-middleware.js.map +1 -1
  120. package/dist/server/app-mounted-slots-header.js.map +1 -1
  121. package/dist/server/app-page-boundary-render.d.ts +1 -0
  122. package/dist/server/app-page-boundary-render.js +14 -13
  123. package/dist/server/app-page-boundary-render.js.map +1 -1
  124. package/dist/server/app-page-boundary.d.ts +1 -0
  125. package/dist/server/app-page-boundary.js +7 -5
  126. package/dist/server/app-page-boundary.js.map +1 -1
  127. package/dist/server/app-page-cache.d.ts +10 -3
  128. package/dist/server/app-page-cache.js +42 -23
  129. package/dist/server/app-page-cache.js.map +1 -1
  130. package/dist/server/app-page-dispatch.d.ts +6 -1
  131. package/dist/server/app-page-dispatch.js +21 -7
  132. package/dist/server/app-page-dispatch.js.map +1 -1
  133. package/dist/server/app-page-element-builder.d.ts +3 -1
  134. package/dist/server/app-page-element-builder.js +6 -2
  135. package/dist/server/app-page-element-builder.js.map +1 -1
  136. package/dist/server/app-page-execution.js.map +1 -1
  137. package/dist/server/app-page-head.js +4 -0
  138. package/dist/server/app-page-head.js.map +1 -1
  139. package/dist/server/app-page-method.js.map +1 -1
  140. package/dist/server/app-page-params.js.map +1 -1
  141. package/dist/server/app-page-probe.js.map +1 -1
  142. package/dist/server/app-page-render.d.ts +7 -1
  143. package/dist/server/app-page-render.js +11 -4
  144. package/dist/server/app-page-render.js.map +1 -1
  145. package/dist/server/app-page-request.js +2 -1
  146. package/dist/server/app-page-request.js.map +1 -1
  147. package/dist/server/app-page-response.d.ts +2 -0
  148. package/dist/server/app-page-response.js +15 -5
  149. package/dist/server/app-page-response.js.map +1 -1
  150. package/dist/server/app-page-route-wiring.d.ts +6 -2
  151. package/dist/server/app-page-route-wiring.js +50 -49
  152. package/dist/server/app-page-route-wiring.js.map +1 -1
  153. package/dist/server/app-page-segment-state.d.ts +10 -0
  154. package/dist/server/app-page-segment-state.js +87 -0
  155. package/dist/server/app-page-segment-state.js.map +1 -0
  156. package/dist/server/app-page-stream.d.ts +7 -2
  157. package/dist/server/app-page-stream.js +3 -1
  158. package/dist/server/app-page-stream.js.map +1 -1
  159. package/dist/server/app-post-middleware-context.js.map +1 -1
  160. package/dist/server/app-prerender-endpoints.js.map +1 -1
  161. package/dist/server/app-prerender-static-params.js.map +1 -1
  162. package/dist/server/app-render-dependency.js.map +1 -1
  163. package/dist/server/app-request-context.js.map +1 -1
  164. package/dist/server/app-route-handler-cache.js.map +1 -1
  165. package/dist/server/app-route-handler-dispatch.js +3 -1
  166. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  167. package/dist/server/app-route-handler-execution.js.map +1 -1
  168. package/dist/server/app-route-handler-policy.js +1 -0
  169. package/dist/server/app-route-handler-policy.js.map +1 -1
  170. package/dist/server/app-route-handler-response.js +4 -3
  171. package/dist/server/app-route-handler-response.js.map +1 -1
  172. package/dist/server/app-route-handler-runtime.js.map +1 -1
  173. package/dist/server/app-router-entry.js +6 -2
  174. package/dist/server/app-router-entry.js.map +1 -1
  175. package/dist/server/app-rsc-cache-busting.d.ts +5 -2
  176. package/dist/server/app-rsc-cache-busting.js +40 -19
  177. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  178. package/dist/server/app-rsc-error-handler.js.map +1 -1
  179. package/dist/server/app-rsc-errors.js.map +1 -1
  180. package/dist/server/app-rsc-handler.d.ts +10 -1
  181. package/dist/server/app-rsc-handler.js +51 -17
  182. package/dist/server/app-rsc-handler.js.map +1 -1
  183. package/dist/server/app-rsc-render-mode.d.ts +11 -0
  184. package/dist/server/app-rsc-render-mode.js +21 -0
  185. package/dist/server/app-rsc-render-mode.js.map +1 -0
  186. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  187. package/dist/server/app-rsc-request-normalization.js +7 -2
  188. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  189. package/dist/server/app-rsc-response-finalizer.d.ts +2 -1
  190. package/dist/server/app-rsc-response-finalizer.js +6 -1
  191. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  192. package/dist/server/app-rsc-route-matching.js.map +1 -1
  193. package/dist/server/app-segment-config.js.map +1 -1
  194. package/dist/server/app-server-action-execution.d.ts +16 -2
  195. package/dist/server/app-server-action-execution.js +79 -23
  196. package/dist/server/app-server-action-execution.js.map +1 -1
  197. package/dist/server/app-ssr-entry.d.ts +6 -0
  198. package/dist/server/app-ssr-entry.js +10 -4
  199. package/dist/server/app-ssr-entry.js.map +1 -1
  200. package/dist/server/app-ssr-stream.js.map +1 -1
  201. package/dist/server/app-static-generation.js.map +1 -1
  202. package/dist/server/artifact-compatibility.js.map +1 -1
  203. package/dist/server/cache-control.js +1 -0
  204. package/dist/server/cache-control.js.map +1 -1
  205. package/dist/server/cache-proof.js.map +1 -1
  206. package/dist/server/csp.js.map +1 -1
  207. package/dist/server/dev-error-overlay-store.js.map +1 -1
  208. package/dist/server/dev-error-overlay.js +5 -0
  209. package/dist/server/dev-error-overlay.js.map +1 -1
  210. package/dist/server/dev-module-runner.js.map +1 -1
  211. package/dist/server/dev-origin-check.js.map +1 -1
  212. package/dist/server/dev-route-files.js.map +1 -1
  213. package/dist/server/dev-server.js +13 -15
  214. package/dist/server/dev-server.js.map +1 -1
  215. package/dist/server/file-based-metadata.js.map +1 -1
  216. package/dist/server/headers.d.ts +79 -0
  217. package/dist/server/headers.js +101 -0
  218. package/dist/server/headers.js.map +1 -0
  219. package/dist/server/html.js.map +1 -1
  220. package/dist/server/http-error-responses.js.map +1 -1
  221. package/dist/server/image-optimization.d.ts +11 -1
  222. package/dist/server/image-optimization.js.map +1 -1
  223. package/dist/server/implicit-tags.js +2 -1
  224. package/dist/server/implicit-tags.js.map +1 -1
  225. package/dist/server/instrumentation-runtime.js.map +1 -1
  226. package/dist/server/instrumentation.js.map +1 -1
  227. package/dist/server/isr-cache.d.ts +10 -1
  228. package/dist/server/isr-cache.js +12 -3
  229. package/dist/server/isr-cache.js.map +1 -1
  230. package/dist/server/metadata-route-build-data.js.map +1 -1
  231. package/dist/server/metadata-route-response.js.map +1 -1
  232. package/dist/server/metadata-routes.js.map +1 -1
  233. package/dist/server/middleware-matcher.js.map +1 -1
  234. package/dist/server/middleware-request-headers.d.ts +4 -1
  235. package/dist/server/middleware-request-headers.js +15 -8
  236. package/dist/server/middleware-request-headers.js.map +1 -1
  237. package/dist/server/middleware-response-headers.d.ts +2 -1
  238. package/dist/server/middleware-response-headers.js +1 -1
  239. package/dist/server/middleware-response-headers.js.map +1 -1
  240. package/dist/server/middleware-runtime.d.ts +1 -0
  241. package/dist/server/middleware-runtime.js +6 -3
  242. package/dist/server/middleware-runtime.js.map +1 -1
  243. package/dist/server/middleware.js.map +1 -1
  244. package/dist/server/navigation-planner.d.ts +119 -0
  245. package/dist/server/navigation-planner.js +171 -0
  246. package/dist/server/navigation-planner.js.map +1 -0
  247. package/dist/server/navigation-trace.d.ts +12 -2
  248. package/dist/server/navigation-trace.js +13 -1
  249. package/dist/server/navigation-trace.js.map +1 -1
  250. package/dist/server/next-error-digest.d.ts +3 -2
  251. package/dist/server/next-error-digest.js +4 -2
  252. package/dist/server/next-error-digest.js.map +1 -1
  253. package/dist/server/normalize-path.js.map +1 -1
  254. package/dist/server/pages-api-route.js +2 -6
  255. package/dist/server/pages-api-route.js.map +1 -1
  256. package/dist/server/pages-i18n.js.map +1 -1
  257. package/dist/server/pages-media-type.js.map +1 -1
  258. package/dist/server/pages-node-compat.js.map +1 -1
  259. package/dist/server/pages-page-data.js +5 -2
  260. package/dist/server/pages-page-data.js.map +1 -1
  261. package/dist/server/pages-page-response.js +3 -2
  262. package/dist/server/pages-page-response.js.map +1 -1
  263. package/dist/server/prerender-work-unit-setup.js +1 -1
  264. package/dist/server/prerender-work-unit-setup.js.map +1 -1
  265. package/dist/server/prod-server.js +35 -13
  266. package/dist/server/prod-server.js.map +1 -1
  267. package/dist/server/request-log.js.map +1 -1
  268. package/dist/server/request-pipeline.d.ts +1 -13
  269. package/dist/server/request-pipeline.js +3 -25
  270. package/dist/server/request-pipeline.js.map +1 -1
  271. package/dist/server/rsc-stream-hints.js.map +1 -1
  272. package/dist/server/seed-cache.js.map +1 -1
  273. package/dist/server/server-action-not-found.js +3 -3
  274. package/dist/server/server-action-not-found.js.map +1 -1
  275. package/dist/server/socket-error-backstop.js.map +1 -1
  276. package/dist/server/static-file-cache.js.map +1 -1
  277. package/dist/server/worker-utils.d.ts +0 -7
  278. package/dist/server/worker-utils.js +3 -2
  279. package/dist/server/worker-utils.js.map +1 -1
  280. package/dist/shims/amp.js.map +1 -1
  281. package/dist/shims/app.d.ts +37 -4
  282. package/dist/shims/app.js +50 -1
  283. package/dist/shims/app.js.map +1 -0
  284. package/dist/shims/cache-for-request.js.map +1 -1
  285. package/dist/shims/cache-runtime.js +20 -8
  286. package/dist/shims/cache-runtime.js.map +1 -1
  287. package/dist/shims/cache.d.ts +15 -3
  288. package/dist/shims/cache.js +99 -15
  289. package/dist/shims/cache.js.map +1 -1
  290. package/dist/shims/client-hook-error.js.map +1 -1
  291. package/dist/shims/compat-router.js.map +1 -1
  292. package/dist/shims/config.js.map +1 -1
  293. package/dist/shims/constants.js.map +1 -1
  294. package/dist/shims/document.js.map +1 -1
  295. package/dist/shims/dynamic.d.ts +18 -10
  296. package/dist/shims/dynamic.js +107 -51
  297. package/dist/shims/dynamic.js.map +1 -1
  298. package/dist/shims/error-boundary.d.ts +35 -6
  299. package/dist/shims/error-boundary.js +118 -33
  300. package/dist/shims/error-boundary.js.map +1 -1
  301. package/dist/shims/error.js.map +1 -1
  302. package/dist/shims/fetch-cache.d.ts +22 -1
  303. package/dist/shims/fetch-cache.js +124 -13
  304. package/dist/shims/fetch-cache.js.map +1 -1
  305. package/dist/shims/font-google-base.js.map +1 -1
  306. package/dist/shims/font-local.js.map +1 -1
  307. package/dist/shims/form.js +3 -1
  308. package/dist/shims/form.js.map +1 -1
  309. package/dist/shims/head-state.js.map +1 -1
  310. package/dist/shims/head.d.ts +3 -1
  311. package/dist/shims/head.js +28 -16
  312. package/dist/shims/head.js.map +1 -1
  313. package/dist/shims/headers.d.ts +4 -2
  314. package/dist/shims/headers.js +24 -7
  315. package/dist/shims/headers.js.map +1 -1
  316. package/dist/shims/i18n-context.js.map +1 -1
  317. package/dist/shims/i18n-state.js.map +1 -1
  318. package/dist/shims/image-config.d.ts +14 -1
  319. package/dist/shims/image-config.js +24 -1
  320. package/dist/shims/image-config.js.map +1 -1
  321. package/dist/shims/image.js +15 -2
  322. package/dist/shims/image.js.map +1 -1
  323. package/dist/shims/internal/als-registry.js.map +1 -1
  324. package/dist/shims/internal/app-router-context.d.ts +1 -0
  325. package/dist/shims/internal/app-router-context.js.map +1 -1
  326. package/dist/shims/internal/cookie-serialize.js.map +1 -1
  327. package/dist/shims/internal/make-hanging-promise.d.ts +1 -1
  328. package/dist/shims/internal/make-hanging-promise.js +1 -1
  329. package/dist/shims/internal/make-hanging-promise.js.map +1 -1
  330. package/dist/shims/internal/parse-cookie-header.js.map +1 -1
  331. package/dist/shims/internal/utils.js.map +1 -1
  332. package/dist/shims/internal/work-unit-async-storage.js +2 -2
  333. package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
  334. package/dist/shims/layout-segment-context.js.map +1 -1
  335. package/dist/shims/legacy-image.js.map +1 -1
  336. package/dist/shims/link-prefetch.d.ts +34 -0
  337. package/dist/shims/link-prefetch.js +40 -0
  338. package/dist/shims/link-prefetch.js.map +1 -0
  339. package/dist/shims/link.d.ts +27 -4
  340. package/dist/shims/link.js +91 -27
  341. package/dist/shims/link.js.map +1 -1
  342. package/dist/shims/metadata.js.map +1 -1
  343. package/dist/shims/navigation-state.js.map +1 -1
  344. package/dist/shims/navigation.d.ts +22 -1
  345. package/dist/shims/navigation.js +30 -15
  346. package/dist/shims/navigation.js.map +1 -1
  347. package/dist/shims/navigation.react-server.js.map +1 -1
  348. package/dist/shims/offline.js.map +1 -1
  349. package/dist/shims/readonly-url-search-params.js.map +1 -1
  350. package/dist/shims/request-context.js.map +1 -1
  351. package/dist/shims/root-params.js.map +1 -1
  352. package/dist/shims/router-state.js.map +1 -1
  353. package/dist/shims/router.d.ts +38 -2
  354. package/dist/shims/router.js +45 -17
  355. package/dist/shims/router.js.map +1 -1
  356. package/dist/shims/script-nonce-context.js.map +1 -1
  357. package/dist/shims/script.js.map +1 -1
  358. package/dist/shims/server.js +10 -14
  359. package/dist/shims/server.js.map +1 -1
  360. package/dist/shims/slot.d.ts +6 -1
  361. package/dist/shims/slot.js +20 -7
  362. package/dist/shims/slot.js.map +1 -1
  363. package/dist/shims/thenable-params.js.map +1 -1
  364. package/dist/shims/unified-request-context.js +3 -0
  365. package/dist/shims/unified-request-context.js.map +1 -1
  366. package/dist/shims/url-safety.js.map +1 -1
  367. package/dist/shims/url-utils.d.ts +2 -1
  368. package/dist/shims/url-utils.js +10 -1
  369. package/dist/shims/url-utils.js.map +1 -1
  370. package/dist/shims/use-merged-ref.js.map +1 -1
  371. package/dist/shims/web-vitals.d.ts +4 -21
  372. package/dist/shims/web-vitals.js +19 -6
  373. package/dist/shims/web-vitals.js.map +1 -1
  374. package/dist/utils/base-path.js.map +1 -1
  375. package/dist/utils/cache-control-metadata.js.map +1 -1
  376. package/dist/utils/domain-locale.js.map +1 -1
  377. package/dist/utils/encode-cache-tag.d.ts +31 -0
  378. package/dist/utils/encode-cache-tag.js +38 -0
  379. package/dist/utils/encode-cache-tag.js.map +1 -0
  380. package/dist/utils/error-cause.js.map +1 -1
  381. package/dist/utils/hash.js.map +1 -1
  382. package/dist/utils/lazy-chunks.js.map +1 -1
  383. package/dist/utils/manifest-paths.js.map +1 -1
  384. package/dist/utils/mdx-scan.js.map +1 -1
  385. package/dist/utils/navigation-signal.d.ts +6 -0
  386. package/dist/utils/navigation-signal.js +14 -0
  387. package/dist/utils/navigation-signal.js.map +1 -0
  388. package/dist/utils/project.js.map +1 -1
  389. package/dist/utils/public-routes.js.map +1 -1
  390. package/dist/utils/query.d.ts +8 -1
  391. package/dist/utils/query.js +12 -1
  392. package/dist/utils/query.js.map +1 -1
  393. package/dist/utils/safe-json-file.js.map +1 -1
  394. package/dist/utils/text-stream.js.map +1 -1
  395. package/dist/utils/vinext-root.js.map +1 -1
  396. package/package.json +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"app-rsc-cache-busting.js","names":[],"sources":["../../src/server/app-rsc-cache-busting.ts"],"sourcesContent":["import { fnv1a64 } from \"../utils/hash.js\";\n\n/**\n * RSC cache-busting hashes cover the headers that make a `.rsc` payload vary.\n * Client-side variant headers must survive transit through CDNs and reverse\n * proxies; stripping them changes the server hash and turns stale URLs into\n * repeated canonicalization redirects.\n */\nexport const VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM = \"_rsc\";\nexport const VINEXT_RSC_CONTENT_TYPE = \"text/x-component\";\nexport const VINEXT_RSC_MOUNTED_SLOTS_HEADER = \"X-Vinext-Mounted-Slots\";\n\nconst VINEXT_RSC_HEADER = \"RSC\";\nconst VINEXT_RSC_INTERCEPTION_CONTEXT_HEADER = \"X-Vinext-Interception-Context\";\nconst NEXT_ROUTER_STATE_TREE_HEADER = \"Next-Router-State-Tree\";\nconst NEXT_ROUTER_PREFETCH_HEADER = \"Next-Router-Prefetch\";\nconst NEXT_ROUTER_SEGMENT_PREFETCH_HEADER = \"Next-Router-Segment-Prefetch\";\nconst NEXT_URL_HEADER = \"Next-Url\";\n\nexport const VINEXT_RSC_VARY_HEADER = [\n VINEXT_RSC_HEADER,\n \"Accept\",\n NEXT_ROUTER_STATE_TREE_HEADER,\n NEXT_ROUTER_PREFETCH_HEADER,\n NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,\n NEXT_URL_HEADER,\n VINEXT_RSC_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_RSC_MOUNTED_SLOTS_HEADER,\n].join(\", \");\n\nconst CACHE_BUSTING_DIGEST_BYTES = 12;\nconst textEncoder = new TextEncoder();\n\ntype CreateRscRequestHeadersOptions = {\n interceptionContext?: string | null;\n mountedSlotsHeader?: string | null;\n};\n\ntype ResolveInvalidRscCacheBustingRequestOptions = {\n isRscRequest: boolean;\n request: Request;\n};\n\nfunction encodeBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n}\n\nfunction normalizeHeaderValue(value: string | null): string {\n return value ?? \"0\";\n}\n\nfunction createCacheBustingInput(headers: Headers): string | null {\n // The order of these values determines the hash. Changing it is a breaking\n // cache-key change and requires accepting the previous hash during rollout.\n const values = [\n headers.get(NEXT_ROUTER_PREFETCH_HEADER),\n headers.get(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER),\n headers.get(NEXT_ROUTER_STATE_TREE_HEADER),\n headers.get(NEXT_URL_HEADER),\n headers.get(VINEXT_RSC_INTERCEPTION_CONTEXT_HEADER),\n headers.get(VINEXT_RSC_MOUNTED_SLOTS_HEADER),\n ];\n\n if (values.every((value) => value === null)) {\n return null;\n }\n\n return values.map(normalizeHeaderValue).join(\",\");\n}\n\nasync function sha256CacheBustingHash(input: string): Promise<string> {\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", textEncoder.encode(input));\n return encodeBase64Url(new Uint8Array(digest).subarray(0, CACHE_BUSTING_DIGEST_BYTES));\n}\n\nfunction computeLegacyRscCacheBustingSearchParam(headers: Headers): string {\n const input = createCacheBustingInput(headers);\n return input === null ? \"\" : fnv1a64(input);\n}\n\nfunction getSearchPairsWithoutRscCacheBusting(url: URL): string[] {\n const rawQuery = url.search.startsWith(\"?\") ? url.search.slice(1) : url.search;\n return rawQuery\n .split(\"&\")\n .filter((pair) => pair.length > 0 && !isRscCacheBustingSearchPair(pair));\n}\n\nfunction isRscCacheBustingSearchPair(pair: string): boolean {\n const separatorIndex = pair.indexOf(\"=\");\n const rawKey = separatorIndex === -1 ? pair : pair.slice(0, separatorIndex);\n\n try {\n return (\n decodeURIComponent(rawKey.replaceAll(\"+\", \" \")) === VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM\n );\n } catch {\n return rawKey === VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM;\n }\n}\n\nexport async function computeRscCacheBustingSearchParam(headers: Headers): Promise<string> {\n const input = createCacheBustingInput(headers);\n if (input === null) {\n return \"\";\n }\n\n return sha256CacheBustingHash(input);\n}\n\nexport function setRscCacheBustingSearchParam(url: URL, hash: string): void {\n const pairs = getSearchPairsWithoutRscCacheBusting(url);\n\n pairs.push(\n hash.length > 0\n ? `${VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM}=${hash}`\n : VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM,\n );\n url.search = `?${pairs.join(\"&\")}`;\n}\n\nexport function stripRscCacheBustingSearchParam(url: URL): void {\n const pairs = getSearchPairsWithoutRscCacheBusting(url);\n url.search = pairs.length > 0 ? `?${pairs.join(\"&\")}` : \"\";\n}\n\n/**\n * Remove a trailing `.rsc` suffix from a pathname. Returns the pathname\n * unchanged when the suffix is absent.\n */\nexport function stripRscSuffix(pathname: string): string {\n return pathname.endsWith(\".rsc\") ? pathname.slice(0, -4) : pathname;\n}\n\nexport function createRscRequestHeaders(options: CreateRscRequestHeadersOptions = {}): Headers {\n const headers = new Headers({\n Accept: VINEXT_RSC_CONTENT_TYPE,\n [VINEXT_RSC_HEADER]: \"1\",\n });\n\n if (options.interceptionContext !== undefined && options.interceptionContext !== null) {\n headers.set(VINEXT_RSC_INTERCEPTION_CONTEXT_HEADER, options.interceptionContext);\n }\n\n if (options.mountedSlotsHeader !== undefined && options.mountedSlotsHeader !== null) {\n headers.set(VINEXT_RSC_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);\n }\n\n return headers;\n}\n\nfunction toRscRequestPath(href: string): string {\n const hashIndex = href.indexOf(\"#\");\n const beforeHash = hashIndex === -1 ? href : href.slice(0, hashIndex);\n const queryIndex = beforeHash.indexOf(\"?\");\n const pathname = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);\n const query = queryIndex === -1 ? \"\" : beforeHash.slice(queryIndex);\n const normalizedPath =\n pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n return `${normalizedPath}.rsc${query}`;\n}\n\nexport async function createRscRequestUrl(href: string, headers: Headers): Promise<string> {\n const url = new URL(toRscRequestPath(href), \"http://vinext.local\");\n const hash = await computeRscCacheBustingSearchParam(headers);\n setRscCacheBustingSearchParam(url, hash);\n return `${url.pathname}${url.search}`;\n}\n\nexport async function createRscRedirectLocation(\n location: string,\n request: Request,\n): Promise<string> {\n const requestUrl = new URL(request.url);\n const destinationUrl = new URL(location, requestUrl);\n\n if (destinationUrl.origin !== requestUrl.origin) {\n return destinationUrl.toString();\n }\n\n const rscPath = await createRscRequestUrl(\n `${destinationUrl.pathname}${destinationUrl.search}`,\n request.headers,\n );\n return `${destinationUrl.origin}${rscPath}`;\n}\n\nexport async function resolveInvalidRscCacheBustingRequest(\n options: ResolveInvalidRscCacheBustingRequestOptions,\n): Promise<Response | null> {\n if (\n !options.isRscRequest ||\n (options.request.method !== \"GET\" && options.request.method !== \"HEAD\")\n ) {\n return null;\n }\n\n const url = new URL(options.request.url);\n const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);\n const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);\n\n if (actualHash === null && expectedHash === \"\") {\n return null;\n }\n\n const legacyHash =\n actualHash !== null && actualHash !== expectedHash\n ? computeLegacyRscCacheBustingSearchParam(options.request.headers)\n : null;\n\n if (actualHash === expectedHash || (legacyHash !== null && actualHash === legacyHash)) {\n return null;\n }\n\n setRscCacheBustingSearchParam(url, expectedHash);\n return new Response(null, {\n status: 307,\n headers: {\n Location: `${url.pathname}${url.search}`,\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-rsc-cache-busting.js","names":[],"sources":["../../src/server/app-rsc-cache-busting.ts"],"sourcesContent":["import { fnv1a64 } from \"../utils/hash.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n parseAppRscRenderMode,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport {\n NEXT_ROUTER_PREFETCH_HEADER,\n NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,\n NEXT_ROUTER_STATE_TREE_HEADER,\n NEXT_URL_HEADER,\n RSC_HEADER,\n VINEXT_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_RSC_RENDER_MODE_HEADER,\n} from \"./headers.js\";\n\n/**\n * RSC cache-busting hashes cover the headers that make a `.rsc` payload vary.\n * Client-side variant headers must survive transit through CDNs and reverse\n * proxies; stripping them changes the server hash and turns stale URLs into\n * repeated canonicalization redirects.\n */\nexport const VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM = \"_rsc\";\nexport const VINEXT_RSC_CONTENT_TYPE = \"text/x-component\";\n\n// Re-export so existing consumers that import from this module keep working.\nexport { VINEXT_RSC_RENDER_MODE_HEADER } from \"./headers.js\";\n\nexport const VINEXT_RSC_VARY_HEADER = [\n RSC_HEADER,\n \"Accept\",\n NEXT_ROUTER_STATE_TREE_HEADER,\n NEXT_ROUTER_PREFETCH_HEADER,\n NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,\n NEXT_URL_HEADER,\n VINEXT_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_RSC_RENDER_MODE_HEADER,\n].join(\", \");\n\nconst CACHE_BUSTING_DIGEST_BYTES = 12;\nconst textEncoder = new TextEncoder();\n\ntype CreateRscRequestHeadersOptions = {\n interceptionContext?: string | null;\n mountedSlotsHeader?: string | null;\n renderMode?: AppRscRenderMode;\n};\n\ntype ResolveInvalidRscCacheBustingRequestOptions = {\n isRscRequest: boolean;\n request: Request;\n};\n\nfunction encodeBase64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n}\n\nfunction normalizeHeaderValue(value: string | null): string {\n return value ?? \"0\";\n}\n\nfunction normalizeRenderModeHeaderValue(value: string | null): string | null {\n const renderMode = parseAppRscRenderMode(value);\n return renderMode === APP_RSC_RENDER_MODE_NAVIGATION ? null : renderMode;\n}\n\ntype CreateCacheBustingInputOptions = {\n includeRenderModeHeader?: boolean;\n};\n\nfunction createCacheBustingInput(\n headers: Headers,\n options: CreateCacheBustingInputOptions = {},\n): string | null {\n // The order of these values determines the hash. Changing it is a breaking\n // cache-key change and requires accepting the previous hash during rollout.\n const values = [\n headers.get(NEXT_ROUTER_PREFETCH_HEADER),\n headers.get(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER),\n headers.get(NEXT_ROUTER_STATE_TREE_HEADER),\n headers.get(NEXT_URL_HEADER),\n headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER),\n headers.get(VINEXT_MOUNTED_SLOTS_HEADER),\n ...(options.includeRenderModeHeader === false\n ? []\n : [normalizeRenderModeHeaderValue(headers.get(VINEXT_RSC_RENDER_MODE_HEADER))]),\n ];\n\n if (values.every((value) => value === null)) {\n return null;\n }\n\n return values.map(normalizeHeaderValue).join(\",\");\n}\n\nasync function sha256CacheBustingHash(input: string): Promise<string> {\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", textEncoder.encode(input));\n return encodeBase64Url(new Uint8Array(digest).subarray(0, CACHE_BUSTING_DIGEST_BYTES));\n}\n\nfunction computeLegacyRscCacheBustingSearchParam(headers: Headers): string {\n const input = createCacheBustingInput(headers);\n return input === null ? \"\" : fnv1a64(input);\n}\n\nasync function computePreviousRscCacheBustingSearchParam(headers: Headers): Promise<string | null> {\n const input = createCacheBustingInput(headers, { includeRenderModeHeader: false });\n if (input === null) {\n return null;\n }\n\n return sha256CacheBustingHash(input);\n}\n\nfunction computePreviousLegacyRscCacheBustingSearchParam(headers: Headers): string | null {\n const input = createCacheBustingInput(headers, { includeRenderModeHeader: false });\n return input === null ? null : fnv1a64(input);\n}\n\nfunction getSearchPairsWithoutRscCacheBusting(url: URL): string[] {\n const rawQuery = url.search.startsWith(\"?\") ? url.search.slice(1) : url.search;\n return rawQuery\n .split(\"&\")\n .filter((pair) => pair.length > 0 && !isRscCacheBustingSearchPair(pair));\n}\n\nfunction isRscCacheBustingSearchPair(pair: string): boolean {\n const separatorIndex = pair.indexOf(\"=\");\n const rawKey = separatorIndex === -1 ? pair : pair.slice(0, separatorIndex);\n\n try {\n return (\n decodeURIComponent(rawKey.replaceAll(\"+\", \" \")) === VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM\n );\n } catch {\n return rawKey === VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM;\n }\n}\n\nexport async function computeRscCacheBustingSearchParam(headers: Headers): Promise<string> {\n const input = createCacheBustingInput(headers);\n if (input === null) {\n return \"\";\n }\n\n return sha256CacheBustingHash(input);\n}\n\nexport function setRscCacheBustingSearchParam(url: URL, hash: string): void {\n const pairs = getSearchPairsWithoutRscCacheBusting(url);\n\n pairs.push(\n hash.length > 0\n ? `${VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM}=${hash}`\n : VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM,\n );\n url.search = `?${pairs.join(\"&\")}`;\n}\n\nexport function stripRscCacheBustingSearchParam(url: URL): void {\n const pairs = getSearchPairsWithoutRscCacheBusting(url);\n url.search = pairs.length > 0 ? `?${pairs.join(\"&\")}` : \"\";\n}\n\n/**\n * Remove a trailing `.rsc` suffix from a pathname. Returns the pathname\n * unchanged when the suffix is absent.\n */\nexport function stripRscSuffix(pathname: string): string {\n return pathname.endsWith(\".rsc\") ? pathname.slice(0, -4) : pathname;\n}\n\nexport function createRscRequestHeaders(options: CreateRscRequestHeadersOptions = {}): Headers {\n const headers = new Headers({\n Accept: VINEXT_RSC_CONTENT_TYPE,\n [RSC_HEADER]: \"1\",\n });\n\n if (options.interceptionContext !== undefined && options.interceptionContext !== null) {\n headers.set(VINEXT_INTERCEPTION_CONTEXT_HEADER, options.interceptionContext);\n }\n\n if (options.mountedSlotsHeader !== undefined && options.mountedSlotsHeader !== null) {\n headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);\n }\n\n const renderMode = options.renderMode ?? APP_RSC_RENDER_MODE_NAVIGATION;\n if (renderMode !== APP_RSC_RENDER_MODE_NAVIGATION) {\n headers.set(VINEXT_RSC_RENDER_MODE_HEADER, renderMode);\n }\n\n return headers;\n}\n\nfunction toRscRequestPath(href: string): string {\n const hashIndex = href.indexOf(\"#\");\n const beforeHash = hashIndex === -1 ? href : href.slice(0, hashIndex);\n const queryIndex = beforeHash.indexOf(\"?\");\n const pathname = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);\n const query = queryIndex === -1 ? \"\" : beforeHash.slice(queryIndex);\n const normalizedPath =\n pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n return `${normalizedPath}.rsc${query}`;\n}\n\nexport async function createRscRequestUrl(href: string, headers: Headers): Promise<string> {\n const url = new URL(toRscRequestPath(href), \"http://vinext.local\");\n const hash = await computeRscCacheBustingSearchParam(headers);\n setRscCacheBustingSearchParam(url, hash);\n return `${url.pathname}${url.search}`;\n}\n\nexport async function createRscRedirectLocation(\n location: string,\n request: Request,\n): Promise<string> {\n const requestUrl = new URL(request.url);\n const destinationUrl = new URL(location, requestUrl);\n\n if (destinationUrl.origin !== requestUrl.origin) {\n return destinationUrl.toString();\n }\n\n const rscPath = await createRscRequestUrl(\n `${destinationUrl.pathname}${destinationUrl.search}`,\n request.headers,\n );\n return `${destinationUrl.origin}${rscPath}`;\n}\n\nexport async function resolveInvalidRscCacheBustingRequest(\n options: ResolveInvalidRscCacheBustingRequestOptions,\n): Promise<Response | null> {\n if (\n !options.isRscRequest ||\n (options.request.method !== \"GET\" && options.request.method !== \"HEAD\")\n ) {\n return null;\n }\n\n const url = new URL(options.request.url);\n const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);\n const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);\n\n if (actualHash === null && expectedHash === \"\") {\n return null;\n }\n\n const acceptedHashes = new Set<string>([expectedHash]);\n if (actualHash !== null && actualHash !== expectedHash) {\n acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));\n if (\n normalizeRenderModeHeaderValue(options.request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) ===\n null\n ) {\n const previousHash = await computePreviousRscCacheBustingSearchParam(options.request.headers);\n const previousLegacyHash = computePreviousLegacyRscCacheBustingSearchParam(\n options.request.headers,\n );\n if (previousHash !== null) acceptedHashes.add(previousHash);\n if (previousLegacyHash !== null) acceptedHashes.add(previousLegacyHash);\n }\n }\n\n if (actualHash !== null && acceptedHashes.has(actualHash)) {\n return null;\n }\n\n setRscCacheBustingSearchParam(url, expectedHash);\n return new Response(null, {\n status: 307,\n headers: {\n Location: `${url.pathname}${url.search}`,\n },\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app-rsc-error-handler.js","names":[],"sources":["../../src/server/app-rsc-error-handler.ts"],"sourcesContent":["import { createRscOnErrorHandler } from \"./app-rsc-errors.js\";\n\ntype ReportRequestError = (\n error: Error,\n requestInfo: { path: string; method: string; headers: Record<string, string> },\n errorContext: { routerKind: \"App Router\"; routePath: string; routeType: \"render\" },\n) => void;\n\n/**\n * Build a per-request RSC error handler that extracts request metadata from\n * the incoming Web `Request`, wires it into a `createRscOnErrorHandler` call,\n * and binds the configured `reportRequestError` reporter.\n *\n * Pure factory: takes all deps explicitly — no closure over module-level state.\n */\nexport function createAppRscOnErrorHandler(\n reportRequestError: ReportRequestError,\n request: Request,\n pathname: string,\n routePath: string,\n): (error: unknown) => string | undefined {\n const requestHeaders: Record<string, string> = Object.fromEntries(request.headers.entries());\n const requestInfo = {\n path: pathname,\n method: request.method,\n headers: requestHeaders,\n };\n const errorContext = {\n routerKind: \"App Router\" as const,\n routePath: routePath || pathname,\n routeType: \"render\" as const,\n };\n return createRscOnErrorHandler({\n errorContext,\n reportRequestError,\n requestInfo,\n });\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,2BACd,oBACA,SACA,UACA,WACwC;CACxC,MAAM,iBAAyC,OAAO,YAAY,QAAQ,QAAQ,SAAS,CAAC;CAC5F,MAAM,cAAc;EAClB,MAAM;EACN,QAAQ,QAAQ;EAChB,SAAS;EACV;AAMD,QAAO,wBAAwB;EAC7B,cANmB;GACnB,YAAY;GACZ,WAAW,aAAa;GACxB,WAAW;GACZ;EAGC;EACA;EACD,CAAC"}
1
+ {"version":3,"file":"app-rsc-error-handler.js","names":[],"sources":["../../src/server/app-rsc-error-handler.ts"],"sourcesContent":["import { createRscOnErrorHandler } from \"./app-rsc-errors.js\";\n\ntype ReportRequestError = (\n error: Error,\n requestInfo: { path: string; method: string; headers: Record<string, string> },\n errorContext: { routerKind: \"App Router\"; routePath: string; routeType: \"render\" },\n) => void;\n\n/**\n * Build a per-request RSC error handler that extracts request metadata from\n * the incoming Web `Request`, wires it into a `createRscOnErrorHandler` call,\n * and binds the configured `reportRequestError` reporter.\n *\n * Pure factory: takes all deps explicitly — no closure over module-level state.\n */\nexport function createAppRscOnErrorHandler(\n reportRequestError: ReportRequestError,\n request: Request,\n pathname: string,\n routePath: string,\n): (error: unknown) => string | undefined {\n const requestHeaders: Record<string, string> = Object.fromEntries(request.headers.entries());\n const requestInfo = {\n path: pathname,\n method: request.method,\n headers: requestHeaders,\n };\n const errorContext = {\n routerKind: \"App Router\" as const,\n routePath: routePath || pathname,\n routeType: \"render\" as const,\n };\n return createRscOnErrorHandler({\n errorContext,\n reportRequestError,\n requestInfo,\n });\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,2BACd,oBACA,SACA,UACA,WACwC;CACxC,MAAM,iBAAyC,OAAO,YAAY,QAAQ,QAAQ,SAAS,CAAC;CAC5F,MAAM,cAAc;EAClB,MAAM;EACN,QAAQ,QAAQ;EAChB,SAAS;EACV;CAMD,OAAO,wBAAwB;EAC7B,cAAA;GALA,YAAY;GACZ,WAAW,aAAa;GACxB,WAAW;GAGC;EACZ;EACA;EACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"app-rsc-errors.js","names":[],"sources":["../../src/server/app-rsc-errors.ts"],"sourcesContent":["import { resolveAppPageSpecialError } from \"./app-page-execution.js\";\n\ntype DigestError = Error & { digest?: string };\n\ntype RscRequestInfo = {\n path: string;\n method: string;\n headers: Record<string, string>;\n};\n\ntype RscErrorContext = {\n routerKind: \"App Router\";\n routePath: string;\n routeType: \"render\";\n};\n\ntype RscErrorReporter = (\n error: Error,\n requestInfo: RscRequestInfo,\n errorContext: RscErrorContext,\n) => void;\n\ntype CreateRscOnErrorHandlerOptions = {\n errorContext: RscErrorContext | null;\n nodeEnv?: string;\n reportRequestError: RscErrorReporter;\n requestInfo: RscRequestInfo | null;\n};\n\nfunction hasDigest(error: unknown): error is { digest: unknown } {\n return Boolean(error && typeof error === \"object\" && \"digest\" in error);\n}\n\nfunction getThrownValueMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction getThrownValueStack(error: unknown): string {\n return error instanceof Error ? error.stack || \"\" : \"\";\n}\n\n/**\n * djb2 hash matching Next.js's string-hash package for RSC error digests.\n */\nexport function errorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nexport function sanitizeErrorForClient(error: unknown, nodeEnv = process.env.NODE_ENV): unknown {\n if (resolveAppPageSpecialError(error)) {\n return error;\n }\n\n if (nodeEnv !== \"production\") {\n return error;\n }\n\n const sanitized: DigestError = new Error(\n \"An error occurred in the Server Components render. \" +\n \"The specific message is omitted in production builds to avoid leaking sensitive details. \" +\n \"A digest property is included on this error instance which may provide additional details about the nature of the error.\",\n );\n sanitized.digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));\n return sanitized;\n}\n\nexport function createRscOnErrorHandler(\n options: CreateRscOnErrorHandlerOptions,\n): (error: unknown) => string | undefined {\n return (error) => {\n const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;\n\n if (hasDigest(error)) {\n return String(error.digest);\n }\n\n if (\n nodeEnv !== \"production\" &&\n error instanceof Error &&\n error.message.includes(\n \"Only plain objects, and a few built-ins, can be passed to Client Components\",\n )\n ) {\n console.error(\n \"[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\\n\" +\n \"\\n\" +\n \"Common causes:\\n\" +\n \" * Passing a module namespace (import * as X) directly as a prop.\\n\" +\n \" Unlike Next.js (webpack), Vite produces real ESM module namespace objects\\n\" +\n \" which are not serializable. Fix: pass individual values instead,\\n\" +\n \" e.g. <Comp value={module.value} />\\n\" +\n \" * Passing a class instance (new Foo()) as a prop.\\n\" +\n \" Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\\n\" +\n \" * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\\n\" +\n \" * Passing Object.create(null). Use { ...obj } to restore a prototype.\\n\" +\n \"\\n\" +\n \"Original error:\",\n error.message,\n );\n return undefined;\n }\n\n if (options.requestInfo && options.errorContext && error) {\n options.reportRequestError(\n error instanceof Error ? error : new Error(getThrownValueMessage(error)),\n options.requestInfo,\n options.errorContext,\n );\n }\n\n if (nodeEnv === \"production\" && error) {\n return errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));\n }\n\n return undefined;\n };\n}\n"],"mappings":";;AA6BA,SAAS,UAAU,OAA8C;AAC/D,QAAO,QAAQ,SAAS,OAAO,UAAU,YAAY,YAAY,MAAM;;AAGzE,SAAS,sBAAsB,OAAwB;AACrD,QAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;AAG/D,SAAS,oBAAoB,OAAwB;AACnD,QAAO,iBAAiB,QAAQ,MAAM,SAAS,KAAK;;;;;AAMtD,SAAgB,YAAY,OAAuB;CACjD,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,IACrC,QAAQ,OAAO,KAAM,MAAM,WAAW,EAAE;AAE1C,SAAQ,SAAS,GAAG,UAAU;;AAGhC,SAAgB,uBAAuB,OAAgB,UAAU,QAAQ,IAAI,UAAmB;AAC9F,KAAI,2BAA2B,MAAM,CACnC,QAAO;AAGT,KAAI,YAAY,aACd,QAAO;CAGT,MAAM,4BAAyB,IAAI,MACjC,uQAGD;AACD,WAAU,SAAS,YAAY,sBAAsB,MAAM,GAAG,oBAAoB,MAAM,CAAC;AACzF,QAAO;;AAGT,SAAgB,wBACd,SACwC;AACxC,SAAQ,UAAU;EAChB,MAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI;AAE/C,MAAI,UAAU,MAAM,CAClB,QAAO,OAAO,MAAM,OAAO;AAG7B,MACE,YAAY,gBACZ,iBAAiB,SACjB,MAAM,QAAQ,SACZ,8EACD,EACD;AACA,WAAQ,MACN,8qBAaA,MAAM,QACP;AACD;;AAGF,MAAI,QAAQ,eAAe,QAAQ,gBAAgB,MACjD,SAAQ,mBACN,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,sBAAsB,MAAM,CAAC,EACxE,QAAQ,aACR,QAAQ,aACT;AAGH,MAAI,YAAY,gBAAgB,MAC9B,QAAO,YAAY,sBAAsB,MAAM,GAAG,oBAAoB,MAAM,CAAC"}
1
+ {"version":3,"file":"app-rsc-errors.js","names":[],"sources":["../../src/server/app-rsc-errors.ts"],"sourcesContent":["import { resolveAppPageSpecialError } from \"./app-page-execution.js\";\n\ntype DigestError = Error & { digest?: string };\n\ntype RscRequestInfo = {\n path: string;\n method: string;\n headers: Record<string, string>;\n};\n\ntype RscErrorContext = {\n routerKind: \"App Router\";\n routePath: string;\n routeType: \"render\";\n};\n\ntype RscErrorReporter = (\n error: Error,\n requestInfo: RscRequestInfo,\n errorContext: RscErrorContext,\n) => void;\n\ntype CreateRscOnErrorHandlerOptions = {\n errorContext: RscErrorContext | null;\n nodeEnv?: string;\n reportRequestError: RscErrorReporter;\n requestInfo: RscRequestInfo | null;\n};\n\nfunction hasDigest(error: unknown): error is { digest: unknown } {\n return Boolean(error && typeof error === \"object\" && \"digest\" in error);\n}\n\nfunction getThrownValueMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction getThrownValueStack(error: unknown): string {\n return error instanceof Error ? error.stack || \"\" : \"\";\n}\n\n/**\n * djb2 hash matching Next.js's string-hash package for RSC error digests.\n */\nexport function errorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nexport function sanitizeErrorForClient(error: unknown, nodeEnv = process.env.NODE_ENV): unknown {\n if (resolveAppPageSpecialError(error)) {\n return error;\n }\n\n if (nodeEnv !== \"production\") {\n return error;\n }\n\n const sanitized: DigestError = new Error(\n \"An error occurred in the Server Components render. \" +\n \"The specific message is omitted in production builds to avoid leaking sensitive details. \" +\n \"A digest property is included on this error instance which may provide additional details about the nature of the error.\",\n );\n sanitized.digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));\n return sanitized;\n}\n\nexport function createRscOnErrorHandler(\n options: CreateRscOnErrorHandlerOptions,\n): (error: unknown) => string | undefined {\n return (error) => {\n const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;\n\n if (hasDigest(error)) {\n return String(error.digest);\n }\n\n if (\n nodeEnv !== \"production\" &&\n error instanceof Error &&\n error.message.includes(\n \"Only plain objects, and a few built-ins, can be passed to Client Components\",\n )\n ) {\n console.error(\n \"[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\\n\" +\n \"\\n\" +\n \"Common causes:\\n\" +\n \" * Passing a module namespace (import * as X) directly as a prop.\\n\" +\n \" Unlike Next.js (webpack), Vite produces real ESM module namespace objects\\n\" +\n \" which are not serializable. Fix: pass individual values instead,\\n\" +\n \" e.g. <Comp value={module.value} />\\n\" +\n \" * Passing a class instance (new Foo()) as a prop.\\n\" +\n \" Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\\n\" +\n \" * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\\n\" +\n \" * Passing Object.create(null). Use { ...obj } to restore a prototype.\\n\" +\n \"\\n\" +\n \"Original error:\",\n error.message,\n );\n return undefined;\n }\n\n if (options.requestInfo && options.errorContext && error) {\n options.reportRequestError(\n error instanceof Error ? error : new Error(getThrownValueMessage(error)),\n options.requestInfo,\n options.errorContext,\n );\n }\n\n if (nodeEnv === \"production\" && error) {\n return errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));\n }\n\n return undefined;\n };\n}\n"],"mappings":";;AA6BA,SAAS,UAAU,OAA8C;CAC/D,OAAO,QAAQ,SAAS,OAAO,UAAU,YAAY,YAAY,MAAM;;AAGzE,SAAS,sBAAsB,OAAwB;CACrD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;AAG/D,SAAS,oBAAoB,OAAwB;CACnD,OAAO,iBAAiB,QAAQ,MAAM,SAAS,KAAK;;;;;AAMtD,SAAgB,YAAY,OAAuB;CACjD,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KACrC,OAAQ,OAAO,KAAM,MAAM,WAAW,EAAE;CAE1C,QAAQ,SAAS,GAAG,UAAU;;AAGhC,SAAgB,uBAAuB,OAAgB,UAAU,QAAQ,IAAI,UAAmB;CAC9F,IAAI,2BAA2B,MAAM,EACnC,OAAO;CAGT,IAAI,YAAY,cACd,OAAO;CAGT,MAAM,4BAAyB,IAAI,MACjC,uQAGD;CACD,UAAU,SAAS,YAAY,sBAAsB,MAAM,GAAG,oBAAoB,MAAM,CAAC;CACzF,OAAO;;AAGT,SAAgB,wBACd,SACwC;CACxC,QAAQ,UAAU;EAChB,MAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI;EAE/C,IAAI,UAAU,MAAM,EAClB,OAAO,OAAO,MAAM,OAAO;EAG7B,IACE,YAAY,gBACZ,iBAAiB,SACjB,MAAM,QAAQ,SACZ,8EACD,EACD;GACA,QAAQ,MACN,8qBAaA,MAAM,QACP;GACD;;EAGF,IAAI,QAAQ,eAAe,QAAQ,gBAAgB,OACjD,QAAQ,mBACN,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,sBAAsB,MAAM,CAAC,EACxE,QAAQ,aACR,QAAQ,aACT;EAGH,IAAI,YAAY,gBAAgB,OAC9B,OAAO,YAAY,sBAAsB,MAAM,GAAG,oBAAoB,MAAM,CAAC"}
@@ -1,8 +1,10 @@
1
1
  import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
2
2
  import { MiddlewareModule } from "./middleware-runtime.js";
3
3
  import { AppMiddlewareContext } from "./app-middleware.js";
4
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
5
  import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
5
6
  import { handleMetadataRouteRequest } from "./metadata-route-response.js";
7
+ import { ReactFormState } from "react-dom/client";
6
8
 
7
9
  //#region src/server/app-rsc-handler.d.ts
8
10
  type AppPageParams = Record<string, string | string[]>;
@@ -12,6 +14,7 @@ type StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1]["staticP
12
14
  type RootParamNamesMap = Parameters<typeof handleAppPrerenderEndpoint>[1]["rootParamNamesByPattern"];
13
15
  type AppRscMiddlewareContext = AppMiddlewareContext;
14
16
  type AppRscHandlerRoute = {
17
+ isDynamic: boolean;
15
18
  page?: unknown;
16
19
  pattern: string;
17
20
  rootParamNames?: readonly string[];
@@ -24,8 +27,10 @@ type AppRscRouteMatch<TRoute> = {
24
27
  };
25
28
  type DispatchMatchedPageOptions<TRoute> = {
26
29
  cleanPathname: string;
30
+ formState: ReactFormState | null;
27
31
  handlerStart: number;
28
32
  interceptionContext: string | null;
33
+ isProgressiveActionRender: boolean;
29
34
  isRscRequest: boolean;
30
35
  middlewareContext: AppRscMiddlewareContext;
31
36
  mountedSlotsHeader: string | null;
@@ -34,6 +39,7 @@ type DispatchMatchedPageOptions<TRoute> = {
34
39
  route: TRoute;
35
40
  scriptNonce?: string;
36
41
  searchParams: URLSearchParams;
42
+ renderMode: AppRscRenderMode;
37
43
  };
38
44
  type DispatchMatchedRouteHandlerOptions<TRoute> = {
39
45
  cleanPathname: string;
@@ -93,7 +99,10 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
93
99
  dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;
94
100
  dispatchMatchedRouteHandler: (options: DispatchMatchedRouteHandlerOptions<TRoute>) => Promise<Response>;
95
101
  ensureInstrumentation?: () => Promise<void>;
96
- handleProgressiveActionRequest: (options: HandleProgressiveActionRequestOptions) => Promise<Response | null>;
102
+ handleProgressiveActionRequest: (options: HandleProgressiveActionRequestOptions) => Promise<Response | {
103
+ formState: ReactFormState | null;
104
+ kind: "form-state";
105
+ } | null>;
97
106
  handleServerActionRequest: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
98
107
  i18nConfig: NextI18nConfig | null;
99
108
  isMiddlewareProxy: boolean;
@@ -1,13 +1,15 @@
1
1
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { hasBasePath } from "../utils/base-path.js";
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
+ import { VINEXT_MW_CTX_HEADER } from "./headers.js";
4
5
  import { isExternalUrl, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
5
6
  import { notFoundResponse } from "./http-error-responses.js";
6
- import { cloneRequestWithHeaders, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute, validateImageUrl } from "./request-pipeline.js";
7
+ import { applyConfigHeadersToResponse, cloneRequestWithHeaders, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute, validateImageUrl } from "./request-pipeline.js";
7
8
  import { headersContextFromRequest } from "../shims/headers.js";
8
9
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
9
10
  import { createRscRedirectLocation, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
10
11
  import { getScriptNonceFromHeaderSources } from "./csp.js";
12
+ import { flattenErrorCauses } from "../utils/error-cause.js";
11
13
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
12
14
  import { applyAppMiddleware } from "./app-middleware.js";
13
15
  import "./app-page-response.js";
@@ -15,7 +17,6 @@ import { buildPageCacheTags } from "./implicit-tags.js";
15
17
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
16
18
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
17
19
  import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
18
- import { flattenErrorCauses } from "../utils/error-cause.js";
19
20
  import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
20
21
  import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
21
22
  import { handleMetadataRouteRequest } from "./metadata-route-response.js";
@@ -42,6 +43,25 @@ async function applyRewrite(options, cleanPathname) {
42
43
  }
43
44
  return rewritten;
44
45
  }
46
+ function applyConfigHeadersToMiddlewareRedirect(response, options) {
47
+ if (response.status < 300 || response.status >= 400) return response;
48
+ if (!options.configHeaders.length) return response;
49
+ const headers = new Headers();
50
+ applyConfigHeadersToResponse(headers, {
51
+ configHeaders: options.configHeaders,
52
+ pathname: options.pathname,
53
+ requestContext: options.requestContext
54
+ });
55
+ if (!headers.entries().next().done) {
56
+ mergeMiddlewareResponseHeaders(headers, response.headers);
57
+ return new Response(response.body, {
58
+ status: response.status,
59
+ statusText: response.statusText,
60
+ headers
61
+ });
62
+ }
63
+ return response;
64
+ }
45
65
  async function handleAppRscRequest(options, request, preMiddlewareRequestContext) {
46
66
  const handlerStart = process.env.NODE_ENV !== "production" ? performance.now() : 0;
47
67
  if (process.env.NODE_ENV !== "production") {
@@ -50,7 +70,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
50
70
  }
51
71
  const normalized = normalizeRscRequest(request, options.basePath);
52
72
  if (normalized instanceof Response) return normalized;
53
- const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader } = normalized;
73
+ const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } = normalized;
54
74
  let { pathname, cleanPathname } = normalized;
55
75
  const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
56
76
  isPrerenderEnabled() {
@@ -93,7 +113,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
93
113
  module: options.middlewareModule,
94
114
  request
95
115
  });
96
- if (middlewareResult.kind === "response") return middlewareResult.response;
116
+ if (middlewareResult.kind === "response") return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {
117
+ configHeaders: options.configHeaders,
118
+ pathname: cleanPathname,
119
+ requestContext: preMiddlewareRequestContext
120
+ });
97
121
  cleanPathname = middlewareResult.cleanPathname;
98
122
  if (middlewareResult.search !== null) url.search = middlewareResult.search;
99
123
  }
@@ -137,14 +161,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
137
161
  });
138
162
  const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
139
163
  const contentType = request.headers.get("content-type") || "";
140
- const progressiveActionResponse = await options.handleProgressiveActionRequest({
164
+ const progressiveActionResult = await options.handleProgressiveActionRequest({
141
165
  actionId,
142
166
  cleanPathname,
143
167
  contentType,
144
168
  middlewareContext,
145
169
  request
146
170
  });
147
- if (progressiveActionResponse) return progressiveActionResponse;
171
+ if (progressiveActionResult instanceof Response) return progressiveActionResult;
172
+ const isProgressiveActionRender = progressiveActionResult?.kind === "form-state";
173
+ const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;
148
174
  const serverActionResponse = await options.handleServerActionRequest({
149
175
  actionId,
150
176
  cleanPathname,
@@ -157,15 +183,20 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
157
183
  searchParams: url.searchParams
158
184
  });
159
185
  if (serverActionResponse) return serverActionResponse;
160
- const afterFilesRewrite = await applyRewrite({
161
- clearRequestContext: options.clearRequestContext,
162
- request,
163
- requestContext: postMiddlewareRequestContext,
164
- rewrites: options.configRewrites.afterFiles
165
- }, cleanPathname);
166
- if (afterFilesRewrite instanceof Response) return afterFilesRewrite;
167
- if (afterFilesRewrite) cleanPathname = afterFilesRewrite;
168
186
  let match = options.matchRoute(cleanPathname);
187
+ if (!match || match.route.isDynamic) {
188
+ const afterFilesRewrite = await applyRewrite({
189
+ clearRequestContext: options.clearRequestContext,
190
+ request,
191
+ requestContext: postMiddlewareRequestContext,
192
+ rewrites: options.configRewrites.afterFiles
193
+ }, cleanPathname);
194
+ if (afterFilesRewrite instanceof Response) return afterFilesRewrite;
195
+ if (afterFilesRewrite) {
196
+ cleanPathname = afterFilesRewrite;
197
+ match = options.matchRoute(cleanPathname);
198
+ }
199
+ }
169
200
  if (!match) {
170
201
  const fallbackRewrite = await applyRewrite({
171
202
  clearRequestContext: options.clearRequestContext,
@@ -223,8 +254,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
223
254
  }
224
255
  return options.dispatchMatchedPage({
225
256
  cleanPathname,
257
+ formState,
226
258
  handlerStart,
227
259
  interceptionContext: interceptionContextHeader,
260
+ isProgressiveActionRender,
228
261
  isRscRequest,
229
262
  middlewareContext,
230
263
  mountedSlotsHeader,
@@ -232,15 +265,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
232
265
  request,
233
266
  route,
234
267
  scriptNonce,
235
- searchParams: url.searchParams
268
+ searchParams: url.searchParams,
269
+ renderMode
236
270
  });
237
271
  }
238
272
  function createAppRscHandler(options) {
239
273
  return async function appRscHandler(rawRequest, ctx) {
240
274
  await options.ensureInstrumentation?.();
241
- const mwCtx = rawRequest.headers.get("x-vinext-mw-ctx");
275
+ const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);
242
276
  const filteredHeaders = filterInternalHeaders(rawRequest.headers);
243
- if (mwCtx !== null) filteredHeaders.set("x-vinext-mw-ctx", mwCtx);
277
+ if (mwCtx !== null) filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);
244
278
  const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);
245
279
  const executionContext = isExecutionContextLike(ctx) ? ctx : getRequestExecutionContext() ?? null;
246
280
  return runWithRequestContext(createRequestContext({
@@ -1 +1 @@
1
- {"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n handlerStart: number;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(cleanPathname, options.rewrites, options.requestContext);\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader } = normalized;\n let { pathname, cleanPathname } = normalized;\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n const redirectPathname = stripRscSuffix(pathname);\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(\"RSC\") === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n });\n if (middlewareResult.kind === \"response\") return middlewareResult.response;\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n const beforeFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n cleanPathname,\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (cleanPathname === \"/_vinext/image\") {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n const actionId = request.headers.get(\"x-rsc-action\") ?? request.headers.get(\"next-action\");\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResponse = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResponse) return progressiveActionResponse;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n const afterFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n cleanPathname,\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) cleanPathname = afterFilesRewrite;\n\n let match = options.matchRoute(cleanPathname);\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n cleanPathname,\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params,\n });\n setRootParams(pickRootParams(params, route.rootParamNames));\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n params,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n return options.dispatchMatchedPage({\n cleanPathname,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n });\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(\"x-vinext-mw-ctx\");\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(\"x-vinext-mw-ctx\", mwCtx);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request);\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(options, request, preMiddlewareRequestContext);\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport {\n NEXT_ACTION_HEADER,\n RSC_ACTION_HEADER,\n RSC_HEADER,\n VINEXT_MW_CTX_HEADER,\n} from \"./headers.js\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport type { AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n applyConfigHeadersToResponse,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n isDynamic: boolean;\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n formState: ReactFormState | null;\n handlerStart: number;\n interceptionContext: string | null;\n isProgressiveActionRender: boolean;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n renderMode: AppRscRenderMode;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | { formState: ReactFormState | null; kind: \"form-state\" } | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(cleanPathname, options.rewrites, options.requestContext);\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nfunction applyConfigHeadersToMiddlewareRedirect(\n response: Response,\n options: {\n configHeaders: NextHeader[];\n pathname: string;\n requestContext: RequestContext;\n },\n): Response {\n // Non-redirect middleware responses still pass through finalization, where\n // config headers are applied once. Redirects skip finalization to avoid\n // mutating immutable redirect headers, so they need the earlier header layer here.\n if (response.status < 300 || response.status >= 400) return response;\n if (!options.configHeaders.length) return response;\n\n const headers = new Headers();\n applyConfigHeadersToResponse(headers, {\n configHeaders: options.configHeaders,\n pathname: options.pathname,\n requestContext: options.requestContext,\n });\n\n if (!headers.entries().next().done) {\n mergeMiddlewareResponseHeaders(headers, response.headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return response;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } =\n normalized;\n let { pathname, cleanPathname } = normalized;\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n const redirectPathname = stripRscSuffix(pathname);\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(RSC_HEADER) === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n });\n if (middlewareResult.kind === \"response\") {\n return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {\n configHeaders: options.configHeaders,\n pathname: cleanPathname,\n requestContext: preMiddlewareRequestContext,\n });\n }\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n const beforeFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n cleanPathname,\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (cleanPathname === \"/_vinext/image\") {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n const actionId =\n request.headers.get(RSC_ACTION_HEADER) ?? request.headers.get(NEXT_ACTION_HEADER);\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResult = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResult instanceof Response) return progressiveActionResult;\n const isProgressiveActionRender = progressiveActionResult?.kind === \"form-state\";\n const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n let match = options.matchRoute(cleanPathname);\n if (!match || match.route.isDynamic) {\n const afterFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n cleanPathname,\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) {\n cleanPathname = afterFilesRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n cleanPathname,\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params,\n });\n setRootParams(pickRootParams(params, route.rootParamNames));\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n params,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n return options.dispatchMatchedPage({\n cleanPathname,\n formState,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isProgressiveActionRender,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n renderMode,\n });\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request);\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(options, request, preMiddlewareRequestContext);\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ //#region src/server/app-rsc-render-mode.d.ts
2
+ type AppRscRenderMode = "navigation" | "refresh-preserve-ui" | "action-rerender-preserve-ui";
3
+ declare const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
4
+ declare const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI = "refresh-preserve-ui";
5
+ declare const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI = "action-rerender-preserve-ui";
6
+ declare function shouldSuppressLoadingBoundaries(mode: AppRscRenderMode): boolean;
7
+ declare function shouldUsePreserveUiCacheVariant(mode: AppRscRenderMode): boolean;
8
+ declare function parseAppRscRenderMode(value: string | null): AppRscRenderMode;
9
+ //#endregion
10
+ export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, AppRscRenderMode, parseAppRscRenderMode, shouldSuppressLoadingBoundaries, shouldUsePreserveUiCacheVariant };
11
+ //# sourceMappingURL=app-rsc-render-mode.d.ts.map
@@ -0,0 +1,21 @@
1
+ //#region src/server/app-rsc-render-mode.ts
2
+ const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
3
+ const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI = "refresh-preserve-ui";
4
+ const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI = "action-rerender-preserve-ui";
5
+ function shouldSuppressLoadingBoundaries(mode) {
6
+ return mode === "refresh-preserve-ui" || mode === "action-rerender-preserve-ui";
7
+ }
8
+ function shouldUsePreserveUiCacheVariant(mode) {
9
+ return shouldSuppressLoadingBoundaries(mode);
10
+ }
11
+ function parseAppRscRenderMode(value) {
12
+ switch (value) {
13
+ case APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI: return APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI;
14
+ case APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI: return APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI;
15
+ default: return APP_RSC_RENDER_MODE_NAVIGATION;
16
+ }
17
+ }
18
+ //#endregion
19
+ export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, parseAppRscRenderMode, shouldSuppressLoadingBoundaries, shouldUsePreserveUiCacheVariant };
20
+
21
+ //# sourceMappingURL=app-rsc-render-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-rsc-render-mode.js","names":[],"sources":["../../src/server/app-rsc-render-mode.ts"],"sourcesContent":["export type AppRscRenderMode = \"navigation\" | \"refresh-preserve-ui\" | \"action-rerender-preserve-ui\";\n\nexport const APP_RSC_RENDER_MODE_NAVIGATION = \"navigation\" satisfies AppRscRenderMode;\nexport const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI =\n \"refresh-preserve-ui\" satisfies AppRscRenderMode;\nexport const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI =\n \"action-rerender-preserve-ui\" satisfies AppRscRenderMode;\n\nexport function shouldSuppressLoadingBoundaries(mode: AppRscRenderMode): boolean {\n return (\n mode === APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI ||\n mode === APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI\n );\n}\n\nexport function shouldUsePreserveUiCacheVariant(mode: AppRscRenderMode): boolean {\n return shouldSuppressLoadingBoundaries(mode);\n}\n\nexport function parseAppRscRenderMode(value: string | null): AppRscRenderMode {\n switch (value) {\n case APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI:\n return APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI;\n case APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI:\n return APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI;\n case null:\n default:\n return APP_RSC_RENDER_MODE_NAVIGATION;\n }\n}\n"],"mappings":";AAEA,MAAa,iCAAiC;AAC9C,MAAa,0CACX;AACF,MAAa,kDACX;AAEF,SAAgB,gCAAgC,MAAiC;CAC/E,OACE,SAAA,yBACA,SAAA;;AAIJ,SAAgB,gCAAgC,MAAiC;CAC/E,OAAO,gCAAgC,KAAK;;AAG9C,SAAgB,sBAAsB,OAAwC;CAC5E,QAAQ,OAAR;EACE,KAAK,yCACH,OAAO;EACT,KAAK,iDACH,OAAO;EAET,SACE,OAAO"}
@@ -1,4 +1,5 @@
1
1
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
2
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
2
3
 
3
4
  //#region src/server/app-rsc-request-normalization.d.ts
4
5
  type NormalizedRscRequest = {
@@ -7,7 +8,8 @@ type NormalizedRscRequest = {
7
8
  cleanPathname: string; /** True when the request targets a canonical `.rsc` payload URL. */
8
9
  isRscRequest: boolean; /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
9
10
  interceptionContextHeader: string | null; /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */
10
- mountedSlotsHeader: string | null;
11
+ mountedSlotsHeader: string | null; /** Semantic RSC payload mode. HTML requests always normalize to "navigation". */
12
+ renderMode: AppRscRenderMode;
11
13
  };
12
14
  /**
13
15
  * Normalize an App Router RSC request.
@@ -32,6 +34,7 @@ type NormalizedRscRequest = {
32
34
  * 7. cleanPathname — pathname with `.rsc` suffix stripped
33
35
  * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
34
36
  * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
37
+ * 10. Read semantic render mode for refresh/action payload rendering
35
38
  *
36
39
  * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
37
40
  * or a NormalizedRscRequest for valid requests.
@@ -1,9 +1,11 @@
1
1
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
2
2
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
3
+ import { VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
3
4
  import { normalizePath } from "./normalize-path.js";
4
5
  import { badRequestResponse, notFoundResponse } from "./http-error-responses.js";
5
6
  import { guardProtocolRelativeUrl } from "./request-pipeline.js";
6
7
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
8
+ import { APP_RSC_RENDER_MODE_NAVIGATION, parseAppRscRenderMode } from "./app-rsc-render-mode.js";
7
9
  import { stripRscSuffix } from "./app-rsc-cache-busting.js";
8
10
  //#region src/server/app-rsc-request-normalization.ts
9
11
  /**
@@ -29,6 +31,7 @@ import { stripRscSuffix } from "./app-rsc-cache-busting.js";
29
31
  * 7. cleanPathname — pathname with `.rsc` suffix stripped
30
32
  * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
31
33
  * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
34
+ * 10. Read semantic render mode for refresh/action payload rendering
32
35
  *
33
36
  * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
34
37
  * or a NormalizedRscRequest for valid requests.
@@ -51,14 +54,16 @@ function normalizeRscRequest(request, basePath) {
51
54
  const isRscRequest = pathname.endsWith(".rsc");
52
55
  const cleanPathname = stripRscSuffix(pathname);
53
56
  const interceptionContextHeader = request.headers.get("X-Vinext-Interception-Context")?.replaceAll("\0", "") || null;
54
- const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get("x-vinext-mounted-slots"));
57
+ const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
58
+ const renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
55
59
  return {
56
60
  url,
57
61
  pathname,
58
62
  cleanPathname,
59
63
  isRscRequest,
60
64
  interceptionContextHeader,
61
- mountedSlotsHeader
65
+ mountedSlotsHeader,
66
+ renderMode
62
67
  };
63
68
  }
64
69
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"app-rsc-request-normalization.js","names":[],"sources":["../../src/server/app-rsc-request-normalization.ts"],"sourcesContent":["import { normalizePath } from \"./normalize-path.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport { guardProtocolRelativeUrl } from \"./request-pipeline.js\";\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\nimport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { stripRscSuffix } from \"./app-rsc-cache-busting.js\";\nimport { badRequestResponse, notFoundResponse } from \"./http-error-responses.js\";\n\nexport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\n\nexport type NormalizedRscRequest = {\n /** Parsed URL. Callers may mutate `url.search` after middleware runs. */\n url: URL;\n /** Normalized pathname with basePath stripped. Used for all internal routing. */\n pathname: string;\n /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */\n cleanPathname: string;\n /** True when the request targets a canonical `.rsc` payload URL. */\n isRscRequest: boolean;\n /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */\n interceptionContextHeader: string | null;\n /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */\n mountedSlotsHeader: string | null;\n};\n\n/**\n * Normalize an App Router RSC request.\n *\n * Performs all security-sensitive and compatibility-sensitive preprocessing before\n * route matching. The ordering of steps is security-critical — changing it introduces\n * vulnerabilities:\n *\n * 1. Parse URL\n * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses\n * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`\n * would bypass the check and reach the trailing-slash redirector, which echoes the\n * path into a `Location` header that browsers interpret as protocol-relative.\n * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must\n * run before basePath check so %2F-encoded slashes cannot create fake basePath prefixes.\n * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)\n * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.\n * `/__vinext/` bypasses this for internal prerender endpoints.\n * 6. RSC detection: `.rsc` suffix only. RSC headers do not select payload\n * rendering at the canonical HTML URL, so caches that ignore Vary cannot\n * store Flight responses under HTML URLs.\n * 7. cleanPathname — pathname with `.rsc` suffix stripped\n * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)\n * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys\n *\n * @returns A 400 or 404 Response for invalid or out-of-scope inputs,\n * or a NormalizedRscRequest for valid requests.\n */\nexport function normalizeRscRequest(\n request: Request,\n basePath: string,\n): Response | NormalizedRscRequest {\n const url = new URL(request.url);\n\n // Step 2: Guard against protocol-relative open redirects on the raw pathname.\n // normalizePath (step 4) would collapse //evil.com to /evil.com, causing the\n // guard to miss it. Raw pathname must be checked first.\n const protoGuard = guardProtocolRelativeUrl(url.pathname);\n if (protoGuard) return protoGuard;\n\n // Step 3: Strict segment-wise percent-decode. Preserves encoded path delimiters\n // (%2F stays %2F) to prevent encoded slashes from acting as path separators.\n // Throws on malformed sequences like %GG — caller must return 400.\n let decoded: string;\n try {\n decoded = normalizePathnameForRouteMatchStrict(url.pathname);\n } catch {\n return badRequestResponse();\n }\n\n // Step 4: Collapse double-slashes and resolve . / .. segments.\n let pathname = normalizePath(decoded);\n\n // Step 5: basePath check and strip.\n // Skipped when basePath is empty (no basePath configured).\n // /__vinext/ prefix bypasses the check for internal prerender endpoints\n // that must be reachable regardless of basePath configuration.\n if (basePath) {\n if (!hasBasePath(pathname, basePath) && !pathname.startsWith(\"/__vinext/\")) {\n return notFoundResponse();\n }\n pathname = stripBasePath(pathname, basePath);\n }\n\n // Steps 6-7: RSC detection and cleanPathname.\n const isRscRequest = pathname.endsWith(\".rsc\");\n const cleanPathname = stripRscSuffix(pathname);\n\n // Step 8: Sanitize X-Vinext-Interception-Context.\n // Null bytes in header values can be used for injection in some HTTP stacks.\n const interceptionContextHeader =\n request.headers.get(\"X-Vinext-Interception-Context\")?.replaceAll(\"\\0\", \"\") || null;\n\n // Step 9: Normalize mounted-slots header for canonical cache keying.\n const mountedSlotsHeader = normalizeMountedSlotsHeader(\n request.headers.get(\"x-vinext-mounted-slots\"),\n );\n\n return {\n url,\n pathname,\n cleanPathname,\n isRscRequest,\n interceptionContextHeader,\n mountedSlotsHeader,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,oBACd,SACA,UACiC;CACjC,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;CAKhC,MAAM,aAAa,yBAAyB,IAAI,SAAS;AACzD,KAAI,WAAY,QAAO;CAKvB,IAAI;AACJ,KAAI;AACF,YAAU,qCAAqC,IAAI,SAAS;SACtD;AACN,SAAO,oBAAoB;;CAI7B,IAAI,WAAW,cAAc,QAAQ;AAMrC,KAAI,UAAU;AACZ,MAAI,CAAC,YAAY,UAAU,SAAS,IAAI,CAAC,SAAS,WAAW,aAAa,CACxE,QAAO,kBAAkB;AAE3B,aAAW,cAAc,UAAU,SAAS;;CAI9C,MAAM,eAAe,SAAS,SAAS,OAAO;CAC9C,MAAM,gBAAgB,eAAe,SAAS;CAI9C,MAAM,4BACJ,QAAQ,QAAQ,IAAI,gCAAgC,EAAE,WAAW,MAAM,GAAG,IAAI;CAGhF,MAAM,qBAAqB,4BACzB,QAAQ,QAAQ,IAAI,yBAAyB,CAC9C;AAED,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
1
+ {"version":3,"file":"app-rsc-request-normalization.js","names":[],"sources":["../../src/server/app-rsc-request-normalization.ts"],"sourcesContent":["import { normalizePath } from \"./normalize-path.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport { guardProtocolRelativeUrl } from \"./request-pipeline.js\";\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\nimport {\n VINEXT_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_RSC_RENDER_MODE_HEADER,\n} from \"./headers.js\";\nimport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { stripRscSuffix } from \"./app-rsc-cache-busting.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n parseAppRscRenderMode,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport { badRequestResponse, notFoundResponse } from \"./http-error-responses.js\";\n\nexport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\n\nexport type NormalizedRscRequest = {\n /** Parsed URL. Callers may mutate `url.search` after middleware runs. */\n url: URL;\n /** Normalized pathname with basePath stripped. Used for all internal routing. */\n pathname: string;\n /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */\n cleanPathname: string;\n /** True when the request targets a canonical `.rsc` payload URL. */\n isRscRequest: boolean;\n /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */\n interceptionContextHeader: string | null;\n /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */\n mountedSlotsHeader: string | null;\n /** Semantic RSC payload mode. HTML requests always normalize to \"navigation\". */\n renderMode: AppRscRenderMode;\n};\n\n/**\n * Normalize an App Router RSC request.\n *\n * Performs all security-sensitive and compatibility-sensitive preprocessing before\n * route matching. The ordering of steps is security-critical — changing it introduces\n * vulnerabilities:\n *\n * 1. Parse URL\n * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses\n * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`\n * would bypass the check and reach the trailing-slash redirector, which echoes the\n * path into a `Location` header that browsers interpret as protocol-relative.\n * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must\n * run before basePath check so %2F-encoded slashes cannot create fake basePath prefixes.\n * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)\n * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.\n * `/__vinext/` bypasses this for internal prerender endpoints.\n * 6. RSC detection: `.rsc` suffix only. RSC headers do not select payload\n * rendering at the canonical HTML URL, so caches that ignore Vary cannot\n * store Flight responses under HTML URLs.\n * 7. cleanPathname — pathname with `.rsc` suffix stripped\n * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)\n * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys\n * 10. Read semantic render mode for refresh/action payload rendering\n *\n * @returns A 400 or 404 Response for invalid or out-of-scope inputs,\n * or a NormalizedRscRequest for valid requests.\n */\nexport function normalizeRscRequest(\n request: Request,\n basePath: string,\n): Response | NormalizedRscRequest {\n const url = new URL(request.url);\n\n // Step 2: Guard against protocol-relative open redirects on the raw pathname.\n // normalizePath (step 4) would collapse //evil.com to /evil.com, causing the\n // guard to miss it. Raw pathname must be checked first.\n const protoGuard = guardProtocolRelativeUrl(url.pathname);\n if (protoGuard) return protoGuard;\n\n // Step 3: Strict segment-wise percent-decode. Preserves encoded path delimiters\n // (%2F stays %2F) to prevent encoded slashes from acting as path separators.\n // Throws on malformed sequences like %GG — caller must return 400.\n let decoded: string;\n try {\n decoded = normalizePathnameForRouteMatchStrict(url.pathname);\n } catch {\n return badRequestResponse();\n }\n\n // Step 4: Collapse double-slashes and resolve . / .. segments.\n let pathname = normalizePath(decoded);\n\n // Step 5: basePath check and strip.\n // Skipped when basePath is empty (no basePath configured).\n // /__vinext/ prefix bypasses the check for internal prerender endpoints\n // that must be reachable regardless of basePath configuration.\n if (basePath) {\n if (!hasBasePath(pathname, basePath) && !pathname.startsWith(\"/__vinext/\")) {\n return notFoundResponse();\n }\n pathname = stripBasePath(pathname, basePath);\n }\n\n // Steps 6-7: RSC detection and cleanPathname.\n const isRscRequest = pathname.endsWith(\".rsc\");\n const cleanPathname = stripRscSuffix(pathname);\n\n // Step 8: Sanitize X-Vinext-Interception-Context.\n // Null bytes in header values can be used for injection in some HTTP stacks.\n const interceptionContextHeader =\n request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER)?.replaceAll(\"\\0\", \"\") || null;\n\n // Step 9: Normalize mounted-slots header for canonical cache keying.\n const mountedSlotsHeader = normalizeMountedSlotsHeader(\n request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER),\n );\n const renderMode = isRscRequest\n ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER))\n : APP_RSC_RENDER_MODE_NAVIGATION;\n\n return {\n url,\n pathname,\n cleanPathname,\n isRscRequest,\n interceptionContextHeader,\n mountedSlotsHeader,\n renderMode,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,SAAgB,oBACd,SACA,UACiC;CACjC,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;CAKhC,MAAM,aAAa,yBAAyB,IAAI,SAAS;CACzD,IAAI,YAAY,OAAO;CAKvB,IAAI;CACJ,IAAI;EACF,UAAU,qCAAqC,IAAI,SAAS;SACtD;EACN,OAAO,oBAAoB;;CAI7B,IAAI,WAAW,cAAc,QAAQ;CAMrC,IAAI,UAAU;EACZ,IAAI,CAAC,YAAY,UAAU,SAAS,IAAI,CAAC,SAAS,WAAW,aAAa,EACxE,OAAO,kBAAkB;EAE3B,WAAW,cAAc,UAAU,SAAS;;CAI9C,MAAM,eAAe,SAAS,SAAS,OAAO;CAC9C,MAAM,gBAAgB,eAAe,SAAS;CAI9C,MAAM,4BACJ,QAAQ,QAAQ,IAAA,gCAAuC,EAAE,WAAW,MAAM,GAAG,IAAI;CAGnF,MAAM,qBAAqB,4BACzB,QAAQ,QAAQ,IAAI,4BAA4B,CACjD;CACD,MAAM,aAAa,eACf,sBAAsB,QAAQ,QAAQ,IAAI,8BAA8B,CAAC,GACzE;CAEJ,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
@@ -14,7 +14,8 @@ type FinalizeAppRscResponseOptions = {
14
14
  requestContext: RequestContext;
15
15
  };
16
16
  /**
17
- * Apply next.config.js response headers to an App Router response.
17
+ * Apply App Router response finalization that must happen outside individual
18
+ * route dispatchers.
18
19
  *
19
20
  * Called once per request in the outer handler() wrapper, after all route
20
21
  * handling, so that every response path (page, route handler, server action,
@@ -1,10 +1,14 @@
1
1
  import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
2
  import { stripBasePath } from "../utils/base-path.js";
3
+ import "./headers.js";
3
4
  import { normalizePath } from "./normalize-path.js";
4
5
  import { applyConfigHeadersToResponse } from "./request-pipeline.js";
6
+ import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-cache-busting.js";
7
+ import { mergeVaryHeader } from "./middleware-response-headers.js";
5
8
  //#region src/server/app-rsc-response-finalizer.ts
6
9
  /**
7
- * Apply next.config.js response headers to an App Router response.
10
+ * Apply App Router response finalization that must happen outside individual
11
+ * route dispatchers.
8
12
  *
9
13
  * Called once per request in the outer handler() wrapper, after all route
10
14
  * handling, so that every response path (page, route handler, server action,
@@ -16,6 +20,7 @@ import { applyConfigHeadersToResponse } from "./request-pipeline.js";
16
20
  */
17
21
  function finalizeAppRscResponse(response, request, options) {
18
22
  if (response.status >= 300 && response.status < 400) return response;
23
+ if (!response.headers.has("x-vinext-static-file")) mergeVaryHeader(response.headers, VINEXT_RSC_VARY_HEADER);
19
24
  if (!options.configHeaders.length) return response;
20
25
  const url = new URL(request.url);
21
26
  let pathname;