vinext 0.0.52 → 0.0.54

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 (330) hide show
  1. package/README.md +1 -1
  2. package/dist/build/clean-output.d.ts +14 -0
  3. package/dist/build/clean-output.js +36 -0
  4. package/dist/build/clean-output.js.map +1 -0
  5. package/dist/build/inline-css.d.ts +7 -0
  6. package/dist/build/inline-css.js +50 -0
  7. package/dist/build/inline-css.js.map +1 -0
  8. package/dist/build/prerender.d.ts +6 -2
  9. package/dist/build/prerender.js +51 -12
  10. package/dist/build/prerender.js.map +1 -1
  11. package/dist/build/run-prerender.js +10 -1
  12. package/dist/build/run-prerender.js.map +1 -1
  13. package/dist/build/static-export.d.ts +5 -0
  14. package/dist/build/static-export.js +8 -3
  15. package/dist/build/static-export.js.map +1 -1
  16. package/dist/check.js +4 -0
  17. package/dist/check.js.map +1 -1
  18. package/dist/cli.js +19 -4
  19. package/dist/cli.js.map +1 -1
  20. package/dist/client/instrumentation-client-inject.d.ts +34 -0
  21. package/dist/client/instrumentation-client-inject.js +57 -0
  22. package/dist/client/instrumentation-client-inject.js.map +1 -0
  23. package/dist/client/navigation-runtime.d.ts +16 -2
  24. package/dist/client/navigation-runtime.js +16 -1
  25. package/dist/client/navigation-runtime.js.map +1 -1
  26. package/dist/client/vinext-next-data.d.ts +2 -1
  27. package/dist/client/vinext-next-data.js.map +1 -1
  28. package/dist/client/window-next.d.ts +17 -2
  29. package/dist/client/window-next.js.map +1 -1
  30. package/dist/cloudflare/tpr.js +1 -1
  31. package/dist/cloudflare/tpr.js.map +1 -1
  32. package/dist/config/config-matchers.js +2 -1
  33. package/dist/config/config-matchers.js.map +1 -1
  34. package/dist/config/next-config.d.ts +95 -4
  35. package/dist/config/next-config.js +173 -14
  36. package/dist/config/next-config.js.map +1 -1
  37. package/dist/deploy.js +42 -7
  38. package/dist/deploy.js.map +1 -1
  39. package/dist/entries/app-browser-entry.d.ts +11 -1
  40. package/dist/entries/app-browser-entry.js +16 -6
  41. package/dist/entries/app-browser-entry.js.map +1 -1
  42. package/dist/entries/app-rsc-entry.d.ts +12 -3
  43. package/dist/entries/app-rsc-entry.js +41 -8
  44. package/dist/entries/app-rsc-entry.js.map +1 -1
  45. package/dist/entries/app-rsc-manifest.d.ts +21 -1
  46. package/dist/entries/app-rsc-manifest.js +6 -4
  47. package/dist/entries/app-rsc-manifest.js.map +1 -1
  48. package/dist/entries/pages-client-entry.d.ts +4 -1
  49. package/dist/entries/pages-client-entry.js +40 -3
  50. package/dist/entries/pages-client-entry.js.map +1 -1
  51. package/dist/entries/pages-server-entry.js +292 -34
  52. package/dist/entries/pages-server-entry.js.map +1 -1
  53. package/dist/entries/runtime-entry-module.d.ts +1 -10
  54. package/dist/entries/runtime-entry-module.js +2 -12
  55. package/dist/entries/runtime-entry-module.js.map +1 -1
  56. package/dist/index.js +91 -10
  57. package/dist/index.js.map +1 -1
  58. package/dist/plugins/fonts.js +25 -2
  59. package/dist/plugins/fonts.js.map +1 -1
  60. package/dist/plugins/remove-console.d.ts +16 -0
  61. package/dist/plugins/remove-console.js +176 -0
  62. package/dist/plugins/remove-console.js.map +1 -0
  63. package/dist/routing/app-route-graph.d.ts +24 -1
  64. package/dist/routing/app-route-graph.js +52 -4
  65. package/dist/routing/app-route-graph.js.map +1 -1
  66. package/dist/routing/app-router.d.ts +2 -2
  67. package/dist/routing/app-router.js +2 -2
  68. package/dist/routing/app-router.js.map +1 -1
  69. package/dist/routing/file-matcher.d.ts +21 -1
  70. package/dist/routing/file-matcher.js +39 -1
  71. package/dist/routing/file-matcher.js.map +1 -1
  72. package/dist/routing/pages-router.d.ts +1 -1
  73. package/dist/routing/pages-router.js +10 -3
  74. package/dist/routing/pages-router.js.map +1 -1
  75. package/dist/routing/route-trie.js +13 -18
  76. package/dist/routing/route-trie.js.map +1 -1
  77. package/dist/routing/utils.d.ts +11 -1
  78. package/dist/routing/utils.js +15 -1
  79. package/dist/routing/utils.js.map +1 -1
  80. package/dist/server/api-handler.js +19 -10
  81. package/dist/server/api-handler.js.map +1 -1
  82. package/dist/server/app-browser-action-result.d.ts +16 -1
  83. package/dist/server/app-browser-action-result.js +15 -1
  84. package/dist/server/app-browser-action-result.js.map +1 -1
  85. package/dist/server/app-browser-entry.js +47 -28
  86. package/dist/server/app-browser-entry.js.map +1 -1
  87. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  88. package/dist/server/app-browser-navigation-controller.js +4 -0
  89. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  90. package/dist/server/app-elements-wire.d.ts +13 -4
  91. package/dist/server/app-elements-wire.js +10 -1
  92. package/dist/server/app-elements-wire.js.map +1 -1
  93. package/dist/server/app-elements.d.ts +2 -2
  94. package/dist/server/app-elements.js +2 -2
  95. package/dist/server/app-elements.js.map +1 -1
  96. package/dist/server/app-fallback-renderer.d.ts +27 -8
  97. package/dist/server/app-fallback-renderer.js +19 -8
  98. package/dist/server/app-fallback-renderer.js.map +1 -1
  99. package/dist/server/app-history-state.js +6 -2
  100. package/dist/server/app-history-state.js.map +1 -1
  101. package/dist/server/app-inline-css-client.d.ts +7 -0
  102. package/dist/server/app-inline-css-client.js +37 -0
  103. package/dist/server/app-inline-css-client.js.map +1 -0
  104. package/dist/server/app-interception-context-header.d.ts +33 -0
  105. package/dist/server/app-interception-context-header.js +44 -0
  106. package/dist/server/app-interception-context-header.js.map +1 -0
  107. package/dist/server/app-mounted-slots-header.d.ts +19 -0
  108. package/dist/server/app-mounted-slots-header.js +40 -1
  109. package/dist/server/app-mounted-slots-header.js.map +1 -1
  110. package/dist/server/app-optimistic-routing.js +26 -18
  111. package/dist/server/app-optimistic-routing.js.map +1 -1
  112. package/dist/server/app-page-boundary-render.d.ts +1 -0
  113. package/dist/server/app-page-boundary-render.js +2 -0
  114. package/dist/server/app-page-boundary-render.js.map +1 -1
  115. package/dist/server/app-page-boundary.d.ts +22 -1
  116. package/dist/server/app-page-boundary.js +30 -3
  117. package/dist/server/app-page-boundary.js.map +1 -1
  118. package/dist/server/app-page-cache.d.ts +9 -3
  119. package/dist/server/app-page-cache.js +14 -8
  120. package/dist/server/app-page-cache.js.map +1 -1
  121. package/dist/server/app-page-dispatch.d.ts +13 -1
  122. package/dist/server/app-page-dispatch.js +136 -82
  123. package/dist/server/app-page-dispatch.js.map +1 -1
  124. package/dist/server/app-page-element-builder.d.ts +2 -1
  125. package/dist/server/app-page-element-builder.js +17 -30
  126. package/dist/server/app-page-element-builder.js.map +1 -1
  127. package/dist/server/app-page-execution.d.ts +1 -0
  128. package/dist/server/app-page-execution.js +2 -0
  129. package/dist/server/app-page-execution.js.map +1 -1
  130. package/dist/server/app-page-head.d.ts +1 -0
  131. package/dist/server/app-page-head.js +8 -0
  132. package/dist/server/app-page-head.js.map +1 -1
  133. package/dist/server/app-page-render-identity.d.ts +22 -0
  134. package/dist/server/app-page-render-identity.js +42 -0
  135. package/dist/server/app-page-render-identity.js.map +1 -0
  136. package/dist/server/app-page-render-observation.js +1 -1
  137. package/dist/server/app-page-render.d.ts +9 -1
  138. package/dist/server/app-page-render.js +8 -2
  139. package/dist/server/app-page-render.js.map +1 -1
  140. package/dist/server/app-page-request.d.ts +6 -3
  141. package/dist/server/app-page-request.js +5 -2
  142. package/dist/server/app-page-request.js.map +1 -1
  143. package/dist/server/app-page-response.d.ts +11 -1
  144. package/dist/server/app-page-response.js +16 -4
  145. package/dist/server/app-page-response.js.map +1 -1
  146. package/dist/server/app-page-route-wiring.d.ts +16 -0
  147. package/dist/server/app-page-route-wiring.js +25 -10
  148. package/dist/server/app-page-route-wiring.js.map +1 -1
  149. package/dist/server/app-page-stream.d.ts +12 -0
  150. package/dist/server/app-page-stream.js +3 -0
  151. package/dist/server/app-page-stream.js.map +1 -1
  152. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  153. package/dist/server/app-route-handler-dispatch.js +3 -0
  154. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  155. package/dist/server/app-route-handler-execution.d.ts +1 -0
  156. package/dist/server/app-route-handler-execution.js +1 -0
  157. package/dist/server/app-route-handler-execution.js.map +1 -1
  158. package/dist/server/app-route-handler-response.js +38 -6
  159. package/dist/server/app-route-handler-response.js.map +1 -1
  160. package/dist/server/app-rsc-handler.d.ts +16 -3
  161. package/dist/server/app-rsc-handler.js +60 -11
  162. package/dist/server/app-rsc-handler.js.map +1 -1
  163. package/dist/server/app-rsc-request-normalization.d.ts +2 -1
  164. package/dist/server/app-rsc-request-normalization.js +6 -4
  165. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  166. package/dist/server/app-segment-config.d.ts +4 -1
  167. package/dist/server/app-segment-config.js +6 -1
  168. package/dist/server/app-segment-config.js.map +1 -1
  169. package/dist/server/app-server-action-execution.d.ts +22 -3
  170. package/dist/server/app-server-action-execution.js +46 -7
  171. package/dist/server/app-server-action-execution.js.map +1 -1
  172. package/dist/server/app-ssr-entry.d.ts +6 -0
  173. package/dist/server/app-ssr-entry.js +57 -6
  174. package/dist/server/app-ssr-entry.js.map +1 -1
  175. package/dist/server/app-ssr-error-meta.js +3 -3
  176. package/dist/server/app-ssr-error-meta.js.map +1 -1
  177. package/dist/server/app-ssr-stream.d.ts +25 -1
  178. package/dist/server/app-ssr-stream.js +237 -19
  179. package/dist/server/app-ssr-stream.js.map +1 -1
  180. package/dist/server/app-static-generation.d.ts +1 -0
  181. package/dist/server/app-static-generation.js +2 -1
  182. package/dist/server/app-static-generation.js.map +1 -1
  183. package/dist/server/client-trace-metadata.d.ts +31 -0
  184. package/dist/server/client-trace-metadata.js +83 -0
  185. package/dist/server/client-trace-metadata.js.map +1 -0
  186. package/dist/server/cookie-utils.d.ts +13 -0
  187. package/dist/server/cookie-utils.js +20 -0
  188. package/dist/server/cookie-utils.js.map +1 -0
  189. package/dist/server/default-not-found-module.d.ts +20 -0
  190. package/dist/server/default-not-found-module.js +20 -0
  191. package/dist/server/default-not-found-module.js.map +1 -0
  192. package/dist/server/dev-server.d.ts +8 -1
  193. package/dist/server/dev-server.js +56 -11
  194. package/dist/server/dev-server.js.map +1 -1
  195. package/dist/server/headers.d.ts +5 -1
  196. package/dist/server/headers.js +5 -1
  197. package/dist/server/headers.js.map +1 -1
  198. package/dist/server/html.d.ts +2 -1
  199. package/dist/server/html.js +6 -1
  200. package/dist/server/html.js.map +1 -1
  201. package/dist/server/image-optimization.d.ts +13 -4
  202. package/dist/server/image-optimization.js +15 -4
  203. package/dist/server/image-optimization.js.map +1 -1
  204. package/dist/server/isr-cache.d.ts +7 -5
  205. package/dist/server/isr-cache.js +17 -6
  206. package/dist/server/isr-cache.js.map +1 -1
  207. package/dist/server/middleware-runtime.js +1 -2
  208. package/dist/server/middleware-runtime.js.map +1 -1
  209. package/dist/server/middleware.js +1 -1
  210. package/dist/server/middleware.js.map +1 -1
  211. package/dist/server/pages-api-route.d.ts +18 -0
  212. package/dist/server/pages-api-route.js +3 -1
  213. package/dist/server/pages-api-route.js.map +1 -1
  214. package/dist/server/pages-body-parser-config.d.ts +60 -0
  215. package/dist/server/pages-body-parser-config.js +79 -0
  216. package/dist/server/pages-body-parser-config.js.map +1 -0
  217. package/dist/server/pages-data-route.js +1 -0
  218. package/dist/server/pages-data-route.js.map +1 -1
  219. package/dist/server/pages-default-404.d.ts +31 -0
  220. package/dist/server/pages-default-404.js +40 -0
  221. package/dist/server/pages-default-404.js.map +1 -0
  222. package/dist/server/pages-document-initial-props.d.ts +7 -0
  223. package/dist/server/pages-document-initial-props.js +14 -0
  224. package/dist/server/pages-document-initial-props.js.map +1 -0
  225. package/dist/server/pages-node-compat.d.ts +10 -0
  226. package/dist/server/pages-node-compat.js +12 -1
  227. package/dist/server/pages-node-compat.js.map +1 -1
  228. package/dist/server/pages-page-data.d.ts +40 -0
  229. package/dist/server/pages-page-data.js +19 -14
  230. package/dist/server/pages-page-data.js.map +1 -1
  231. package/dist/server/pages-page-method.d.ts +48 -0
  232. package/dist/server/pages-page-method.js +19 -0
  233. package/dist/server/pages-page-method.js.map +1 -0
  234. package/dist/server/pages-page-response.d.ts +8 -0
  235. package/dist/server/pages-page-response.js +21 -11
  236. package/dist/server/pages-page-response.js.map +1 -1
  237. package/dist/server/pages-serializable-props.d.ts +25 -0
  238. package/dist/server/pages-serializable-props.js +69 -0
  239. package/dist/server/pages-serializable-props.js.map +1 -0
  240. package/dist/server/prerender-route-params.d.ts +14 -0
  241. package/dist/server/prerender-route-params.js +94 -0
  242. package/dist/server/prerender-route-params.js.map +1 -0
  243. package/dist/server/prod-server.d.ts +3 -23
  244. package/dist/server/prod-server.js +43 -57
  245. package/dist/server/prod-server.js.map +1 -1
  246. package/dist/server/proxy-trust.d.ts +41 -0
  247. package/dist/server/proxy-trust.js +70 -0
  248. package/dist/server/proxy-trust.js.map +1 -0
  249. package/dist/server/request-pipeline.d.ts +3 -3
  250. package/dist/server/request-pipeline.js +5 -4
  251. package/dist/server/request-pipeline.js.map +1 -1
  252. package/dist/server/seed-cache.js +12 -6
  253. package/dist/server/seed-cache.js.map +1 -1
  254. package/dist/server/server-action-not-found.js +3 -2
  255. package/dist/server/server-action-not-found.js.map +1 -1
  256. package/dist/server/static-file-cache.js +2 -1
  257. package/dist/server/static-file-cache.js.map +1 -1
  258. package/dist/server/streaming-metadata.d.ts +5 -0
  259. package/dist/server/streaming-metadata.js +10 -0
  260. package/dist/server/streaming-metadata.js.map +1 -0
  261. package/dist/shims/app-router-scroll-state.d.ts +14 -0
  262. package/dist/shims/app-router-scroll-state.js +51 -0
  263. package/dist/shims/app-router-scroll-state.js.map +1 -0
  264. package/dist/shims/app-router-scroll.d.ts +28 -0
  265. package/dist/shims/app-router-scroll.js +115 -0
  266. package/dist/shims/app-router-scroll.js.map +1 -0
  267. package/dist/shims/before-interactive-context.d.ts +30 -0
  268. package/dist/shims/before-interactive-context.js +10 -0
  269. package/dist/shims/before-interactive-context.js.map +1 -0
  270. package/dist/shims/cache-runtime.d.ts +1 -1
  271. package/dist/shims/cache-runtime.js +14 -1
  272. package/dist/shims/cache-runtime.js.map +1 -1
  273. package/dist/shims/cache.d.ts +6 -0
  274. package/dist/shims/cache.js +7 -0
  275. package/dist/shims/cache.js.map +1 -1
  276. package/dist/shims/default-not-found.d.ts +12 -0
  277. package/dist/shims/default-not-found.js +61 -0
  278. package/dist/shims/default-not-found.js.map +1 -0
  279. package/dist/shims/error.js +3 -0
  280. package/dist/shims/error.js.map +1 -1
  281. package/dist/shims/font-local.d.ts +5 -0
  282. package/dist/shims/font-local.js +6 -2
  283. package/dist/shims/font-local.js.map +1 -1
  284. package/dist/shims/head.js +4 -4
  285. package/dist/shims/head.js.map +1 -1
  286. package/dist/shims/headers.d.ts +13 -2
  287. package/dist/shims/headers.js +73 -22
  288. package/dist/shims/headers.js.map +1 -1
  289. package/dist/shims/image.d.ts +1 -1
  290. package/dist/shims/image.js +4 -4
  291. package/dist/shims/image.js.map +1 -1
  292. package/dist/shims/internal/app-route-detection.d.ts +37 -0
  293. package/dist/shims/internal/app-route-detection.js +69 -0
  294. package/dist/shims/internal/app-route-detection.js.map +1 -0
  295. package/dist/shims/internal/pages-data-target.d.ts +58 -0
  296. package/dist/shims/internal/pages-data-target.js +91 -0
  297. package/dist/shims/internal/pages-data-target.js.map +1 -0
  298. package/dist/shims/internal/pages-data-url.d.ts +42 -0
  299. package/dist/shims/internal/pages-data-url.js +73 -0
  300. package/dist/shims/internal/pages-data-url.js.map +1 -0
  301. package/dist/shims/link.d.ts +18 -2
  302. package/dist/shims/link.js +129 -15
  303. package/dist/shims/link.js.map +1 -1
  304. package/dist/shims/metadata.d.ts +9 -7
  305. package/dist/shims/metadata.js +70 -7
  306. package/dist/shims/metadata.js.map +1 -1
  307. package/dist/shims/navigation.d.ts +1 -2
  308. package/dist/shims/navigation.js +94 -20
  309. package/dist/shims/navigation.js.map +1 -1
  310. package/dist/shims/router.d.ts +5 -0
  311. package/dist/shims/router.js +389 -80
  312. package/dist/shims/router.js.map +1 -1
  313. package/dist/shims/script.d.ts +11 -1
  314. package/dist/shims/script.js +158 -15
  315. package/dist/shims/script.js.map +1 -1
  316. package/dist/shims/server.js +1 -0
  317. package/dist/shims/server.js.map +1 -1
  318. package/dist/shims/url-utils.d.ts +2 -1
  319. package/dist/shims/url-utils.js +15 -4
  320. package/dist/shims/url-utils.js.map +1 -1
  321. package/dist/utils/html-limited-bots.d.ts +5 -0
  322. package/dist/utils/html-limited-bots.js +15 -0
  323. package/dist/utils/html-limited-bots.js.map +1 -0
  324. package/dist/utils/path.d.ts +13 -0
  325. package/dist/utils/path.js +16 -0
  326. package/dist/utils/path.js.map +1 -0
  327. package/dist/utils/query.d.ts +6 -0
  328. package/dist/utils/query.js +10 -1
  329. package/dist/utils/query.js.map +1 -1
  330. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"api-handler.js","names":["decodeQueryString"],"sources":["../../src/server/api-handler.ts"],"sourcesContent":["/**\n * API route handler for Pages Router (pages/api/*).\n *\n * Next.js API routes export a default handler function:\n * export default function handler(req, res) { ... }\n *\n * The req/res objects are Node.js IncomingMessage/ServerResponse with\n * Next.js extensions: req.query, req.body, res.json(), res.status(), etc.\n */\nimport \"./server-globals.js\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { decode as decodeQueryString } from \"node:querystring\";\nimport { Buffer } from \"node:buffer\";\nimport { type Route, matchRoute } from \"../routing/pages-router.js\";\nimport { reportRequestError, importModule, type ModuleImporter } from \"./instrumentation.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport { PagesBodyParseError, getMediaType, isJsonMediaType } from \"./pages-media-type.js\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\nimport { NextRequest } from \"vinext/shims/server\";\n\n/**\n * Extend the Node.js request with Next.js-style helpers.\n */\ntype NextApiRequest = {\n query: Record<string, string | string[]>;\n body: unknown;\n cookies: Record<string, string>;\n} & IncomingMessage;\n\n/**\n * Extend the Node.js response with Next.js-style helpers.\n */\ntype NextApiResponse = {\n status(code: number): NextApiResponse;\n json(data: unknown): void;\n send(data: unknown): void;\n redirect(statusOrUrl: number | string, url?: string): void;\n} & ServerResponse;\n\ntype EdgeApiRouteModule = {\n /**\n * `export const config = { runtime: 'edge' }` — historical Pages Router form.\n */\n config?: {\n runtime?: string;\n };\n /**\n * `export const runtime = 'edge'` — bare export form. Next.js resolves the\n * effective runtime as `config.runtime ?? config.config?.runtime`, so a\n * top-level `runtime` export takes precedence over the nested config form.\n */\n runtime?: string;\n default: (request: Request) => Response | Promise<Response>;\n};\n\n/**\n * Maximum request body size (1 MB). Matches Next.js default bodyParser sizeLimit.\n * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config\n * Prevents denial-of-service via unbounded request body buffering.\n */\nconst MAX_BODY_SIZE = 1 * 1024 * 1024;\n\n/**\n * Parse the request body based on content-type.\n * Enforces a size limit to prevent memory exhaustion attacks.\n */\nasync function parseBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let settled = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > MAX_BODY_SIZE) {\n settled = true;\n req.destroy();\n reject(new PagesBodyParseError(\"Request body too large\", 413));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"error\", (err) => {\n if (!settled) {\n settled = true;\n reject(err);\n }\n });\n req.on(\"end\", () => {\n if (settled) return;\n settled = true;\n const raw = Buffer.concat(chunks).toString(\"utf-8\");\n const mediaType = getMediaType(req.headers[\"content-type\"]);\n if (!raw) {\n resolve(\n isJsonMediaType(mediaType)\n ? {}\n : mediaType === \"application/x-www-form-urlencoded\"\n ? decodeQueryString(raw)\n : undefined,\n );\n return;\n }\n if (isJsonMediaType(mediaType)) {\n try {\n resolve(JSON.parse(raw));\n } catch {\n reject(new PagesBodyParseError(\"Invalid JSON\", 400));\n }\n } else if (mediaType === \"application/x-www-form-urlencoded\") {\n resolve(decodeQueryString(raw));\n } else {\n resolve(raw);\n }\n });\n });\n}\n\n/**\n * Parse cookies from the Cookie header.\n */\nfunction parseCookies(req: IncomingMessage): Record<string, string> {\n const header = req.headers.cookie ?? \"\";\n const cookies: Record<string, string> = {};\n for (const part of header.split(\";\")) {\n const [key, ...rest] = part.split(\"=\");\n if (key) {\n cookies[key.trim()] = rest.join(\"=\").trim();\n }\n }\n return cookies;\n}\n\nfunction isEdgeApiRouteModule(module: Record<string, unknown>): module is EdgeApiRouteModule {\n if (typeof module.default !== \"function\") return false;\n // Bare `export const runtime = 'edge'` takes precedence over the nested config\n // form, matching Next.js (`config.runtime ?? config.config?.runtime` in\n // packages/next/src/build/analysis/get-page-static-info.ts).\n const bare = module.runtime;\n if (typeof bare === \"string\") return isEdgeApiRuntime(bare);\n const config = module.config;\n if (!config || typeof config !== \"object\") return false;\n const runtime = \"runtime\" in config ? (config as { runtime?: unknown }).runtime : undefined;\n return typeof runtime === \"string\" && isEdgeApiRuntime(runtime);\n}\n\nfunction readEdgeRequestBody(req: IncomingMessage): ReadableStream<Uint8Array> | undefined {\n if (req.method === \"GET\" || req.method === \"HEAD\") return undefined;\n return new ReadableStream<Uint8Array>({\n start(controller) {\n req.on(\"data\", (chunk: Buffer | string) => {\n controller.enqueue(typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk));\n });\n req.on(\"end\", () => controller.close());\n req.on(\"error\", (error) => controller.error(error));\n },\n });\n}\n\nfunction createEdgeApiRequest(req: IncomingMessage, url: string): Request {\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (Array.isArray(value)) {\n for (const item of value) headers.append(name, item);\n } else if (value !== undefined) {\n headers.set(name, value);\n }\n }\n\n const rawProto = headers.get(\"x-forwarded-proto\")?.split(\",\")[0]?.trim();\n const forwardedProto = rawProto === \"https\" || rawProto === \"http\" ? rawProto : \"http\";\n const host = headers.get(\"host\") ?? \"localhost\";\n const requestUrl = new URL(url, `${forwardedProto}://${host}`);\n const body = readEdgeRequestBody(req);\n\n const init: RequestInit & { duplex?: \"half\" } = {\n headers,\n method: req.method,\n };\n\n if (body) {\n init.body = body;\n init.duplex = \"half\";\n }\n\n return new Request(requestUrl, init);\n}\n\nfunction waitForWritableDrain(res: ServerResponse): Promise<void> {\n return new Promise((resolve, reject) => {\n const cleanup = () => {\n res.off(\"drain\", onDrain);\n res.off(\"error\", onError);\n res.off(\"close\", onClose);\n };\n const onDrain = () => {\n cleanup();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const onClose = () => {\n cleanup();\n reject(new Error(\"Response closed before writable drain\"));\n };\n res.once(\"drain\", onDrain);\n res.once(\"error\", onError);\n res.once(\"close\", onClose);\n });\n}\n\nasync function writeEdgeApiResponseBody(\n res: ServerResponse,\n body: ReadableStream<Uint8Array> | null,\n): Promise<void> {\n if (!body) {\n res.end();\n return;\n }\n\n const reader = body.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n if (result.value.byteLength === 0) continue;\n if (!res.write(Buffer.from(result.value))) {\n await waitForWritableDrain(res);\n }\n }\n res.end();\n } catch (error) {\n res.destroy(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Enhance a Node.js req/res pair with Next.js API route helpers.\n */\nfunction enhanceApiObjects(\n req: IncomingMessage,\n res: ServerResponse,\n query: Record<string, string | string[]>,\n body: unknown,\n): { apiReq: NextApiRequest; apiRes: NextApiResponse } {\n const apiReq: NextApiRequest = Object.assign(req, {\n body,\n cookies: parseCookies(req),\n query,\n });\n\n const apiRes: NextApiResponse = Object.assign(res, {\n status(this: NextApiResponse, code: number) {\n this.statusCode = code;\n return this;\n },\n\n json(this: NextApiResponse, data: unknown) {\n this.setHeader(\"Content-Type\", \"application/json\");\n this.end(JSON.stringify(data));\n },\n\n send(this: NextApiResponse, data: unknown) {\n if (Buffer.isBuffer(data)) {\n if (!this.getHeader(\"Content-Type\")) {\n this.setHeader(\"Content-Type\", \"application/octet-stream\");\n }\n this.setHeader(\"Content-Length\", String(data.length));\n this.end(data);\n return;\n }\n\n if (typeof data === \"object\" && data !== null) {\n this.setHeader(\"Content-Type\", \"application/json\");\n this.end(JSON.stringify(data));\n } else {\n if (!this.getHeader(\"Content-Type\")) {\n this.setHeader(\"Content-Type\", \"text/plain\");\n }\n this.end(String(data));\n }\n },\n\n redirect(this: NextApiResponse, statusOrUrl: number | string, url?: string) {\n if (typeof statusOrUrl === \"string\") {\n this.writeHead(307, { Location: statusOrUrl });\n } else {\n this.writeHead(statusOrUrl, { Location: url ?? \"\" });\n }\n this.end();\n },\n });\n\n return { apiReq, apiRes };\n}\n\n/**\n * Handle an API route request.\n * Returns true if the request was handled, false if no API route matched.\n */\nexport async function handleApiRoute(\n runner: ModuleImporter,\n req: IncomingMessage,\n res: ServerResponse,\n url: string,\n apiRoutes: Route[],\n): Promise<boolean> {\n const match = matchRoute(url, apiRoutes);\n if (!match) return false;\n\n const { route, params } = match;\n\n try {\n // Load the API route module through the ModuleRunner\n const apiModule = await importModule(runner, route.filePath);\n if (isEdgeApiRouteModule(apiModule)) {\n // Next.js wraps the incoming Request in a NextRequest before invoking\n // edge API handlers, so handlers can use `req.nextUrl.searchParams`,\n // `req.cookies`, etc. (Cf. NextRequestHint in next/src/server/web/adapter.ts.)\n const nextRequest = new NextRequest(createEdgeApiRequest(req, url));\n const response = await apiModule.default(nextRequest);\n if (!(response instanceof Response)) {\n throw new Error(\"Edge API route did not return a Response\");\n }\n\n res.statusCode = response.status;\n res.statusMessage = response.statusText;\n const setCookieHeaders = response.headers.getSetCookie();\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\") res.setHeader(name, value);\n });\n if (setCookieHeaders.length) {\n res.setHeader(\"set-cookie\", setCookieHeaders);\n }\n await writeEdgeApiResponseBody(res, response.body);\n return true;\n }\n\n const handler = apiModule.default;\n if (typeof handler !== \"function\") {\n console.error(`[vinext] API route ${route.filePath} does not export a default function`);\n res.statusCode = 500;\n res.end(\"API route does not export a default function\");\n return true;\n }\n\n // Parse query from URL + route params. Path params win over same-key search\n // params so a query string cannot change the dynamic route value.\n const query = mergeRouteParamsIntoQuery(parseQueryString(url), params);\n\n // Parse body\n const body = await parseBody(req);\n\n // Enhance req/res with Next.js helpers\n const { apiReq, apiRes } = enhanceApiObjects(req, res, query, body);\n\n // Call the handler\n await handler(apiReq, apiRes);\n return true;\n } catch (e) {\n if (e instanceof PagesBodyParseError) {\n res.statusCode = e.statusCode;\n res.statusMessage = e.message;\n res.end(e.message);\n return true;\n }\n\n // ssrFixStacktrace() is specific to ssrLoadModule and is not applicable\n // when using ModuleRunner — no stack trace fixup is needed here.\n console.error(e);\n void reportRequestError(\n e instanceof Error ? e : new Error(String(e)),\n {\n path: url,\n method: req.method ?? \"GET\",\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(\", \") : String(v ?? \"\"),\n ]),\n ),\n },\n { routerKind: \"Pages Router\", routePath: match.route.pattern, routeType: \"route\" },\n );\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n } else if (!res.writableEnded) {\n res.end();\n }\n return true;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-handler.js","names":["decodeQueryString"],"sources":["../../src/server/api-handler.ts"],"sourcesContent":["/**\n * API route handler for Pages Router (pages/api/*).\n *\n * Next.js API routes export a default handler function:\n * export default function handler(req, res) { ... }\n *\n * The req/res objects are Node.js IncomingMessage/ServerResponse with\n * Next.js extensions: req.query, req.body, res.json(), res.status(), etc.\n */\nimport \"./server-globals.js\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { decode as decodeQueryString } from \"node:querystring\";\nimport { Buffer } from \"node:buffer\";\nimport { type Route, matchRoute } from \"../routing/pages-router.js\";\nimport { reportRequestError, importModule, type ModuleImporter } from \"./instrumentation.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport { PagesBodyParseError, getMediaType, isJsonMediaType } from \"./pages-media-type.js\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\nimport {\n DEFAULT_PAGES_API_BODY_SIZE_LIMIT,\n resolveBodyParserConfig,\n} from \"./pages-body-parser-config.js\";\nimport { resolveRequestProtocol, resolveRequestHost } from \"./proxy-trust.js\";\nimport { NextRequest } from \"vinext/shims/server\";\n\n/**\n * Extend the Node.js request with Next.js-style helpers.\n */\ntype NextApiRequest = {\n query: Record<string, string | string[]>;\n body: unknown;\n cookies: Record<string, string>;\n} & IncomingMessage;\n\n/**\n * Extend the Node.js response with Next.js-style helpers.\n */\ntype NextApiResponse = {\n status(code: number): NextApiResponse;\n json(data: unknown): void;\n send(data: unknown): void;\n redirect(statusOrUrl: number | string, url?: string): void;\n} & ServerResponse;\n\ntype EdgeApiRouteModule = {\n /**\n * `export const config = { runtime: 'edge' }` — historical Pages Router form.\n */\n config?: {\n runtime?: string;\n };\n /**\n * `export const runtime = 'edge'` — bare export form. Next.js resolves the\n * effective runtime as `config.runtime ?? config.config?.runtime`, so a\n * top-level `runtime` export takes precedence over the nested config form.\n */\n runtime?: string;\n default: (request: Request) => Response | Promise<Response>;\n};\n\n/**\n * Default request body size (1 MB). Matches Next.js default bodyParser sizeLimit.\n * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config\n * Prevents denial-of-service via unbounded request body buffering.\n */\nconst MAX_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;\n\n/**\n * Parse the request body based on content-type.\n * Enforces a size limit to prevent memory exhaustion attacks.\n *\n * The `sizeLimit` argument honours `export const config = { api: { bodyParser:\n * { sizeLimit: '4mb' } } }` on the route module. To opt out of parsing\n * entirely (`bodyParser: false`), callers must skip this function so the\n * underlying readable stream stays intact on `req` (critical for webhook\n * HMAC signature verification).\n */\nasync function parseBody(\n req: IncomingMessage,\n sizeLimit: number = MAX_BODY_SIZE,\n): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let totalSize = 0;\n let settled = false;\n req.on(\"data\", (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > sizeLimit) {\n settled = true;\n req.destroy();\n reject(new PagesBodyParseError(\"Request body too large\", 413));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"error\", (err) => {\n if (!settled) {\n settled = true;\n reject(err);\n }\n });\n req.on(\"end\", () => {\n if (settled) return;\n settled = true;\n const raw = Buffer.concat(chunks).toString(\"utf-8\");\n const mediaType = getMediaType(req.headers[\"content-type\"]);\n if (!raw) {\n resolve(\n isJsonMediaType(mediaType)\n ? {}\n : mediaType === \"application/x-www-form-urlencoded\"\n ? decodeQueryString(raw)\n : undefined,\n );\n return;\n }\n if (isJsonMediaType(mediaType)) {\n try {\n resolve(JSON.parse(raw));\n } catch {\n reject(new PagesBodyParseError(\"Invalid JSON\", 400));\n }\n } else if (mediaType === \"application/x-www-form-urlencoded\") {\n resolve(decodeQueryString(raw));\n } else {\n resolve(raw);\n }\n });\n });\n}\n\n/**\n * Parse cookies from the Cookie header.\n */\nfunction parseCookies(req: IncomingMessage): Record<string, string> {\n const header = req.headers.cookie ?? \"\";\n const cookies: Record<string, string> = {};\n for (const part of header.split(\";\")) {\n const [key, ...rest] = part.split(\"=\");\n if (key) {\n cookies[key.trim()] = rest.join(\"=\").trim();\n }\n }\n return cookies;\n}\n\nfunction isEdgeApiRouteModule(module: Record<string, unknown>): module is EdgeApiRouteModule {\n if (typeof module.default !== \"function\") return false;\n // Bare `export const runtime = 'edge'` takes precedence over the nested config\n // form, matching Next.js (`config.runtime ?? config.config?.runtime` in\n // packages/next/src/build/analysis/get-page-static-info.ts).\n const bare = module.runtime;\n if (typeof bare === \"string\") return isEdgeApiRuntime(bare);\n const config = module.config;\n if (!config || typeof config !== \"object\") return false;\n const runtime = \"runtime\" in config ? (config as { runtime?: unknown }).runtime : undefined;\n return typeof runtime === \"string\" && isEdgeApiRuntime(runtime);\n}\n\nfunction readEdgeRequestBody(req: IncomingMessage): ReadableStream<Uint8Array> | undefined {\n if (req.method === \"GET\" || req.method === \"HEAD\") return undefined;\n return new ReadableStream<Uint8Array>({\n start(controller) {\n req.on(\"data\", (chunk: Buffer | string) => {\n controller.enqueue(typeof chunk === \"string\" ? Buffer.from(chunk) : new Uint8Array(chunk));\n });\n req.on(\"end\", () => controller.close());\n req.on(\"error\", (error) => controller.error(error));\n },\n });\n}\n\nfunction createEdgeApiRequest(req: IncomingMessage, url: string): Request {\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (Array.isArray(value)) {\n for (const item of value) headers.append(name, item);\n } else if (value !== undefined) {\n headers.set(name, value);\n }\n }\n\n // Honor `X-Forwarded-Proto` / `X-Forwarded-Host` only when running behind\n // a trusted proxy (gated on `VINEXT_TRUST_PROXY` / `VINEXT_TRUSTED_HOSTS`).\n // Without this gate a client could send `X-Forwarded-Proto: https` and\n // trick edge API handlers that check `request.url.startsWith(\"https\")`\n // (e.g. to gate Secure-cookie issuance) into believing the request was\n // TLS-terminated. See: Finding F-PROD-7 in SECURITY-AUDIT-2026-05.md.\n const proto = resolveRequestProtocol(req);\n const host = resolveRequestHost(req, \"localhost\");\n const requestUrl = new URL(url, `${proto}://${host}`);\n const body = readEdgeRequestBody(req);\n\n const init: RequestInit & { duplex?: \"half\" } = {\n headers,\n method: req.method,\n };\n\n if (body) {\n init.body = body;\n init.duplex = \"half\";\n }\n\n return new Request(requestUrl, init);\n}\n\nfunction waitForWritableDrain(res: ServerResponse): Promise<void> {\n return new Promise((resolve, reject) => {\n const cleanup = () => {\n res.off(\"drain\", onDrain);\n res.off(\"error\", onError);\n res.off(\"close\", onClose);\n };\n const onDrain = () => {\n cleanup();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const onClose = () => {\n cleanup();\n reject(new Error(\"Response closed before writable drain\"));\n };\n res.once(\"drain\", onDrain);\n res.once(\"error\", onError);\n res.once(\"close\", onClose);\n });\n}\n\nasync function writeEdgeApiResponseBody(\n res: ServerResponse,\n body: ReadableStream<Uint8Array> | null,\n): Promise<void> {\n if (!body) {\n res.end();\n return;\n }\n\n const reader = body.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n if (result.value.byteLength === 0) continue;\n if (!res.write(Buffer.from(result.value))) {\n await waitForWritableDrain(res);\n }\n }\n res.end();\n } catch (error) {\n res.destroy(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Enhance a Node.js req/res pair with Next.js API route helpers.\n */\nfunction enhanceApiObjects(\n req: IncomingMessage,\n res: ServerResponse,\n query: Record<string, string | string[]>,\n body: unknown,\n): { apiReq: NextApiRequest; apiRes: NextApiResponse } {\n const apiReq: NextApiRequest = Object.assign(req, {\n body,\n cookies: parseCookies(req),\n query,\n });\n\n const apiRes: NextApiResponse = Object.assign(res, {\n status(this: NextApiResponse, code: number) {\n this.statusCode = code;\n return this;\n },\n\n json(this: NextApiResponse, data: unknown) {\n this.setHeader(\"Content-Type\", \"application/json\");\n this.end(JSON.stringify(data));\n },\n\n send(this: NextApiResponse, data: unknown) {\n if (Buffer.isBuffer(data)) {\n if (!this.getHeader(\"Content-Type\")) {\n this.setHeader(\"Content-Type\", \"application/octet-stream\");\n }\n this.setHeader(\"Content-Length\", String(data.length));\n this.end(data);\n return;\n }\n\n if (typeof data === \"object\" && data !== null) {\n this.setHeader(\"Content-Type\", \"application/json\");\n this.end(JSON.stringify(data));\n } else {\n if (!this.getHeader(\"Content-Type\")) {\n this.setHeader(\"Content-Type\", \"text/plain\");\n }\n this.end(String(data));\n }\n },\n\n redirect(this: NextApiResponse, statusOrUrl: number | string, url?: string) {\n if (typeof statusOrUrl === \"string\") {\n this.writeHead(307, { Location: statusOrUrl });\n } else {\n this.writeHead(statusOrUrl, { Location: url ?? \"\" });\n }\n this.end();\n },\n });\n\n return { apiReq, apiRes };\n}\n\n/**\n * Handle an API route request.\n * Returns true if the request was handled, false if no API route matched.\n */\nexport async function handleApiRoute(\n runner: ModuleImporter,\n req: IncomingMessage,\n res: ServerResponse,\n url: string,\n apiRoutes: Route[],\n): Promise<boolean> {\n const match = matchRoute(url, apiRoutes);\n if (!match) return false;\n\n const { route, params } = match;\n\n try {\n // Load the API route module through the ModuleRunner\n const apiModule = await importModule(runner, route.filePath);\n if (isEdgeApiRouteModule(apiModule)) {\n // Next.js wraps the incoming Request in a NextRequest before invoking\n // edge API handlers, so handlers can use `req.nextUrl.searchParams`,\n // `req.cookies`, etc. (Cf. NextRequestHint in next/src/server/web/adapter.ts.)\n const nextRequest = new NextRequest(createEdgeApiRequest(req, url));\n const response = await apiModule.default(nextRequest);\n if (!(response instanceof Response)) {\n throw new Error(\"Edge API route did not return a Response\");\n }\n\n res.statusCode = response.status;\n res.statusMessage = response.statusText;\n const setCookieHeaders = response.headers.getSetCookie();\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\") res.setHeader(name, value);\n });\n if (setCookieHeaders.length) {\n res.setHeader(\"set-cookie\", setCookieHeaders);\n }\n await writeEdgeApiResponseBody(res, response.body);\n return true;\n }\n\n const handler = apiModule.default;\n if (typeof handler !== \"function\") {\n console.error(`[vinext] API route ${route.filePath} does not export a default function`);\n res.statusCode = 500;\n res.end(\"API route does not export a default function\");\n return true;\n }\n\n // Parse query from URL + route params. Path params win over same-key search\n // params so a query string cannot change the dynamic route value.\n const query = mergeRouteParamsIntoQuery(parseQueryString(url), params);\n\n // Honour `export const config = { api: { bodyParser: ... } }` on the\n // route module. When the handler opts out (`bodyParser: false`) we must\n // not consume the stream — leave `req` intact so user code (e.g. a\n // Stripe/GitHub webhook) can read the raw bytes for HMAC verification.\n const bodyParserConfig = resolveBodyParserConfig(\n (apiModule as { config?: { api?: { bodyParser?: unknown } } }).config as\n | { api?: { bodyParser?: boolean | { sizeLimit?: string | number } } }\n | undefined,\n );\n\n const body = bodyParserConfig.enabled\n ? await parseBody(req, bodyParserConfig.sizeLimit)\n : undefined;\n\n // Enhance req/res with Next.js helpers\n const { apiReq, apiRes } = enhanceApiObjects(req, res, query, body);\n\n // Call the handler\n await handler(apiReq, apiRes);\n return true;\n } catch (e) {\n if (e instanceof PagesBodyParseError) {\n res.statusCode = e.statusCode;\n res.statusMessage = e.message;\n res.end(e.message);\n return true;\n }\n\n // ssrFixStacktrace() is specific to ssrLoadModule and is not applicable\n // when using ModuleRunner — no stack trace fixup is needed here.\n console.error(e);\n void reportRequestError(\n e instanceof Error ? e : new Error(String(e)),\n {\n path: url,\n method: req.method ?? \"GET\",\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(\", \") : String(v ?? \"\"),\n ]),\n ),\n },\n { routerKind: \"Pages Router\", routePath: match.route.pattern, routeType: \"route\" },\n );\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n } else if (!res.writableEnded) {\n res.end();\n }\n return true;\n }\n}\n"],"mappings":"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"}
@@ -22,6 +22,21 @@ type ServerActionInitiationSnapshot<TRouterState> = {
22
22
  declare function isServerActionResult<TRoot>(value: unknown): value is AppBrowserServerActionResult<TRoot>;
23
23
  declare function shouldClearClientNavigationCachesForServerActionResult<TRoot>(result: AppBrowserServerActionResult<TRoot> | TRoot, revalidation?: ServerActionRevalidationKind): boolean;
24
24
  declare function parseServerActionRevalidationHeader(headers: Pick<Headers, "get">): ServerActionRevalidationKind;
25
+ type ServerActionRedirectLocation = {
26
+ href: string;
27
+ internal: boolean;
28
+ };
29
+ /**
30
+ * Resolve a server-action redirect target against the URL that initiated the
31
+ * action. Dot-relative redirects intentionally resolve as if the current route
32
+ * pathname were a directory, matching Next.js' `assignLocation()` behavior:
33
+ * `./subpage` from `/subdir` lands on `/subdir/subpage`, not `/subpage`.
34
+ */
35
+ declare function resolveServerActionRedirectLocation(options: {
36
+ currentHref: string;
37
+ location: string;
38
+ origin: string;
39
+ }): ServerActionRedirectLocation;
25
40
  declare function shouldScheduleRefreshForDiscardedServerAction(revalidation: ServerActionRevalidationKind): boolean;
26
41
  declare function createServerActionInitiationSnapshot<TRouterState>(options: {
27
42
  href: string;
@@ -40,5 +55,5 @@ type DiscardedServerActionRefreshSchedulerOptions = {
40
55
  };
41
56
  declare function createDiscardedServerActionRefreshScheduler(options: DiscardedServerActionRefreshSchedulerOptions): DiscardedServerActionRefreshScheduler;
42
57
  //#endregion
43
- export { AppBrowserServerActionResult, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
58
+ export { AppBrowserServerActionResult, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, resolveServerActionRedirectLocation, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
44
59
  //# sourceMappingURL=app-browser-action-result.d.ts.map
@@ -31,6 +31,20 @@ function parseServerActionRevalidationHeader(headers) {
31
31
  default: return "none";
32
32
  }
33
33
  }
34
+ /**
35
+ * Resolve a server-action redirect target against the URL that initiated the
36
+ * action. Dot-relative redirects intentionally resolve as if the current route
37
+ * pathname were a directory, matching Next.js' `assignLocation()` behavior:
38
+ * `./subpage` from `/subdir` lands on `/subdir/subpage`, not `/subpage`.
39
+ */
40
+ function resolveServerActionRedirectLocation(options) {
41
+ const currentUrl = new URL(options.currentHref, options.origin);
42
+ const redirectUrl = options.location.startsWith(".") ? new URL(options.location, `${currentUrl.origin}${currentUrl.pathname.endsWith("/") ? currentUrl.pathname : `${currentUrl.pathname}/`}`) : new URL(options.location, currentUrl.href);
43
+ return {
44
+ href: redirectUrl.href,
45
+ internal: redirectUrl.origin === currentUrl.origin
46
+ };
47
+ }
34
48
  function shouldScheduleRefreshForDiscardedServerAction(revalidation) {
35
49
  return revalidation !== "none";
36
50
  }
@@ -74,6 +88,6 @@ function createDiscardedServerActionRefreshScheduler(options) {
74
88
  };
75
89
  }
76
90
  //#endregion
77
- export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
91
+ export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, resolveServerActionRedirectLocation, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
78
92
 
79
93
  //# sourceMappingURL=app-browser-action-result.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-browser-action-result.js","names":[],"sources":["../../src/server/app-browser-action-result.ts"],"sourcesContent":["import { ACTION_REVALIDATED_HEADER } from \"./headers.js\";\n\nexport type AppBrowserServerActionResult<TRoot> = {\n root?: TRoot;\n returnValue?: {\n ok: boolean;\n data: unknown;\n };\n};\n\nexport type ServerActionRevalidationKind = \"dynamicOnly\" | \"none\" | \"staticAndDynamic\";\n\nconst ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;\nconst ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;\n\ntype ServerActionInitiationSnapshot<TRouterState> = {\n href: string;\n navigationId: number;\n path: string;\n routerState: TRouterState;\n};\n\n/**\n * Structural discriminator: matches on `\"returnValue\"` or `\"root\"` keys.\n * This is safe because {@link AppWireElements} keys are prefixed (`route:`,\n * `slot:`, `__route`, etc.) and will never collide with these property names.\n * If the wire format ever adds a `\"root\"` key, this guard must be updated.\n */\nexport function isServerActionResult<TRoot>(\n value: unknown,\n): value is AppBrowserServerActionResult<TRoot> {\n return !!value && typeof value === \"object\" && (\"returnValue\" in value || \"root\" in value);\n}\n\nexport function shouldClearClientNavigationCachesForServerActionResult<TRoot>(\n result: AppBrowserServerActionResult<TRoot> | TRoot,\n revalidation: ServerActionRevalidationKind = \"none\",\n): boolean {\n if (revalidation !== \"none\") {\n return true;\n }\n\n if (!isServerActionResult<TRoot>(result)) {\n return true;\n }\n\n return result.root !== undefined;\n}\n\nexport function parseServerActionRevalidationHeader(\n headers: Pick<Headers, \"get\">,\n): ServerActionRevalidationKind {\n const value = headers.get(ACTION_REVALIDATED_HEADER);\n if (!value) return \"none\";\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n return \"none\";\n }\n\n switch (parsed) {\n case ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC:\n return \"staticAndDynamic\";\n case ACTION_DID_REVALIDATE_DYNAMIC_ONLY:\n return \"dynamicOnly\";\n default:\n return \"none\";\n }\n}\n\nexport function shouldScheduleRefreshForDiscardedServerAction(\n revalidation: ServerActionRevalidationKind,\n): boolean {\n return revalidation !== \"none\";\n}\n\nexport function createServerActionInitiationSnapshot<TRouterState>(options: {\n href: string;\n navigationId: number;\n origin?: string;\n routerState: TRouterState;\n}): ServerActionInitiationSnapshot<TRouterState> {\n const url =\n options.origin === undefined ? new URL(options.href) : new URL(options.href, options.origin);\n return {\n href: url.href,\n navigationId: options.navigationId,\n path: url.pathname + url.search,\n routerState: options.routerState,\n };\n}\n\ntype DiscardedServerActionRefreshScheduler = {\n markNavigationSettled(): void;\n markNavigationStart(): void;\n schedule(): void;\n};\n\ntype DiscardedServerActionRefreshSchedulerOptions = {\n queueTask?: (callback: () => void) => void;\n runRefresh: () => void;\n};\n\nexport function createDiscardedServerActionRefreshScheduler(\n options: DiscardedServerActionRefreshSchedulerOptions,\n): DiscardedServerActionRefreshScheduler {\n const queueTask = options.queueTask ?? queueMicrotask;\n let activeNavigationCount = 0;\n let flushQueued = false;\n let refreshPending = false;\n\n function flush(): void {\n flushQueued = false;\n if (!refreshPending || activeNavigationCount > 0) return;\n\n refreshPending = false;\n options.runRefresh();\n }\n\n function queueFlush(): void {\n if (flushQueued) return;\n flushQueued = true;\n queueTask(flush);\n }\n\n return {\n markNavigationSettled() {\n if (activeNavigationCount > 0) {\n activeNavigationCount -= 1;\n }\n queueFlush();\n },\n markNavigationStart() {\n activeNavigationCount += 1;\n },\n schedule() {\n refreshPending = true;\n queueFlush();\n },\n };\n}\n"],"mappings":";;AAYA,MAAM,2CAA2C;AACjD,MAAM,qCAAqC;;;;;;;AAe3C,SAAgB,qBACd,OAC8C;CAC9C,OAAO,CAAC,CAAC,SAAS,OAAO,UAAU,aAAa,iBAAiB,SAAS,UAAU;;AAGtF,SAAgB,uDACd,QACA,eAA6C,QACpC;CACT,IAAI,iBAAiB,QACnB,OAAO;CAGT,IAAI,CAAC,qBAA4B,OAAO,EACtC,OAAO;CAGT,OAAO,OAAO,SAAS,KAAA;;AAGzB,SAAgB,oCACd,SAC8B;CAC9B,MAAM,QAAQ,QAAQ,IAAI,0BAA0B;CACpD,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,MAAM;SACpB;EACN,OAAO;;CAGT,QAAQ,QAAR;EACE,KAAK,0CACH,OAAO;EACT,KAAK,oCACH,OAAO;EACT,SACE,OAAO;;;AAIb,SAAgB,8CACd,cACS;CACT,OAAO,iBAAiB;;AAG1B,SAAgB,qCAAmD,SAKlB;CAC/C,MAAM,MACJ,QAAQ,WAAW,KAAA,IAAY,IAAI,IAAI,QAAQ,KAAK,GAAG,IAAI,IAAI,QAAQ,MAAM,QAAQ,OAAO;CAC9F,OAAO;EACL,MAAM,IAAI;EACV,cAAc,QAAQ;EACtB,MAAM,IAAI,WAAW,IAAI;EACzB,aAAa,QAAQ;EACtB;;AAcH,SAAgB,4CACd,SACuC;CACvC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI,wBAAwB;CAC5B,IAAI,cAAc;CAClB,IAAI,iBAAiB;CAErB,SAAS,QAAc;EACrB,cAAc;EACd,IAAI,CAAC,kBAAkB,wBAAwB,GAAG;EAElD,iBAAiB;EACjB,QAAQ,YAAY;;CAGtB,SAAS,aAAmB;EAC1B,IAAI,aAAa;EACjB,cAAc;EACd,UAAU,MAAM;;CAGlB,OAAO;EACL,wBAAwB;GACtB,IAAI,wBAAwB,GAC1B,yBAAyB;GAE3B,YAAY;;EAEd,sBAAsB;GACpB,yBAAyB;;EAE3B,WAAW;GACT,iBAAiB;GACjB,YAAY;;EAEf"}
1
+ {"version":3,"file":"app-browser-action-result.js","names":[],"sources":["../../src/server/app-browser-action-result.ts"],"sourcesContent":["import { ACTION_REVALIDATED_HEADER } from \"./headers.js\";\n\nexport type AppBrowserServerActionResult<TRoot> = {\n root?: TRoot;\n returnValue?: {\n ok: boolean;\n data: unknown;\n };\n};\n\nexport type ServerActionRevalidationKind = \"dynamicOnly\" | \"none\" | \"staticAndDynamic\";\n\nconst ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;\nconst ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;\n\ntype ServerActionInitiationSnapshot<TRouterState> = {\n href: string;\n navigationId: number;\n path: string;\n routerState: TRouterState;\n};\n\n/**\n * Structural discriminator: matches on `\"returnValue\"` or `\"root\"` keys.\n * This is safe because {@link AppWireElements} keys are prefixed (`route:`,\n * `slot:`, `__route`, etc.) and will never collide with these property names.\n * If the wire format ever adds a `\"root\"` key, this guard must be updated.\n */\nexport function isServerActionResult<TRoot>(\n value: unknown,\n): value is AppBrowserServerActionResult<TRoot> {\n return !!value && typeof value === \"object\" && (\"returnValue\" in value || \"root\" in value);\n}\n\nexport function shouldClearClientNavigationCachesForServerActionResult<TRoot>(\n result: AppBrowserServerActionResult<TRoot> | TRoot,\n revalidation: ServerActionRevalidationKind = \"none\",\n): boolean {\n if (revalidation !== \"none\") {\n return true;\n }\n\n if (!isServerActionResult<TRoot>(result)) {\n return true;\n }\n\n return result.root !== undefined;\n}\n\nexport function parseServerActionRevalidationHeader(\n headers: Pick<Headers, \"get\">,\n): ServerActionRevalidationKind {\n const value = headers.get(ACTION_REVALIDATED_HEADER);\n if (!value) return \"none\";\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n return \"none\";\n }\n\n switch (parsed) {\n case ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC:\n return \"staticAndDynamic\";\n case ACTION_DID_REVALIDATE_DYNAMIC_ONLY:\n return \"dynamicOnly\";\n default:\n return \"none\";\n }\n}\n\ntype ServerActionRedirectLocation = {\n href: string;\n internal: boolean;\n};\n\n/**\n * Resolve a server-action redirect target against the URL that initiated the\n * action. Dot-relative redirects intentionally resolve as if the current route\n * pathname were a directory, matching Next.js' `assignLocation()` behavior:\n * `./subpage` from `/subdir` lands on `/subdir/subpage`, not `/subpage`.\n */\nexport function resolveServerActionRedirectLocation(options: {\n currentHref: string;\n location: string;\n origin: string;\n}): ServerActionRedirectLocation {\n const currentUrl = new URL(options.currentHref, options.origin);\n const redirectUrl = options.location.startsWith(\".\")\n ? new URL(\n options.location,\n `${currentUrl.origin}${currentUrl.pathname.endsWith(\"/\") ? currentUrl.pathname : `${currentUrl.pathname}/`}`,\n )\n : new URL(options.location, currentUrl.href);\n\n return {\n href: redirectUrl.href,\n internal: redirectUrl.origin === currentUrl.origin,\n };\n}\n\nexport function shouldScheduleRefreshForDiscardedServerAction(\n revalidation: ServerActionRevalidationKind,\n): boolean {\n return revalidation !== \"none\";\n}\n\nexport function createServerActionInitiationSnapshot<TRouterState>(options: {\n href: string;\n navigationId: number;\n origin?: string;\n routerState: TRouterState;\n}): ServerActionInitiationSnapshot<TRouterState> {\n const url =\n options.origin === undefined ? new URL(options.href) : new URL(options.href, options.origin);\n return {\n href: url.href,\n navigationId: options.navigationId,\n path: url.pathname + url.search,\n routerState: options.routerState,\n };\n}\n\ntype DiscardedServerActionRefreshScheduler = {\n markNavigationSettled(): void;\n markNavigationStart(): void;\n schedule(): void;\n};\n\ntype DiscardedServerActionRefreshSchedulerOptions = {\n queueTask?: (callback: () => void) => void;\n runRefresh: () => void;\n};\n\nexport function createDiscardedServerActionRefreshScheduler(\n options: DiscardedServerActionRefreshSchedulerOptions,\n): DiscardedServerActionRefreshScheduler {\n const queueTask = options.queueTask ?? queueMicrotask;\n let activeNavigationCount = 0;\n let flushQueued = false;\n let refreshPending = false;\n\n function flush(): void {\n flushQueued = false;\n if (!refreshPending || activeNavigationCount > 0) return;\n\n refreshPending = false;\n options.runRefresh();\n }\n\n function queueFlush(): void {\n if (flushQueued) return;\n flushQueued = true;\n queueTask(flush);\n }\n\n return {\n markNavigationSettled() {\n if (activeNavigationCount > 0) {\n activeNavigationCount -= 1;\n }\n queueFlush();\n },\n markNavigationStart() {\n activeNavigationCount += 1;\n },\n schedule() {\n refreshPending = true;\n queueFlush();\n },\n };\n}\n"],"mappings":";;AAYA,MAAM,2CAA2C;AACjD,MAAM,qCAAqC;;;;;;;AAe3C,SAAgB,qBACd,OAC8C;CAC9C,OAAO,CAAC,CAAC,SAAS,OAAO,UAAU,aAAa,iBAAiB,SAAS,UAAU;;AAGtF,SAAgB,uDACd,QACA,eAA6C,QACpC;CACT,IAAI,iBAAiB,QACnB,OAAO;CAGT,IAAI,CAAC,qBAA4B,OAAO,EACtC,OAAO;CAGT,OAAO,OAAO,SAAS,KAAA;;AAGzB,SAAgB,oCACd,SAC8B;CAC9B,MAAM,QAAQ,QAAQ,IAAI,0BAA0B;CACpD,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,MAAM;SACpB;EACN,OAAO;;CAGT,QAAQ,QAAR;EACE,KAAK,0CACH,OAAO;EACT,KAAK,oCACH,OAAO;EACT,SACE,OAAO;;;;;;;;;AAeb,SAAgB,oCAAoC,SAInB;CAC/B,MAAM,aAAa,IAAI,IAAI,QAAQ,aAAa,QAAQ,OAAO;CAC/D,MAAM,cAAc,QAAQ,SAAS,WAAW,IAAI,GAChD,IAAI,IACF,QAAQ,UACR,GAAG,WAAW,SAAS,WAAW,SAAS,SAAS,IAAI,GAAG,WAAW,WAAW,GAAG,WAAW,SAAS,KACzG,GACD,IAAI,IAAI,QAAQ,UAAU,WAAW,KAAK;CAE9C,OAAO;EACL,MAAM,YAAY;EAClB,UAAU,YAAY,WAAW,WAAW;EAC7C;;AAGH,SAAgB,8CACd,cACS;CACT,OAAO,iBAAiB;;AAG1B,SAAgB,qCAAmD,SAKlB;CAC/C,MAAM,MACJ,QAAQ,WAAW,KAAA,IAAY,IAAI,IAAI,QAAQ,KAAK,GAAG,IAAI,IAAI,QAAQ,MAAM,QAAQ,OAAO;CAC9F,OAAO;EACL,MAAM,IAAI;EACV,cAAc,QAAQ;EACtB,MAAM,IAAI,WAAW,IAAI;EACzB,aAAa,QAAQ;EACtB;;AAcH,SAAgB,4CACd,SACuC;CACvC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI,wBAAwB;CAC5B,IAAI,cAAc;CAClB,IAAI,iBAAiB;CAErB,SAAS,QAAc;EACrB,cAAc;EACd,IAAI,CAAC,kBAAkB,wBAAwB,GAAG;EAElD,iBAAiB;EACjB,QAAQ,YAAY;;CAGtB,SAAS,aAAmB;EAC1B,IAAI,aAAa;EACjB,cAAc;EACd,UAAU,MAAM;;CAGlB,OAAO;EACL,wBAAwB;GACtB,IAAI,wBAAwB,GAC1B,yBAAyB;GAE3B,YAAY;;EAEd,sBAAsB;GACpB,yBAAyB;;EAE3B,WAAW;GACT,iBAAiB;GACjB,YAAY;;EAEf"}
@@ -1,22 +1,24 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { ACTION_REDIRECT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RSC_REDIRECT_HEADER } from "./headers.js";
3
3
  import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
4
+ import { AppElementsWire } from "./app-elements-wire.js";
4
5
  import { APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI } from "./app-rsc-render-mode.js";
6
+ import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
5
7
  import { installWindowNext } from "../client/window-next.js";
6
8
  import { scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
7
9
  import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
8
10
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
9
- import { AppElementsWire } from "./app-elements-wire.js";
10
- import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
11
11
  import { resolveManifestNavigationInterceptionContext } from "./app-browser-interception-context.js";
12
12
  import { createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
13
13
  import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId, resolveHardNavigationTargetFromRscResponse, resolveRscCompatibilityNavigationDecision } from "./app-rsc-cache-busting.js";
14
14
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
15
- import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, getClientNavigationRenderContext, getPrefetchCache, invalidatePrefetchCache, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, restoreRscResponse, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname } from "../shims/navigation.js";
15
+ import { consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
16
+ import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, getClientNavigationRenderContext, getPrefetchCache, invalidatePrefetchCache, navigateClientSide, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, restoreRscResponse, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname } from "../shims/navigation.js";
16
17
  import { DevRecoveryBoundary, RedirectBoundary } from "../shims/error-boundary.js";
18
+ import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
17
19
  import { ElementsContext, Slot } from "../shims/slot.js";
18
20
  import "../client/instrumentation-client.js";
19
- import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
21
+ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, parseServerActionRevalidationHeader, resolveServerActionRedirectLocation, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
20
22
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
21
23
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
22
24
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController } from "./app-browser-navigation-controller.js";
@@ -28,6 +30,7 @@ import { devOnCaughtError, devOnUncaughtError, installDevErrorOverlay } from "./
28
30
  import { throwOnServerActionNotFound } from "./server-action-not-found.js";
29
31
  import { resolveRscRedirectLifecycleHop } from "./app-browser-rsc-redirect.js";
30
32
  import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
33
+ import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
31
34
  import { createElement, startTransition, use, useLayoutEffect, useRef, useState } from "react";
32
35
  import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
33
36
  import { hydrateRoot } from "react-dom/client";
@@ -267,7 +270,7 @@ function createNavigationCommitEffect(options) {
267
270
  commitClientNavigationState(navId);
268
271
  };
269
272
  }
270
- async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, payloadOrigin, actionType = "navigate", operationLane = "navigation", traversalIntent = null) {
273
+ async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, payloadOrigin, actionType = "navigate", operationLane = "navigation", traversalIntent = null, scrollIntent = null) {
271
274
  try {
272
275
  return await browserNavigationController.renderNavigationPayload({
273
276
  actionType,
@@ -283,6 +286,7 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
283
286
  params,
284
287
  pendingRouterState,
285
288
  previousNextUrl,
289
+ scrollIntent,
286
290
  targetHistoryIndex: traversalIntent === null ? void 0 : traversalIntent.targetHistoryIndex,
287
291
  targetHref,
288
292
  navId
@@ -434,6 +438,7 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
434
438
  }, [setTreeStateValue]);
435
439
  useLayoutEffect(() => {
436
440
  setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
441
+ removeStylesheetLinksCoveredByInlineCss();
437
442
  getNavigationRuntime()?.functions.pingVisibleLinks?.();
438
443
  }, [treeState.elements]);
439
444
  useLayoutEffect(() => {
@@ -449,9 +454,10 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
449
454
  resetKey: treeState.renderId,
450
455
  onCatch: handleDevRecoveryBoundaryCatch
451
456
  }, innerTree) : innerTree;
457
+ const scrollScopedTree = createElement(AppRouterScrollCommitProvider, { commitId: treeState.renderId }, committedTree);
452
458
  const ClientNavigationRenderContext = getClientNavigationRenderContext();
453
- if (!ClientNavigationRenderContext) return committedTree;
454
- return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, committedTree);
459
+ if (!ClientNavigationRenderContext) return scrollScopedTree;
460
+ return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, scrollScopedTree);
455
461
  }
456
462
  function restoreHydrationNavigationContext(pathname, searchParams, params) {
457
463
  setNavigationContext({
@@ -582,15 +588,24 @@ function registerServerActionCallback() {
582
588
  console.error(DANGEROUS_URL_BLOCK_MESSAGE);
583
589
  return;
584
590
  }
591
+ const historyUpdateMode = (fetchResponse.headers.get("x-action-redirect-type") ?? "push") === "push" ? "push" : "replace";
592
+ const hardNavigationMode = historyUpdateMode === "push" ? "assign" : "replace";
593
+ let redirectLocation;
585
594
  try {
586
- if (new URL(actionRedirect, window.location.origin).origin !== window.location.origin) {
587
- browserNavigationController.performHardNavigation(actionRedirect);
588
- return;
589
- }
590
- } catch {}
595
+ redirectLocation = resolveServerActionRedirectLocation({
596
+ currentHref: actionInitiation.href,
597
+ location: actionRedirect,
598
+ origin: window.location.origin
599
+ });
600
+ } catch {
601
+ clearClientNavigationCaches();
602
+ browserNavigationController.performHardNavigation(actionRedirect, hardNavigationMode);
603
+ return;
604
+ }
591
605
  clearClientNavigationCaches();
592
- if ((fetchResponse.headers.get("x-action-redirect-type") ?? "replace") === "push") browserNavigationController.performHardNavigation(actionRedirect, "assign");
593
- else browserNavigationController.performHardNavigation(actionRedirect, "replace");
606
+ startTransition(() => {
607
+ navigateClientSide(redirectLocation.href, historyUpdateMode, true, true);
608
+ });
594
609
  return;
595
610
  }
596
611
  if (resolveRscCompatibilityNavigationDecision({
@@ -654,7 +669,7 @@ function bootstrapHydration(rscStream) {
654
669
  registerNavigationRuntimeFunctions({
655
670
  clearNavigationCaches: clearClientNavigationCaches,
656
671
  commitHashNavigation: commitHashOnlyNavigation,
657
- navigate: async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false, traversalIntent) {
672
+ navigate: async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false, traversalIntent, scrollIntent) {
658
673
  let pendingRouterState = null;
659
674
  const navId = browserNavigationController.beginNavigation();
660
675
  discardedServerActionRefreshScheduler.markNavigationStart();
@@ -667,6 +682,10 @@ function bootstrapHydration(rscStream) {
667
682
  currentHistoryIndex: currentHistoryTraversalIndex,
668
683
  historyState: window.history.state
669
684
  }) : null;
685
+ const performHardNavigationForScrollIntent = (targetHref) => {
686
+ consumeAppRouterScrollIntent(scrollIntent ?? null);
687
+ return browserNavigationController.performHardNavigation(targetHref);
688
+ };
670
689
  try {
671
690
  const shouldUsePendingRouterState = programmaticTransition;
672
691
  if (shouldUsePendingRouterState && hasBrowserRouterState()) pendingRouterState = beginPendingBrowserRouterState();
@@ -700,7 +719,7 @@ function bootstrapHydration(rscStream) {
700
719
  responseUrl: cachedRoute.response.url
701
720
  });
702
721
  if (compatibilityDecision.kind === "hard-navigate") {
703
- browserNavigationController.performHardNavigation(compatibilityDecision.hardNavigationTarget);
722
+ performHardNavigationForScrollIntent(compatibilityDecision.hardNavigationTarget);
704
723
  return;
705
724
  }
706
725
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
@@ -708,7 +727,7 @@ function bootstrapHydration(rscStream) {
708
727
  const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, cachedParams);
709
728
  const cachedPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
710
729
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
711
- await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent);
730
+ await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent);
712
731
  return;
713
732
  }
714
733
  let navResponse;
@@ -740,7 +759,7 @@ function bootstrapHydration(rscStream) {
740
759
  if (optimisticPayload !== null) {
741
760
  detachedNavigationCommits = true;
742
761
  const optimisticNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, optimisticPayload.params);
743
- renderNavigationPayload(Promise.resolve(optimisticPayload.elements), optimisticNavigationSnapshot, currentHref, navId, currentHistoryMode, optimisticPayload.params, requestPreviousNextUrl, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent).catch((error) => {
762
+ renderNavigationPayload(Promise.resolve(optimisticPayload.elements), optimisticNavigationSnapshot, currentHref, navId, currentHistoryMode, optimisticPayload.params, requestPreviousNextUrl, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent).catch((error) => {
744
763
  if (browserNavigationController.isCurrentNavigation(navId)) console.error("[vinext] Optimistic RSC navigation error:", error);
745
764
  });
746
765
  }
@@ -753,8 +772,7 @@ function bootstrapHydration(rscStream) {
753
772
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
754
773
  const isRscResponse = (navResponse.headers.get("content-type") ?? "").startsWith("text/x-component");
755
774
  if (!navResponse.ok || !isRscResponse || !navResponse.body) {
756
- const responseUrl = navResponseUrl ?? navResponse.url;
757
- browserNavigationController.performHardNavigation(resolveHardNavigationTargetFromRscResponse(responseUrl, currentHref, window.location.origin));
775
+ performHardNavigationForScrollIntent(resolveHardNavigationTargetFromRscResponse(navResponseUrl ?? navResponse.url, currentHref, window.location.origin));
758
776
  return;
759
777
  }
760
778
  const compatibilityDecision = resolveRscCompatibilityNavigationDecision({
@@ -765,7 +783,7 @@ function bootstrapHydration(rscStream) {
765
783
  responseUrl: navResponseUrl ?? navResponse.url
766
784
  });
767
785
  if (compatibilityDecision.kind === "hard-navigate") {
768
- browserNavigationController.performHardNavigation(compatibilityDecision.hardNavigationTarget);
786
+ performHardNavigationForScrollIntent(compatibilityDecision.hardNavigationTarget);
769
787
  return;
770
788
  }
771
789
  const redirectDecision = resolveRscRedirectLifecycleHop({
@@ -778,7 +796,7 @@ function bootstrapHydration(rscStream) {
778
796
  });
779
797
  if (redirectDecision.kind === "terminal-hard-navigation") {
780
798
  if (redirectDecision.reason === "maxRedirectsExceeded") console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
781
- browserNavigationController.performHardNavigation(redirectDecision.href);
799
+ performHardNavigationForScrollIntent(redirectDecision.href);
782
800
  return;
783
801
  }
784
802
  if (redirectDecision.kind === "follow") {
@@ -793,12 +811,12 @@ function bootstrapHydration(rscStream) {
793
811
  navResponse.body?.cancel().catch(() => {});
794
812
  const resolvedTarget = new URL(flightRedirectTarget, window.location.origin);
795
813
  if (resolvedTarget.origin !== window.location.origin) {
796
- browserNavigationController.performHardNavigation(resolvedTarget.href);
814
+ performHardNavigationForScrollIntent(resolvedTarget.href);
797
815
  return;
798
816
  }
799
817
  if (redirectCount >= 10) {
800
818
  console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
801
- browserNavigationController.performHardNavigation(resolvedTarget.href);
819
+ performHardNavigationForScrollIntent(resolvedTarget.href);
802
820
  return;
803
821
  }
804
822
  currentHref = `${resolvedTarget.pathname}${resolvedTarget.search}${resolvedTarget.hash}`;
@@ -818,7 +836,7 @@ function bootstrapHydration(rscStream) {
818
836
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
819
837
  const rscPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(reactResponse)));
820
838
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
821
- if (await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent) !== "committed") return;
839
+ if (await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent) !== "committed") return;
822
840
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
823
841
  const resolvedElements = await rscPayload;
824
842
  const metadata = AppElementsWire.readMetadata(resolvedElements);
@@ -826,14 +844,15 @@ function bootstrapHydration(rscStream) {
826
844
  cacheBufferPromise.catch(() => {});
827
845
  return;
828
846
  }
829
- const cacheBuffer = await cacheBufferPromise;
830
- storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, metadata.interceptionContext), createCachedRscResponseSnapshot(navResponse, cacheBuffer, navResponseUrl), navParams);
847
+ cacheBufferPromise.then((cacheBuffer) => {
848
+ storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, metadata.interceptionContext), createCachedRscResponseSnapshot(navResponse, cacheBuffer, navResponseUrl), navParams);
849
+ }).catch(() => {});
831
850
  return;
832
851
  }
833
852
  } catch (error) {
834
853
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
835
854
  if (!isPageUnloading) console.error("[vinext] RSC navigation error:", error);
836
- browserNavigationController.performHardNavigation(currentHref);
855
+ performHardNavigationForScrollIntent(currentHref);
837
856
  } finally {
838
857
  browserNavigationController.finalizeNavigation(navId, pendingRouterState);
839
858
  discardedServerActionRefreshScheduler.markNavigationSettled();