vinext 0.0.51 → 0.0.53

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 (423) 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/precompress.d.ts +7 -7
  6. package/dist/build/precompress.js +18 -17
  7. package/dist/build/precompress.js.map +1 -1
  8. package/dist/build/prerender.d.ts +9 -16
  9. package/dist/build/prerender.js +88 -50
  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-args.d.ts +1 -0
  19. package/dist/cli-args.js +5 -0
  20. package/dist/cli-args.js.map +1 -1
  21. package/dist/cli.js +58 -4
  22. package/dist/cli.js.map +1 -1
  23. package/dist/client/instrumentation-client-inject.d.ts +34 -0
  24. package/dist/client/instrumentation-client-inject.js +57 -0
  25. package/dist/client/instrumentation-client-inject.js.map +1 -0
  26. package/dist/client/navigation-runtime.d.ts +60 -0
  27. package/dist/client/navigation-runtime.js +171 -0
  28. package/dist/client/navigation-runtime.js.map +1 -0
  29. package/dist/client/pages-router-link-navigation.d.ts +26 -0
  30. package/dist/client/pages-router-link-navigation.js +14 -0
  31. package/dist/client/pages-router-link-navigation.js.map +1 -0
  32. package/dist/client/vinext-next-data.d.ts +14 -3
  33. package/dist/client/vinext-next-data.js +50 -1
  34. package/dist/client/vinext-next-data.js.map +1 -0
  35. package/dist/client/window-next.d.ts +10 -2
  36. package/dist/client/window-next.js.map +1 -1
  37. package/dist/cloudflare/kv-cache-handler.js +2 -1
  38. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  39. package/dist/cloudflare/tpr.js +1 -1
  40. package/dist/cloudflare/tpr.js.map +1 -1
  41. package/dist/config/config-matchers.d.ts +63 -16
  42. package/dist/config/config-matchers.js +145 -9
  43. package/dist/config/config-matchers.js.map +1 -1
  44. package/dist/config/next-config.d.ts +32 -5
  45. package/dist/config/next-config.js +55 -15
  46. package/dist/config/next-config.js.map +1 -1
  47. package/dist/deploy.js +130 -46
  48. package/dist/deploy.js.map +1 -1
  49. package/dist/entries/app-browser-entry.js +9 -3
  50. package/dist/entries/app-browser-entry.js.map +1 -1
  51. package/dist/entries/app-rsc-entry.d.ts +4 -2
  52. package/dist/entries/app-rsc-entry.js +76 -16
  53. package/dist/entries/app-rsc-entry.js.map +1 -1
  54. package/dist/entries/app-rsc-manifest.d.ts +1 -0
  55. package/dist/entries/app-rsc-manifest.js +53 -6
  56. package/dist/entries/app-rsc-manifest.js.map +1 -1
  57. package/dist/entries/app-ssr-entry.d.ts +3 -3
  58. package/dist/entries/app-ssr-entry.js +4 -4
  59. package/dist/entries/app-ssr-entry.js.map +1 -1
  60. package/dist/entries/pages-client-entry.js +40 -3
  61. package/dist/entries/pages-client-entry.js.map +1 -1
  62. package/dist/entries/pages-server-entry.js +261 -31
  63. package/dist/entries/pages-server-entry.js.map +1 -1
  64. package/dist/entries/runtime-entry-module.d.ts +2 -1
  65. package/dist/entries/runtime-entry-module.js +9 -3
  66. package/dist/entries/runtime-entry-module.js.map +1 -1
  67. package/dist/index.js +161 -46
  68. package/dist/index.js.map +1 -1
  69. package/dist/plugins/css-data-url.d.ts +7 -0
  70. package/dist/plugins/css-data-url.js +81 -0
  71. package/dist/plugins/css-data-url.js.map +1 -0
  72. package/dist/plugins/fonts.js +30 -5
  73. package/dist/plugins/fonts.js.map +1 -1
  74. package/dist/plugins/middleware-server-only.d.ts +54 -0
  75. package/dist/plugins/middleware-server-only.js +91 -0
  76. package/dist/plugins/middleware-server-only.js.map +1 -0
  77. package/dist/plugins/optimize-imports.js +4 -4
  78. package/dist/plugins/optimize-imports.js.map +1 -1
  79. package/dist/plugins/strip-server-exports.js +5 -8
  80. package/dist/plugins/strip-server-exports.js.map +1 -1
  81. package/dist/routing/app-route-graph.d.ts +20 -1
  82. package/dist/routing/app-route-graph.js +58 -6
  83. package/dist/routing/app-route-graph.js.map +1 -1
  84. package/dist/routing/app-router.d.ts +2 -2
  85. package/dist/routing/app-router.js +2 -2
  86. package/dist/routing/app-router.js.map +1 -1
  87. package/dist/routing/route-trie.js +13 -18
  88. package/dist/routing/route-trie.js.map +1 -1
  89. package/dist/routing/utils.d.ts +12 -1
  90. package/dist/routing/utils.js +18 -1
  91. package/dist/routing/utils.js.map +1 -1
  92. package/dist/server/api-handler.js +153 -42
  93. package/dist/server/api-handler.js.map +1 -1
  94. package/dist/server/app-browser-action-result.d.ts +16 -1
  95. package/dist/server/app-browser-action-result.js +15 -1
  96. package/dist/server/app-browser-action-result.js.map +1 -1
  97. package/dist/server/app-browser-entry.js +309 -155
  98. package/dist/server/app-browser-entry.js.map +1 -1
  99. package/dist/server/app-browser-interception-context.d.ts +24 -0
  100. package/dist/server/app-browser-interception-context.js +32 -0
  101. package/dist/server/app-browser-interception-context.js.map +1 -0
  102. package/dist/server/app-browser-navigation-controller.d.ts +3 -1
  103. package/dist/server/app-browser-navigation-controller.js +5 -1
  104. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  105. package/dist/server/app-browser-rsc-redirect.d.ts +2 -1
  106. package/dist/server/app-browser-rsc-redirect.js +2 -2
  107. package/dist/server/app-browser-rsc-redirect.js.map +1 -1
  108. package/dist/server/app-browser-state.d.ts +18 -1
  109. package/dist/server/app-browser-state.js +19 -1
  110. package/dist/server/app-browser-state.js.map +1 -1
  111. package/dist/server/app-browser-stream.d.ts +5 -14
  112. package/dist/server/app-browser-stream.js +13 -7
  113. package/dist/server/app-browser-stream.js.map +1 -1
  114. package/dist/server/app-browser-visible-commit.d.ts +2 -1
  115. package/dist/server/app-browser-visible-commit.js +1 -0
  116. package/dist/server/app-browser-visible-commit.js.map +1 -1
  117. package/dist/server/app-elements-wire.d.ts +10 -5
  118. package/dist/server/app-elements-wire.js +84 -2
  119. package/dist/server/app-elements-wire.js.map +1 -1
  120. package/dist/server/app-elements.d.ts +3 -2
  121. package/dist/server/app-elements.js +3 -2
  122. package/dist/server/app-elements.js.map +1 -1
  123. package/dist/server/app-fallback-renderer.d.ts +12 -3
  124. package/dist/server/app-fallback-renderer.js +15 -8
  125. package/dist/server/app-fallback-renderer.js.map +1 -1
  126. package/dist/server/app-history-state.js +6 -2
  127. package/dist/server/app-history-state.js.map +1 -1
  128. package/dist/server/app-interception-context-header.d.ts +33 -0
  129. package/dist/server/app-interception-context-header.js +44 -0
  130. package/dist/server/app-interception-context-header.js.map +1 -0
  131. package/dist/server/app-middleware.d.ts +13 -0
  132. package/dist/server/app-middleware.js +3 -1
  133. package/dist/server/app-middleware.js.map +1 -1
  134. package/dist/server/app-mounted-slots-header.d.ts +19 -0
  135. package/dist/server/app-mounted-slots-header.js +40 -1
  136. package/dist/server/app-mounted-slots-header.js.map +1 -1
  137. package/dist/server/app-optimistic-routing.d.ts +54 -0
  138. package/dist/server/app-optimistic-routing.js +208 -0
  139. package/dist/server/app-optimistic-routing.js.map +1 -0
  140. package/dist/server/app-page-boundary-render.d.ts +1 -0
  141. package/dist/server/app-page-boundary-render.js +2 -0
  142. package/dist/server/app-page-boundary-render.js.map +1 -1
  143. package/dist/server/app-page-boundary.d.ts +1 -0
  144. package/dist/server/app-page-boundary.js +2 -0
  145. package/dist/server/app-page-boundary.js.map +1 -1
  146. package/dist/server/app-page-cache.d.ts +15 -1
  147. package/dist/server/app-page-cache.js +68 -7
  148. package/dist/server/app-page-cache.js.map +1 -1
  149. package/dist/server/app-page-dispatch.d.ts +5 -0
  150. package/dist/server/app-page-dispatch.js +39 -5
  151. package/dist/server/app-page-dispatch.js.map +1 -1
  152. package/dist/server/app-page-element-builder.d.ts +2 -1
  153. package/dist/server/app-page-element-builder.js +7 -3
  154. package/dist/server/app-page-element-builder.js.map +1 -1
  155. package/dist/server/app-page-execution.d.ts +29 -1
  156. package/dist/server/app-page-execution.js +91 -4
  157. package/dist/server/app-page-execution.js.map +1 -1
  158. package/dist/server/app-page-head.d.ts +1 -0
  159. package/dist/server/app-page-head.js +29 -2
  160. package/dist/server/app-page-head.js.map +1 -1
  161. package/dist/server/app-page-probe.js +1 -1
  162. package/dist/server/app-page-render-observation.js +1 -1
  163. package/dist/server/app-page-render.d.ts +3 -0
  164. package/dist/server/app-page-render.js +7 -3
  165. package/dist/server/app-page-render.js.map +1 -1
  166. package/dist/server/app-page-response.d.ts +11 -1
  167. package/dist/server/app-page-response.js +18 -5
  168. package/dist/server/app-page-response.js.map +1 -1
  169. package/dist/server/app-page-route-wiring.d.ts +1 -0
  170. package/dist/server/app-page-route-wiring.js +35 -15
  171. package/dist/server/app-page-route-wiring.js.map +1 -1
  172. package/dist/server/app-page-stream.d.ts +4 -0
  173. package/dist/server/app-page-stream.js +3 -0
  174. package/dist/server/app-page-stream.js.map +1 -1
  175. package/dist/server/app-prerender-static-params.d.ts +2 -1
  176. package/dist/server/app-prerender-static-params.js +44 -8
  177. package/dist/server/app-prerender-static-params.js.map +1 -1
  178. package/dist/server/app-route-handler-cache.d.ts +2 -2
  179. package/dist/server/app-route-handler-cache.js +3 -2
  180. package/dist/server/app-route-handler-cache.js.map +1 -1
  181. package/dist/server/app-route-handler-dispatch.d.ts +7 -1
  182. package/dist/server/app-route-handler-dispatch.js +4 -1
  183. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  184. package/dist/server/app-route-handler-execution.d.ts +18 -2
  185. package/dist/server/app-route-handler-execution.js +1 -0
  186. package/dist/server/app-route-handler-execution.js.map +1 -1
  187. package/dist/server/app-route-handler-response.js +6 -5
  188. package/dist/server/app-route-handler-response.js.map +1 -1
  189. package/dist/server/app-router-entry.js +6 -2
  190. package/dist/server/app-router-entry.js.map +1 -1
  191. package/dist/server/app-rsc-handler.d.ts +11 -1
  192. package/dist/server/app-rsc-handler.js +48 -21
  193. package/dist/server/app-rsc-handler.js.map +1 -1
  194. package/dist/server/app-rsc-render-mode.d.ts +4 -3
  195. package/dist/server/app-rsc-render-mode.js +7 -1
  196. package/dist/server/app-rsc-render-mode.js.map +1 -1
  197. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  198. package/dist/server/app-rsc-request-normalization.js +6 -2
  199. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  200. package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
  201. package/dist/server/app-rsc-response-finalizer.js +10 -3
  202. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  203. package/dist/server/app-rsc-route-matching.js +2 -2
  204. package/dist/server/app-rsc-route-matching.js.map +1 -1
  205. package/dist/server/app-segment-config.d.ts +4 -1
  206. package/dist/server/app-segment-config.js +6 -1
  207. package/dist/server/app-segment-config.js.map +1 -1
  208. package/dist/server/app-server-action-execution.d.ts +1 -0
  209. package/dist/server/app-server-action-execution.js +5 -1
  210. package/dist/server/app-server-action-execution.js.map +1 -1
  211. package/dist/server/app-ssr-entry.d.ts +2 -0
  212. package/dist/server/app-ssr-entry.js +92 -55
  213. package/dist/server/app-ssr-entry.js.map +1 -1
  214. package/dist/server/app-ssr-stream.d.ts +30 -2
  215. package/dist/server/app-ssr-stream.js +95 -8
  216. package/dist/server/app-ssr-stream.js.map +1 -1
  217. package/dist/server/app-static-generation.d.ts +1 -0
  218. package/dist/server/app-static-generation.js +2 -1
  219. package/dist/server/app-static-generation.js.map +1 -1
  220. package/dist/server/artifact-compatibility.d.ts +1 -1
  221. package/dist/server/artifact-compatibility.js.map +1 -1
  222. package/dist/server/cache-headers.d.ts +7 -0
  223. package/dist/server/cache-headers.js +19 -0
  224. package/dist/server/cache-headers.js.map +1 -0
  225. package/dist/server/cache-proof.d.ts +49 -3
  226. package/dist/server/cache-proof.js +78 -22
  227. package/dist/server/cache-proof.js.map +1 -1
  228. package/dist/server/client-reuse-manifest.d.ts +99 -0
  229. package/dist/server/client-reuse-manifest.js +212 -0
  230. package/dist/server/client-reuse-manifest.js.map +1 -0
  231. package/dist/server/default-global-error-module.d.ts +20 -0
  232. package/dist/server/default-global-error-module.js +20 -0
  233. package/dist/server/default-global-error-module.js.map +1 -0
  234. package/dist/server/default-not-found-module.d.ts +20 -0
  235. package/dist/server/default-not-found-module.js +20 -0
  236. package/dist/server/default-not-found-module.js.map +1 -0
  237. package/dist/server/dev-server.d.ts +10 -2
  238. package/dist/server/dev-server.js +99 -36
  239. package/dist/server/dev-server.js.map +1 -1
  240. package/dist/server/edge-api-runtime.d.ts +5 -0
  241. package/dist/server/edge-api-runtime.js +8 -0
  242. package/dist/server/edge-api-runtime.js.map +1 -0
  243. package/dist/server/headers.d.ts +22 -1
  244. package/dist/server/headers.js +22 -1
  245. package/dist/server/headers.js.map +1 -1
  246. package/dist/server/http-error-responses.d.ts +16 -1
  247. package/dist/server/http-error-responses.js +21 -1
  248. package/dist/server/http-error-responses.js.map +1 -1
  249. package/dist/server/image-optimization.d.ts +13 -4
  250. package/dist/server/image-optimization.js +15 -4
  251. package/dist/server/image-optimization.js.map +1 -1
  252. package/dist/server/isr-cache.d.ts +6 -2
  253. package/dist/server/isr-cache.js +20 -4
  254. package/dist/server/isr-cache.js.map +1 -1
  255. package/dist/server/middleware-runtime.d.ts +15 -0
  256. package/dist/server/middleware-runtime.js +59 -7
  257. package/dist/server/middleware-runtime.js.map +1 -1
  258. package/dist/server/middleware.d.ts +1 -1
  259. package/dist/server/middleware.js +5 -3
  260. package/dist/server/middleware.js.map +1 -1
  261. package/dist/server/navigation-planner.d.ts +9 -3
  262. package/dist/server/navigation-planner.js +98 -25
  263. package/dist/server/navigation-planner.js.map +1 -1
  264. package/dist/server/navigation-trace.d.ts +2 -1
  265. package/dist/server/navigation-trace.js +1 -0
  266. package/dist/server/navigation-trace.js.map +1 -1
  267. package/dist/server/pages-api-route.d.ts +45 -1
  268. package/dist/server/pages-api-route.js +27 -4
  269. package/dist/server/pages-api-route.js.map +1 -1
  270. package/dist/server/pages-body-parser-config.d.ts +60 -0
  271. package/dist/server/pages-body-parser-config.js +79 -0
  272. package/dist/server/pages-body-parser-config.js.map +1 -0
  273. package/dist/server/pages-data-route.d.ts +77 -0
  274. package/dist/server/pages-data-route.js +98 -0
  275. package/dist/server/pages-data-route.js.map +1 -0
  276. package/dist/server/pages-default-404.d.ts +31 -0
  277. package/dist/server/pages-default-404.js +40 -0
  278. package/dist/server/pages-default-404.js.map +1 -0
  279. package/dist/server/pages-i18n.d.ts +51 -1
  280. package/dist/server/pages-i18n.js +61 -1
  281. package/dist/server/pages-i18n.js.map +1 -1
  282. package/dist/server/pages-node-compat.d.ts +10 -0
  283. package/dist/server/pages-node-compat.js +12 -1
  284. package/dist/server/pages-node-compat.js.map +1 -1
  285. package/dist/server/pages-page-data.d.ts +69 -2
  286. package/dist/server/pages-page-data.js +47 -31
  287. package/dist/server/pages-page-data.js.map +1 -1
  288. package/dist/server/pages-page-response.d.ts +13 -1
  289. package/dist/server/pages-page-response.js +16 -11
  290. package/dist/server/pages-page-response.js.map +1 -1
  291. package/dist/server/prerender-route-params.d.ts +14 -0
  292. package/dist/server/prerender-route-params.js +94 -0
  293. package/dist/server/prerender-route-params.js.map +1 -0
  294. package/dist/server/prod-server.d.ts +15 -37
  295. package/dist/server/prod-server.js +143 -107
  296. package/dist/server/prod-server.js.map +1 -1
  297. package/dist/server/proxy-trust.d.ts +41 -0
  298. package/dist/server/proxy-trust.js +70 -0
  299. package/dist/server/proxy-trust.js.map +1 -0
  300. package/dist/server/request-pipeline.d.ts +13 -4
  301. package/dist/server/request-pipeline.js +32 -14
  302. package/dist/server/request-pipeline.js.map +1 -1
  303. package/dist/server/seed-cache.d.ts +12 -31
  304. package/dist/server/seed-cache.js +30 -37
  305. package/dist/server/seed-cache.js.map +1 -1
  306. package/dist/server/server-action-not-found.js +8 -3
  307. package/dist/server/server-action-not-found.js.map +1 -1
  308. package/dist/server/skip-cache-proof.d.ts +41 -0
  309. package/dist/server/skip-cache-proof.js +101 -0
  310. package/dist/server/skip-cache-proof.js.map +1 -0
  311. package/dist/server/static-file-cache.d.ts +1 -1
  312. package/dist/server/static-file-cache.js +8 -7
  313. package/dist/server/static-file-cache.js.map +1 -1
  314. package/dist/server/streaming-metadata.d.ts +5 -0
  315. package/dist/server/streaming-metadata.js +10 -0
  316. package/dist/server/streaming-metadata.js.map +1 -0
  317. package/dist/shims/app-router-scroll-state.d.ts +12 -0
  318. package/dist/shims/app-router-scroll-state.js +38 -0
  319. package/dist/shims/app-router-scroll-state.js.map +1 -0
  320. package/dist/shims/app-router-scroll.d.ts +14 -0
  321. package/dist/shims/app-router-scroll.js +100 -0
  322. package/dist/shims/app-router-scroll.js.map +1 -0
  323. package/dist/shims/before-interactive-context.d.ts +30 -0
  324. package/dist/shims/before-interactive-context.js +10 -0
  325. package/dist/shims/before-interactive-context.js.map +1 -0
  326. package/dist/shims/cache-runtime.d.ts +1 -1
  327. package/dist/shims/cache-runtime.js +14 -1
  328. package/dist/shims/cache-runtime.js.map +1 -1
  329. package/dist/shims/client-locale.d.ts +15 -0
  330. package/dist/shims/client-locale.js +13 -0
  331. package/dist/shims/client-locale.js.map +1 -0
  332. package/dist/shims/default-global-error.d.ts +32 -0
  333. package/dist/shims/default-global-error.js +181 -0
  334. package/dist/shims/default-global-error.js.map +1 -0
  335. package/dist/shims/default-not-found.d.ts +12 -0
  336. package/dist/shims/default-not-found.js +61 -0
  337. package/dist/shims/default-not-found.js.map +1 -0
  338. package/dist/shims/document.d.ts +59 -3
  339. package/dist/shims/document.js +36 -5
  340. package/dist/shims/document.js.map +1 -1
  341. package/dist/shims/error-boundary.d.ts +2 -2
  342. package/dist/shims/font-local.d.ts +5 -0
  343. package/dist/shims/font-local.js +6 -2
  344. package/dist/shims/font-local.js.map +1 -1
  345. package/dist/shims/form.js +13 -6
  346. package/dist/shims/form.js.map +1 -1
  347. package/dist/shims/head.js +4 -4
  348. package/dist/shims/head.js.map +1 -1
  349. package/dist/shims/headers.d.ts +6 -2
  350. package/dist/shims/headers.js +64 -21
  351. package/dist/shims/headers.js.map +1 -1
  352. package/dist/shims/image.d.ts +1 -1
  353. package/dist/shims/image.js +4 -4
  354. package/dist/shims/image.js.map +1 -1
  355. package/dist/shims/internal/pages-data-target.d.ts +58 -0
  356. package/dist/shims/internal/pages-data-target.js +91 -0
  357. package/dist/shims/internal/pages-data-target.js.map +1 -0
  358. package/dist/shims/internal/pages-data-url.d.ts +42 -0
  359. package/dist/shims/internal/pages-data-url.js +73 -0
  360. package/dist/shims/internal/pages-data-url.js.map +1 -0
  361. package/dist/shims/link.d.ts +21 -3
  362. package/dist/shims/link.js +189 -30
  363. package/dist/shims/link.js.map +1 -1
  364. package/dist/shims/metadata.d.ts +2 -1
  365. package/dist/shims/metadata.js +65 -6
  366. package/dist/shims/metadata.js.map +1 -1
  367. package/dist/shims/navigation.d.ts +8 -2
  368. package/dist/shims/navigation.js +67 -23
  369. package/dist/shims/navigation.js.map +1 -1
  370. package/dist/shims/og.d.ts +18 -2
  371. package/dist/shims/og.js +49 -1
  372. package/dist/shims/og.js.map +1 -0
  373. package/dist/shims/request-state-types.d.ts +1 -1
  374. package/dist/shims/root-params.d.ts +3 -1
  375. package/dist/shims/root-params.js +11 -3
  376. package/dist/shims/root-params.js.map +1 -1
  377. package/dist/shims/router-state.d.ts +1 -0
  378. package/dist/shims/router-state.js.map +1 -1
  379. package/dist/shims/router.d.ts +12 -5
  380. package/dist/shims/router.js +535 -86
  381. package/dist/shims/router.js.map +1 -1
  382. package/dist/shims/script.js +86 -12
  383. package/dist/shims/script.js.map +1 -1
  384. package/dist/shims/server.d.ts +21 -4
  385. package/dist/shims/server.js +30 -9
  386. package/dist/shims/server.js.map +1 -1
  387. package/dist/shims/slot.js +5 -1
  388. package/dist/shims/slot.js.map +1 -1
  389. package/dist/shims/unified-request-context.d.ts +1 -1
  390. package/dist/shims/url-safety.d.ts +23 -1
  391. package/dist/shims/url-safety.js +29 -2
  392. package/dist/shims/url-safety.js.map +1 -1
  393. package/dist/shims/url-utils.d.ts +2 -1
  394. package/dist/shims/url-utils.js +15 -4
  395. package/dist/shims/url-utils.js.map +1 -1
  396. package/dist/typegen.d.ts +10 -0
  397. package/dist/typegen.js +242 -0
  398. package/dist/typegen.js.map +1 -0
  399. package/dist/utils/asset-prefix.d.ts +33 -5
  400. package/dist/utils/asset-prefix.js +39 -6
  401. package/dist/utils/asset-prefix.js.map +1 -1
  402. package/dist/utils/cache-control-metadata.d.ts +2 -1
  403. package/dist/utils/cache-control-metadata.js +1 -3
  404. package/dist/utils/cache-control-metadata.js.map +1 -1
  405. package/dist/utils/domain-locale.d.ts +2 -1
  406. package/dist/utils/domain-locale.js +9 -1
  407. package/dist/utils/domain-locale.js.map +1 -1
  408. package/dist/utils/html-limited-bots.d.ts +5 -0
  409. package/dist/utils/html-limited-bots.js +15 -0
  410. package/dist/utils/html-limited-bots.js.map +1 -0
  411. package/dist/utils/lazy-chunks.d.ts +1 -1
  412. package/dist/utils/lazy-chunks.js +1 -1
  413. package/dist/utils/lazy-chunks.js.map +1 -1
  414. package/dist/utils/prerender-output-paths.d.ts +15 -0
  415. package/dist/utils/prerender-output-paths.js +24 -0
  416. package/dist/utils/prerender-output-paths.js.map +1 -0
  417. package/dist/utils/query.d.ts +23 -1
  418. package/dist/utils/query.js +46 -2
  419. package/dist/utils/query.js.map +1 -1
  420. package/dist/utils/record.d.ts +5 -0
  421. package/dist/utils/record.js +8 -0
  422. package/dist/utils/record.js.map +1 -0
  423. package/package.json +11 -3
@@ -25,6 +25,40 @@ type PagesI18nRequestInfo = {
25
25
  domainLocale?: DomainLocale;
26
26
  redirectUrl?: string;
27
27
  };
28
+ /**
29
+ * Prepend the default locale prefix to a pathname when i18n is configured and
30
+ * the path does not already carry a locale prefix. Mirrors Next.js's
31
+ * server-side path normalisation in `resolve-routes.ts` (lines ~250-263):
32
+ *
33
+ * if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {
34
+ * parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`
35
+ * }
36
+ *
37
+ * Run this **before** matching against `next.config.js` redirects/rewrites
38
+ * (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so
39
+ * that requests arriving without a locale prefix still match those rules.
40
+ *
41
+ * Skips internal paths that Next.js leaves alone:
42
+ * - `/_next/*` (build assets, prerender manifests, image optimisation)
43
+ * - `/__vinext/*` (vinext-internal endpoints)
44
+ *
45
+ * Returns the input unchanged when i18n is not configured or when the path
46
+ * already starts with one of the configured locales. The host-based default
47
+ * locale (i18n.domains[].defaultLocale) is preferred over the global default
48
+ * when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
49
+ *
50
+ * Item 4 of issue #1336: without this normalisation, requests like
51
+ * `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`
52
+ * with `locale: false` do not match because there is no segment for
53
+ * `:locale`. After normalisation the request looks like `/en/to-sv` and
54
+ * the rule matches with `:locale=en`.
55
+ *
56
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
57
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
58
+ */
59
+ declare function normalizeDefaultLocalePathname(pathname: string, i18n: NextI18nConfig | null | undefined, options?: {
60
+ hostname?: string | null;
61
+ }): string;
28
62
  /**
29
63
  * Extract locale prefix from a URL path.
30
64
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
@@ -35,6 +69,22 @@ declare function extractLocaleFromUrl(url: string, i18nConfig: NextI18nConfig, d
35
69
  url: string;
36
70
  hadPrefix: boolean;
37
71
  };
72
+ /**
73
+ * Strip a leading i18n locale segment from a URL so the result can be used for
74
+ * API route matching. Mirrors Next.js's base-server behaviour for Pages
75
+ * Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`
76
+ * runs before the `/api/*` check so `/fr/api/ok` resolves to the
77
+ * `pages/api/ok` handler instead of 404'ing.
78
+ *
79
+ * Returns the original URL untouched when:
80
+ * - `i18nConfig` is null/undefined (no i18n configured)
81
+ * - the URL does not start with a configured locale
82
+ *
83
+ * The query string is preserved verbatim — only the path segment is stripped.
84
+ *
85
+ * Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.
86
+ */
87
+ declare function stripI18nLocaleForApiRoute(url: string, i18nConfig: NextI18nConfig | null | undefined): string;
38
88
  /**
39
89
  * Detect the preferred locale from the Accept-Language header.
40
90
  * Returns the best matching locale or null.
@@ -53,5 +103,5 @@ declare function getLocaleRedirect({
53
103
  }: LocaleRedirectOptions): string | undefined;
54
104
  declare function resolvePagesI18nRequest(url: string, i18nConfig: NextI18nConfig, headers?: HeaderBag, hostname?: string | null, basePath?: string, trailingSlash?: boolean): PagesI18nRequestInfo;
55
105
  //#endregion
56
- export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, parseCookieLocaleFromHeader, resolvePagesI18nRequest };
106
+ export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
57
107
  //# sourceMappingURL=pages-i18n.d.ts.map
@@ -9,6 +9,46 @@ function readHeader(headers, name) {
9
9
  }
10
10
  const normalizeHostname = normalizeDomainHostname;
11
11
  /**
12
+ * Prepend the default locale prefix to a pathname when i18n is configured and
13
+ * the path does not already carry a locale prefix. Mirrors Next.js's
14
+ * server-side path normalisation in `resolve-routes.ts` (lines ~250-263):
15
+ *
16
+ * if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {
17
+ * parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`
18
+ * }
19
+ *
20
+ * Run this **before** matching against `next.config.js` redirects/rewrites
21
+ * (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so
22
+ * that requests arriving without a locale prefix still match those rules.
23
+ *
24
+ * Skips internal paths that Next.js leaves alone:
25
+ * - `/_next/*` (build assets, prerender manifests, image optimisation)
26
+ * - `/__vinext/*` (vinext-internal endpoints)
27
+ *
28
+ * Returns the input unchanged when i18n is not configured or when the path
29
+ * already starts with one of the configured locales. The host-based default
30
+ * locale (i18n.domains[].defaultLocale) is preferred over the global default
31
+ * when supplied, matching Next.js's `domainLocale.defaultLocale` branch.
32
+ *
33
+ * Item 4 of issue #1336: without this normalisation, requests like
34
+ * `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`
35
+ * with `locale: false` do not match because there is no segment for
36
+ * `:locale`. After normalisation the request looks like `/en/to-sv` and
37
+ * the rule matches with `:locale=en`.
38
+ *
39
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
40
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
41
+ */
42
+ function normalizeDefaultLocalePathname(pathname, i18n, options = {}) {
43
+ if (!i18n) return pathname;
44
+ if (pathname.startsWith("/_next/") || pathname.startsWith("/__vinext/")) return pathname;
45
+ const parts = pathname.split("/", 3);
46
+ if (parts[1] && i18n.locales.includes(parts[1])) return pathname;
47
+ const defaultLocale = detectDomainLocale(i18n.domains, options.hostname ?? void 0)?.defaultLocale ?? i18n.defaultLocale;
48
+ if (pathname === "/") return `/${defaultLocale}`;
49
+ return `/${defaultLocale}${pathname}`;
50
+ }
51
+ /**
12
52
  * Extract locale prefix from a URL path.
13
53
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
14
54
  * /about -> { locale: defaultLocale, url: "/about", hadPrefix: false }
@@ -28,6 +68,26 @@ function extractLocaleFromUrl(url, i18nConfig, defaultLocale = i18nConfig.defaul
28
68
  };
29
69
  }
30
70
  /**
71
+ * Strip a leading i18n locale segment from a URL so the result can be used for
72
+ * API route matching. Mirrors Next.js's base-server behaviour for Pages
73
+ * Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`
74
+ * runs before the `/api/*` check so `/fr/api/ok` resolves to the
75
+ * `pages/api/ok` handler instead of 404'ing.
76
+ *
77
+ * Returns the original URL untouched when:
78
+ * - `i18nConfig` is null/undefined (no i18n configured)
79
+ * - the URL does not start with a configured locale
80
+ *
81
+ * The query string is preserved verbatim — only the path segment is stripped.
82
+ *
83
+ * Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.
84
+ */
85
+ function stripI18nLocaleForApiRoute(url, i18nConfig) {
86
+ if (!i18nConfig) return url;
87
+ const { url: stripped, hadPrefix } = extractLocaleFromUrl(url, i18nConfig);
88
+ return hadPrefix ? stripped : url;
89
+ }
90
+ /**
31
91
  * Detect the preferred locale from the Accept-Language header.
32
92
  * Returns the best matching locale or null.
33
93
  */
@@ -120,6 +180,6 @@ function resolvePagesI18nRequest(url, i18nConfig, headers, hostname, basePath =
120
180
  };
121
181
  }
122
182
  //#endregion
123
- export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, parseCookieLocaleFromHeader, resolvePagesI18nRequest };
183
+ export { detectDomainLocale, detectLocaleFromAcceptLanguage, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
124
184
 
125
185
  //# sourceMappingURL=pages-i18n.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pages-i18n.js","names":[],"sources":["../../src/server/pages-i18n.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport {\n detectDomainLocale,\n normalizeDomainHostname,\n type DomainLocale,\n} from \"../utils/domain-locale.js\";\n\ntype HeaderValue = string | string[] | undefined;\ntype HeaderBag = Headers | Record<string, HeaderValue> | undefined;\n\ntype LocaleRedirectOptions = {\n headers?: HeaderBag;\n nextConfig: {\n basePath?: string;\n i18n?: NextI18nConfig | null;\n trailingSlash?: boolean;\n };\n pathLocale?: string;\n urlParsed: {\n hostname?: string | null;\n pathname: string;\n search?: string;\n };\n};\n\ntype PagesI18nRequestInfo = {\n locale: string;\n url: string;\n hadPrefix: boolean;\n domainLocale?: DomainLocale;\n redirectUrl?: string;\n};\n\nfunction readHeader(headers: HeaderBag, name: string): string | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined;\n }\n\n // For Record headers, callers must pass lowercase names. Node's\n // IncomingMessage.headers are already lowercased by the HTTP parser.\n const direct = headers[name];\n if (Array.isArray(direct)) return direct.join(\", \");\n return direct;\n}\n\nconst normalizeHostname = normalizeDomainHostname;\nexport { detectDomainLocale };\n\n/**\n * Extract locale prefix from a URL path.\n * e.g. /fr/about -> { locale: \"fr\", url: \"/about\", hadPrefix: true }\n * /about -> { locale: defaultLocale, url: \"/about\", hadPrefix: false }\n */\nexport function extractLocaleFromUrl(\n url: string,\n i18nConfig: NextI18nConfig,\n defaultLocale = i18nConfig.defaultLocale,\n): { locale: string; url: string; hadPrefix: boolean } {\n const pathname = url.split(\"?\")[0];\n const parts = pathname.split(\"/\").filter(Boolean);\n const query = url.includes(\"?\") ? url.slice(url.indexOf(\"?\")) : \"\";\n\n if (parts.length > 0 && i18nConfig.locales.includes(parts[0])) {\n const locale = parts[0];\n const rest = \"/\" + parts.slice(1).join(\"/\");\n return { locale, url: (rest || \"/\") + query, hadPrefix: true };\n }\n\n return { locale: defaultLocale, url, hadPrefix: false };\n}\n\n/**\n * Detect the preferred locale from the Accept-Language header.\n * Returns the best matching locale or null.\n */\nexport function detectLocaleFromAcceptLanguage(\n acceptLang: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!acceptLang) return null;\n\n const langs = acceptLang\n .split(\",\")\n .map((part) => {\n const [lang, qPart] = part.trim().split(\";\");\n const q = qPart ? parseFloat(qPart.replace(\"q=\", \"\")) : 1;\n return { lang: lang.trim().toLowerCase(), q };\n })\n .sort((a, b) => b.q - a.q);\n\n for (const { lang } of langs) {\n const exactMatch = i18nConfig.locales.find((locale) => locale.toLowerCase() === lang);\n if (exactMatch) return exactMatch;\n\n const prefix = lang.split(\"-\")[0];\n const prefixMatch = i18nConfig.locales.find((locale) => {\n const lowered = locale.toLowerCase();\n return lowered === prefix || lowered.startsWith(prefix + \"-\");\n });\n if (prefixMatch) return prefixMatch;\n }\n\n return null;\n}\n\n/**\n * Parse the NEXT_LOCALE cookie.\n * Returns the cookie value if it matches a configured locale, otherwise null.\n */\nexport function parseCookieLocaleFromHeader(\n cookieHeader: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!cookieHeader) return null;\n\n const match = cookieHeader.match(/(?:^|;\\s*)NEXT_LOCALE=([^;]*)/);\n if (!match) return null;\n\n let value: string;\n try {\n value = decodeURIComponent(match[1].trim());\n } catch {\n return null;\n }\n\n if (i18nConfig.locales.includes(value)) return value;\n return null;\n}\n\nfunction formatLocalizedRootPath(\n locale: string,\n defaultLocale: string,\n basePath = \"\",\n trailingSlash = false,\n search = \"\",\n): string | undefined {\n if (locale.toLowerCase() === defaultLocale.toLowerCase()) return undefined;\n const rootPath = `${basePath}/${locale}${trailingSlash ? \"/\" : \"\"}`;\n return `${rootPath.replace(/\\/{2,}/g, \"/\")}${search}`;\n}\n\nexport function getLocaleRedirect({\n headers,\n nextConfig,\n pathLocale,\n urlParsed,\n}: LocaleRedirectOptions): string | undefined {\n const i18n = nextConfig.i18n;\n // Next.js treats localeDetection as the global auto-redirect switch, so\n // disabling it also disables root domain-locale redirects, including\n // cross-domain redirects driven by the current host or Accept-Language.\n if (!i18n || i18n.localeDetection === false || urlParsed.pathname !== \"/\") return undefined;\n\n const domainLocale = detectDomainLocale(i18n.domains, urlParsed.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18n.defaultLocale;\n const preferredLocale =\n detectLocaleFromAcceptLanguage(readHeader(headers, \"accept-language\"), i18n) ?? undefined;\n const detectedLocale =\n pathLocale ||\n domainLocale?.defaultLocale ||\n (parseCookieLocaleFromHeader(readHeader(headers, \"cookie\"), i18n) ?? undefined) ||\n preferredLocale ||\n i18n.defaultLocale;\n const search = urlParsed.search ?? \"\";\n\n const preferredDomain = detectDomainLocale(i18n.domains, undefined, preferredLocale);\n if (domainLocale && preferredDomain) {\n const sameDomain =\n normalizeHostname(domainLocale.domain) === normalizeHostname(preferredDomain.domain);\n const sameLocale =\n preferredLocale !== undefined &&\n preferredDomain.defaultLocale.toLowerCase() === preferredLocale.toLowerCase();\n\n if (!sameDomain || !sameLocale) {\n // sameDomain && !sameLocale yields a locale-prefixed redirect on the same\n // host (for example /nl-BE). This matches Next.js and doesn't loop because\n // the next request is prefixed and therefore skips getLocaleRedirect().\n const scheme = `http${preferredDomain.http ? \"\" : \"s\"}`;\n const localePath = sameLocale || preferredLocale === undefined ? \"\" : `/${preferredLocale}`;\n const basePath = nextConfig.basePath ?? \"\";\n const rootPath = `${basePath}${localePath}${nextConfig.trailingSlash ? \"/\" : \"\"}` || \"/\";\n const normalizedPath = rootPath.startsWith(\"/\") ? rootPath : `/${rootPath}`;\n return `${scheme}://${preferredDomain.domain}${normalizedPath}${search}`;\n }\n }\n\n return formatLocalizedRootPath(\n detectedLocale,\n defaultLocale,\n nextConfig.basePath,\n nextConfig.trailingSlash,\n search,\n );\n}\n\nexport function resolvePagesI18nRequest(\n url: string,\n i18nConfig: NextI18nConfig,\n headers?: HeaderBag,\n hostname?: string | null,\n basePath = \"\",\n trailingSlash = false,\n): PagesI18nRequestInfo {\n const domainLocale = detectDomainLocale(i18nConfig.domains, hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18nConfig.defaultLocale;\n const localeInfo = extractLocaleFromUrl(url, i18nConfig, defaultLocale);\n\n let redirectUrl: string | undefined;\n if (!localeInfo.hadPrefix) {\n redirectUrl = getLocaleRedirect({\n headers,\n nextConfig: {\n basePath,\n i18n: i18nConfig,\n trailingSlash,\n },\n urlParsed: {\n hostname,\n pathname: localeInfo.url.split(\"?\")[0] || \"/\",\n search: localeInfo.url.includes(\"?\")\n ? localeInfo.url.slice(localeInfo.url.indexOf(\"?\"))\n : \"\",\n },\n });\n }\n\n return {\n ...localeInfo,\n domainLocale,\n redirectUrl,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pages-i18n.js","names":[],"sources":["../../src/server/pages-i18n.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport {\n detectDomainLocale,\n normalizeDomainHostname,\n type DomainLocale,\n} from \"../utils/domain-locale.js\";\n\ntype HeaderValue = string | string[] | undefined;\ntype HeaderBag = Headers | Record<string, HeaderValue> | undefined;\n\ntype LocaleRedirectOptions = {\n headers?: HeaderBag;\n nextConfig: {\n basePath?: string;\n i18n?: NextI18nConfig | null;\n trailingSlash?: boolean;\n };\n pathLocale?: string;\n urlParsed: {\n hostname?: string | null;\n pathname: string;\n search?: string;\n };\n};\n\ntype PagesI18nRequestInfo = {\n locale: string;\n url: string;\n hadPrefix: boolean;\n domainLocale?: DomainLocale;\n redirectUrl?: string;\n};\n\nfunction readHeader(headers: HeaderBag, name: string): string | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined;\n }\n\n // For Record headers, callers must pass lowercase names. Node's\n // IncomingMessage.headers are already lowercased by the HTTP parser.\n const direct = headers[name];\n if (Array.isArray(direct)) return direct.join(\", \");\n return direct;\n}\n\nconst normalizeHostname = normalizeDomainHostname;\nexport { detectDomainLocale };\n\n/**\n * Prepend the default locale prefix to a pathname when i18n is configured and\n * the path does not already carry a locale prefix. Mirrors Next.js's\n * server-side path normalisation in `resolve-routes.ts` (lines ~250-263):\n *\n * if (!initialLocaleResult.detectedLocale && !pathname.startsWith('/_next/')) {\n * parsedUrl.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`\n * }\n *\n * Run this **before** matching against `next.config.js` redirects/rewrites\n * (which are emitted by `applyLocaleToRoutes` in locale-prefixed forms) so\n * that requests arriving without a locale prefix still match those rules.\n *\n * Skips internal paths that Next.js leaves alone:\n * - `/_next/*` (build assets, prerender manifests, image optimisation)\n * - `/__vinext/*` (vinext-internal endpoints)\n *\n * Returns the input unchanged when i18n is not configured or when the path\n * already starts with one of the configured locales. The host-based default\n * locale (i18n.domains[].defaultLocale) is preferred over the global default\n * when supplied, matching Next.js's `domainLocale.defaultLocale` branch.\n *\n * Item 4 of issue #1336: without this normalisation, requests like\n * `/to-sv` (default locale = en) against a rule `source: '/:locale/to-sv'`\n * with `locale: false` do not match because there is no segment for\n * `:locale`. After normalisation the request looks like `/en/to-sv` and\n * the rule matches with `:locale=en`.\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts\n */\nexport function normalizeDefaultLocalePathname(\n pathname: string,\n i18n: NextI18nConfig | null | undefined,\n options: { hostname?: string | null } = {},\n): string {\n if (!i18n) return pathname;\n // Don't touch internal paths.\n if (pathname.startsWith(\"/_next/\") || pathname.startsWith(\"/__vinext/\")) return pathname;\n // If the path already starts with a known locale, leave it alone.\n const parts = pathname.split(\"/\", 3);\n // parts[0] is the empty string before the leading \"/\", parts[1] is the first segment.\n if (parts[1] && i18n.locales.includes(parts[1])) return pathname;\n\n // Pick the default locale: prefer the domain-mapped one when host matches.\n const domainLocale = detectDomainLocale(i18n.domains, options.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale ?? i18n.defaultLocale;\n\n if (pathname === \"/\") return `/${defaultLocale}`;\n return `/${defaultLocale}${pathname}`;\n}\n\n/**\n * Extract locale prefix from a URL path.\n * e.g. /fr/about -> { locale: \"fr\", url: \"/about\", hadPrefix: true }\n * /about -> { locale: defaultLocale, url: \"/about\", hadPrefix: false }\n */\nexport function extractLocaleFromUrl(\n url: string,\n i18nConfig: NextI18nConfig,\n defaultLocale = i18nConfig.defaultLocale,\n): { locale: string; url: string; hadPrefix: boolean } {\n const pathname = url.split(\"?\")[0];\n const parts = pathname.split(\"/\").filter(Boolean);\n const query = url.includes(\"?\") ? url.slice(url.indexOf(\"?\")) : \"\";\n\n if (parts.length > 0 && i18nConfig.locales.includes(parts[0])) {\n const locale = parts[0];\n const rest = \"/\" + parts.slice(1).join(\"/\");\n return { locale, url: (rest || \"/\") + query, hadPrefix: true };\n }\n\n return { locale: defaultLocale, url, hadPrefix: false };\n}\n\n/**\n * Strip a leading i18n locale segment from a URL so the result can be used for\n * API route matching. Mirrors Next.js's base-server behaviour for Pages\n * Router API routes: `normalizeLocalePath(pathname, i18n.locales).pathname`\n * runs before the `/api/*` check so `/fr/api/ok` resolves to the\n * `pages/api/ok` handler instead of 404'ing.\n *\n * Returns the original URL untouched when:\n * - `i18nConfig` is null/undefined (no i18n configured)\n * - the URL does not start with a configured locale\n *\n * The query string is preserved verbatim — only the path segment is stripped.\n *\n * Reference: packages/next/src/shared/lib/i18n/normalize-locale-path.ts.\n */\nexport function stripI18nLocaleForApiRoute(\n url: string,\n i18nConfig: NextI18nConfig | null | undefined,\n): string {\n if (!i18nConfig) return url;\n const { url: stripped, hadPrefix } = extractLocaleFromUrl(url, i18nConfig);\n return hadPrefix ? stripped : url;\n}\n\n/**\n * Detect the preferred locale from the Accept-Language header.\n * Returns the best matching locale or null.\n */\nexport function detectLocaleFromAcceptLanguage(\n acceptLang: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!acceptLang) return null;\n\n const langs = acceptLang\n .split(\",\")\n .map((part) => {\n const [lang, qPart] = part.trim().split(\";\");\n const q = qPart ? parseFloat(qPart.replace(\"q=\", \"\")) : 1;\n return { lang: lang.trim().toLowerCase(), q };\n })\n .sort((a, b) => b.q - a.q);\n\n for (const { lang } of langs) {\n const exactMatch = i18nConfig.locales.find((locale) => locale.toLowerCase() === lang);\n if (exactMatch) return exactMatch;\n\n const prefix = lang.split(\"-\")[0];\n const prefixMatch = i18nConfig.locales.find((locale) => {\n const lowered = locale.toLowerCase();\n return lowered === prefix || lowered.startsWith(prefix + \"-\");\n });\n if (prefixMatch) return prefixMatch;\n }\n\n return null;\n}\n\n/**\n * Parse the NEXT_LOCALE cookie.\n * Returns the cookie value if it matches a configured locale, otherwise null.\n */\nexport function parseCookieLocaleFromHeader(\n cookieHeader: string | null | undefined,\n i18nConfig: NextI18nConfig,\n): string | null {\n if (!cookieHeader) return null;\n\n const match = cookieHeader.match(/(?:^|;\\s*)NEXT_LOCALE=([^;]*)/);\n if (!match) return null;\n\n let value: string;\n try {\n value = decodeURIComponent(match[1].trim());\n } catch {\n return null;\n }\n\n if (i18nConfig.locales.includes(value)) return value;\n return null;\n}\n\nfunction formatLocalizedRootPath(\n locale: string,\n defaultLocale: string,\n basePath = \"\",\n trailingSlash = false,\n search = \"\",\n): string | undefined {\n if (locale.toLowerCase() === defaultLocale.toLowerCase()) return undefined;\n const rootPath = `${basePath}/${locale}${trailingSlash ? \"/\" : \"\"}`;\n return `${rootPath.replace(/\\/{2,}/g, \"/\")}${search}`;\n}\n\nexport function getLocaleRedirect({\n headers,\n nextConfig,\n pathLocale,\n urlParsed,\n}: LocaleRedirectOptions): string | undefined {\n const i18n = nextConfig.i18n;\n // Next.js treats localeDetection as the global auto-redirect switch, so\n // disabling it also disables root domain-locale redirects, including\n // cross-domain redirects driven by the current host or Accept-Language.\n if (!i18n || i18n.localeDetection === false || urlParsed.pathname !== \"/\") return undefined;\n\n const domainLocale = detectDomainLocale(i18n.domains, urlParsed.hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18n.defaultLocale;\n const preferredLocale =\n detectLocaleFromAcceptLanguage(readHeader(headers, \"accept-language\"), i18n) ?? undefined;\n const detectedLocale =\n pathLocale ||\n domainLocale?.defaultLocale ||\n (parseCookieLocaleFromHeader(readHeader(headers, \"cookie\"), i18n) ?? undefined) ||\n preferredLocale ||\n i18n.defaultLocale;\n const search = urlParsed.search ?? \"\";\n\n const preferredDomain = detectDomainLocale(i18n.domains, undefined, preferredLocale);\n if (domainLocale && preferredDomain) {\n const sameDomain =\n normalizeHostname(domainLocale.domain) === normalizeHostname(preferredDomain.domain);\n const sameLocale =\n preferredLocale !== undefined &&\n preferredDomain.defaultLocale.toLowerCase() === preferredLocale.toLowerCase();\n\n if (!sameDomain || !sameLocale) {\n // sameDomain && !sameLocale yields a locale-prefixed redirect on the same\n // host (for example /nl-BE). This matches Next.js and doesn't loop because\n // the next request is prefixed and therefore skips getLocaleRedirect().\n const scheme = `http${preferredDomain.http ? \"\" : \"s\"}`;\n const localePath = sameLocale || preferredLocale === undefined ? \"\" : `/${preferredLocale}`;\n const basePath = nextConfig.basePath ?? \"\";\n const rootPath = `${basePath}${localePath}${nextConfig.trailingSlash ? \"/\" : \"\"}` || \"/\";\n const normalizedPath = rootPath.startsWith(\"/\") ? rootPath : `/${rootPath}`;\n return `${scheme}://${preferredDomain.domain}${normalizedPath}${search}`;\n }\n }\n\n return formatLocalizedRootPath(\n detectedLocale,\n defaultLocale,\n nextConfig.basePath,\n nextConfig.trailingSlash,\n search,\n );\n}\n\nexport function resolvePagesI18nRequest(\n url: string,\n i18nConfig: NextI18nConfig,\n headers?: HeaderBag,\n hostname?: string | null,\n basePath = \"\",\n trailingSlash = false,\n): PagesI18nRequestInfo {\n const domainLocale = detectDomainLocale(i18nConfig.domains, hostname ?? undefined);\n const defaultLocale = domainLocale?.defaultLocale || i18nConfig.defaultLocale;\n const localeInfo = extractLocaleFromUrl(url, i18nConfig, defaultLocale);\n\n let redirectUrl: string | undefined;\n if (!localeInfo.hadPrefix) {\n redirectUrl = getLocaleRedirect({\n headers,\n nextConfig: {\n basePath,\n i18n: i18nConfig,\n trailingSlash,\n },\n urlParsed: {\n hostname,\n pathname: localeInfo.url.split(\"?\")[0] || \"/\",\n search: localeInfo.url.includes(\"?\")\n ? localeInfo.url.slice(localeInfo.url.indexOf(\"?\"))\n : \"\",\n },\n });\n }\n\n return {\n ...localeInfo,\n domainLocale,\n redirectUrl,\n };\n}\n"],"mappings":"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"}
@@ -37,6 +37,16 @@ type CreatePagesReqResResult = {
37
37
  res: PagesReqResResponse;
38
38
  responsePromise: Promise<Response>;
39
39
  };
40
+ /**
41
+ * Read and parse a Pages Router API request body for the Workers/prod path.
42
+ *
43
+ * `maxBytes` defaults to the 1 MB Next.js default but may be overridden by
44
+ * `export const config = { api: { bodyParser: { sizeLimit: '4mb' } } }` on
45
+ * the route module. Handlers that opt out entirely (`bodyParser: false`)
46
+ * MUST skip this function so the body stream stays intact for user code.
47
+ *
48
+ * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
49
+ */
40
50
  declare function parsePagesApiBody(request: Request, maxBytes?: number): Promise<unknown>;
41
51
  declare function createPagesReqRes(options: CreatePagesReqResOptions): CreatePagesReqResResult;
42
52
  //#endregion
@@ -1,15 +1,26 @@
1
1
  import { parseCookies } from "../config/config-matchers.js";
2
2
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
3
+ import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
3
4
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
4
5
  import { decode } from "node:querystring";
5
6
  //#region src/server/pages-node-compat.ts
6
- const MAX_PAGES_API_BODY_SIZE = 1 * 1024 * 1024;
7
+ const MAX_PAGES_API_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;
7
8
  async function readPagesRequestBodyWithLimit(request, maxBytes) {
8
9
  if (!request.body) return "";
9
10
  return readStreamAsTextWithLimit(request.body, maxBytes, () => {
10
11
  throw new PagesBodyParseError("Request body too large", 413);
11
12
  });
12
13
  }
14
+ /**
15
+ * Read and parse a Pages Router API request body for the Workers/prod path.
16
+ *
17
+ * `maxBytes` defaults to the 1 MB Next.js default but may be overridden by
18
+ * `export const config = { api: { bodyParser: { sizeLimit: '4mb' } } }` on
19
+ * the route module. Handlers that opt out entirely (`bodyParser: false`)
20
+ * MUST skip this function so the body stream stays intact for user code.
21
+ *
22
+ * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
23
+ */
13
24
  async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
14
25
  if (Number.parseInt(request.headers.get("content-length") || "0", 10) > maxBytes) throw new PagesBodyParseError("Request body too large", 413);
15
26
  let rawBody = "";
@@ -1 +1 @@
1
- {"version":3,"file":"pages-node-compat.js","names":["decodeQueryString"],"sources":["../../src/server/pages-node-compat.ts"],"sourcesContent":["import { decode as decodeQueryString } from \"node:querystring\";\nimport { parseCookies } from \"../config/config-matchers.js\";\nimport { readStreamAsTextWithLimit } from \"../utils/text-stream.js\";\nimport { PagesBodyParseError, getMediaType, isJsonMediaType } from \"./pages-media-type.js\";\n\nconst MAX_PAGES_API_BODY_SIZE = 1 * 1024 * 1024;\n\n/**\n * @deprecated Use PagesBodyParseError from pages-media-type.ts instead.\n * Kept for backwards compatibility.\n */\nexport { PagesBodyParseError as PagesApiBodyParseError };\n\nexport type PagesRequestQuery = Record<string, string | string[]>;\n\nexport type PagesReqResRequest = {\n method: string;\n url: string;\n headers: Record<string, string>;\n query: PagesRequestQuery;\n body: unknown;\n cookies: Record<string, string>;\n};\n\nexport type PagesReqResHeaders = {\n [key: string]: string | number | boolean | string[];\n};\n\nexport type PagesReqResResponse = {\n statusCode: number;\n readonly headersSent: boolean;\n writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;\n setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;\n getHeader: (name: string) => string | number | boolean | string[] | undefined;\n end: (data?: BodyInit | null) => void;\n status: (code: number) => PagesReqResResponse;\n json: (data: unknown) => void;\n send: (data: unknown) => void;\n redirect: (statusOrUrl: number | string, url?: string) => void;\n getHeaders: () => PagesReqResHeaders;\n};\n\ntype CreatePagesReqResOptions = {\n body: unknown;\n query: PagesRequestQuery;\n request: Request;\n url: string;\n};\n\ntype CreatePagesReqResResult = {\n req: PagesReqResRequest;\n res: PagesReqResResponse;\n responsePromise: Promise<Response>;\n};\n\nasync function readPagesRequestBodyWithLimit(request: Request, maxBytes: number): Promise<string> {\n if (!request.body) {\n return \"\";\n }\n\n return readStreamAsTextWithLimit(request.body, maxBytes, () => {\n throw new PagesBodyParseError(\"Request body too large\", 413);\n });\n}\n\nexport async function parsePagesApiBody(\n request: Request,\n maxBytes = MAX_PAGES_API_BODY_SIZE,\n): Promise<unknown> {\n const contentLength = Number.parseInt(request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > maxBytes) {\n throw new PagesBodyParseError(\"Request body too large\", 413);\n }\n\n let rawBody = \"\";\n try {\n rawBody = await readPagesRequestBodyWithLimit(request, maxBytes);\n } catch (err) {\n if (err instanceof PagesBodyParseError) {\n throw err;\n }\n throw new PagesBodyParseError(\"Request body too large\", 413);\n }\n\n const mediaType = getMediaType(request.headers.get(\"content-type\"));\n if (!rawBody) {\n return isJsonMediaType(mediaType)\n ? {}\n : mediaType === \"application/x-www-form-urlencoded\"\n ? decodeQueryString(rawBody)\n : undefined;\n }\n\n if (isJsonMediaType(mediaType)) {\n try {\n return JSON.parse(rawBody);\n } catch {\n throw new PagesBodyParseError(\"Invalid JSON\", 400);\n }\n }\n\n if (mediaType === \"application/x-www-form-urlencoded\") {\n return decodeQueryString(rawBody);\n }\n\n return rawBody;\n}\n\nexport function createPagesReqRes(options: CreatePagesReqResOptions): CreatePagesReqResResult {\n const headersObj: Record<string, string> = {};\n for (const [key, value] of options.request.headers) {\n headersObj[key.toLowerCase()] = value;\n }\n\n const req: PagesReqResRequest = {\n method: options.request.method,\n url: options.url,\n headers: headersObj,\n query: options.query,\n body: options.body,\n cookies: parseCookies(options.request.headers.get(\"cookie\")),\n };\n\n let resStatusCode = 200;\n const resHeaders: Record<string, string | number | boolean> = {};\n const setCookieHeaders: string[] = [];\n let resBody: BodyInit | null = null;\n let ended = false;\n let resolveResponse!: (value: Response) => void;\n const responsePromise = new Promise<Response>((resolve) => {\n resolveResponse = resolve;\n });\n\n const res: PagesReqResResponse = {\n get statusCode() {\n return resStatusCode;\n },\n set statusCode(code) {\n resStatusCode = code;\n },\n get headersSent() {\n return ended;\n },\n writeHead(code, headers) {\n resStatusCode = code;\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === \"set-cookie\") {\n if (Array.isArray(value)) {\n setCookieHeaders.push(...value.map(String));\n } else {\n setCookieHeaders.push(String(value));\n }\n } else {\n resHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : value;\n }\n }\n }\n return res;\n },\n setHeader(name, value) {\n if (name.toLowerCase() === \"set-cookie\") {\n // Node.js res.setHeader() replaces the existing value entirely.\n setCookieHeaders.length = 0;\n if (Array.isArray(value)) {\n setCookieHeaders.push(...value.map(String));\n } else {\n setCookieHeaders.push(String(value));\n }\n } else {\n resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : value;\n }\n return res;\n },\n getHeader(name) {\n if (name.toLowerCase() === \"set-cookie\") {\n return setCookieHeaders.length > 0 ? setCookieHeaders : undefined;\n }\n return resHeaders[name.toLowerCase()];\n },\n end(data) {\n if (ended) {\n return;\n }\n ended = true;\n if (data !== undefined && data !== null) {\n resBody = data;\n }\n const headers = new Headers();\n for (const [key, value] of Object.entries(resHeaders)) {\n headers.set(key, String(value));\n }\n for (const cookie of setCookieHeaders) {\n headers.append(\"set-cookie\", cookie);\n }\n resolveResponse(new Response(resBody, { status: resStatusCode, headers }));\n },\n status(code) {\n resStatusCode = code;\n return res;\n },\n json(data) {\n resHeaders[\"content-type\"] = \"application/json\";\n res.end(JSON.stringify(data));\n },\n send(data) {\n if (Buffer.isBuffer(data)) {\n if (!resHeaders[\"content-type\"]) {\n resHeaders[\"content-type\"] = \"application/octet-stream\";\n }\n resHeaders[\"content-length\"] = String(data.length);\n res.end(new Uint8Array(data));\n return;\n }\n\n if (typeof data === \"object\" && data !== null) {\n resHeaders[\"content-type\"] = \"application/json\";\n res.end(JSON.stringify(data));\n return;\n }\n\n if (!resHeaders[\"content-type\"]) {\n resHeaders[\"content-type\"] = \"text/plain\";\n }\n res.end(String(data));\n },\n redirect(statusOrUrl, url) {\n if (typeof statusOrUrl === \"string\") {\n res.writeHead(307, { Location: statusOrUrl });\n } else {\n res.writeHead(statusOrUrl, { Location: url ?? \"\" });\n }\n res.end();\n },\n getHeaders() {\n const headers: PagesReqResHeaders = { ...resHeaders };\n if (setCookieHeaders.length > 0) {\n headers[\"set-cookie\"] = setCookieHeaders;\n }\n return headers;\n },\n };\n\n return { req, res, responsePromise };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pages-node-compat.js","names":["decodeQueryString"],"sources":["../../src/server/pages-node-compat.ts"],"sourcesContent":["import { decode as decodeQueryString } from \"node:querystring\";\nimport { parseCookies } from \"../config/config-matchers.js\";\nimport { readStreamAsTextWithLimit } from \"../utils/text-stream.js\";\nimport { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from \"./pages-body-parser-config.js\";\nimport { PagesBodyParseError, getMediaType, isJsonMediaType } from \"./pages-media-type.js\";\n\nconst MAX_PAGES_API_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;\n\n/**\n * @deprecated Use PagesBodyParseError from pages-media-type.ts instead.\n * Kept for backwards compatibility.\n */\nexport { PagesBodyParseError as PagesApiBodyParseError };\n\nexport type PagesRequestQuery = Record<string, string | string[]>;\n\nexport type PagesReqResRequest = {\n method: string;\n url: string;\n headers: Record<string, string>;\n query: PagesRequestQuery;\n body: unknown;\n cookies: Record<string, string>;\n};\n\nexport type PagesReqResHeaders = {\n [key: string]: string | number | boolean | string[];\n};\n\nexport type PagesReqResResponse = {\n statusCode: number;\n readonly headersSent: boolean;\n writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;\n setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;\n getHeader: (name: string) => string | number | boolean | string[] | undefined;\n end: (data?: BodyInit | null) => void;\n status: (code: number) => PagesReqResResponse;\n json: (data: unknown) => void;\n send: (data: unknown) => void;\n redirect: (statusOrUrl: number | string, url?: string) => void;\n getHeaders: () => PagesReqResHeaders;\n};\n\ntype CreatePagesReqResOptions = {\n body: unknown;\n query: PagesRequestQuery;\n request: Request;\n url: string;\n};\n\ntype CreatePagesReqResResult = {\n req: PagesReqResRequest;\n res: PagesReqResResponse;\n responsePromise: Promise<Response>;\n};\n\nasync function readPagesRequestBodyWithLimit(request: Request, maxBytes: number): Promise<string> {\n if (!request.body) {\n return \"\";\n }\n\n return readStreamAsTextWithLimit(request.body, maxBytes, () => {\n throw new PagesBodyParseError(\"Request body too large\", 413);\n });\n}\n\n/**\n * Read and parse a Pages Router API request body for the Workers/prod path.\n *\n * `maxBytes` defaults to the 1 MB Next.js default but may be overridden by\n * `export const config = { api: { bodyParser: { sizeLimit: '4mb' } } }` on\n * the route module. Handlers that opt out entirely (`bodyParser: false`)\n * MUST skip this function so the body stream stays intact for user code.\n *\n * @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config\n */\nexport async function parsePagesApiBody(\n request: Request,\n maxBytes = MAX_PAGES_API_BODY_SIZE,\n): Promise<unknown> {\n const contentLength = Number.parseInt(request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > maxBytes) {\n throw new PagesBodyParseError(\"Request body too large\", 413);\n }\n\n let rawBody = \"\";\n try {\n rawBody = await readPagesRequestBodyWithLimit(request, maxBytes);\n } catch (err) {\n if (err instanceof PagesBodyParseError) {\n throw err;\n }\n throw new PagesBodyParseError(\"Request body too large\", 413);\n }\n\n const mediaType = getMediaType(request.headers.get(\"content-type\"));\n if (!rawBody) {\n return isJsonMediaType(mediaType)\n ? {}\n : mediaType === \"application/x-www-form-urlencoded\"\n ? decodeQueryString(rawBody)\n : undefined;\n }\n\n if (isJsonMediaType(mediaType)) {\n try {\n return JSON.parse(rawBody);\n } catch {\n throw new PagesBodyParseError(\"Invalid JSON\", 400);\n }\n }\n\n if (mediaType === \"application/x-www-form-urlencoded\") {\n return decodeQueryString(rawBody);\n }\n\n return rawBody;\n}\n\nexport function createPagesReqRes(options: CreatePagesReqResOptions): CreatePagesReqResResult {\n const headersObj: Record<string, string> = {};\n for (const [key, value] of options.request.headers) {\n headersObj[key.toLowerCase()] = value;\n }\n\n const req: PagesReqResRequest = {\n method: options.request.method,\n url: options.url,\n headers: headersObj,\n query: options.query,\n body: options.body,\n cookies: parseCookies(options.request.headers.get(\"cookie\")),\n };\n\n let resStatusCode = 200;\n const resHeaders: Record<string, string | number | boolean> = {};\n const setCookieHeaders: string[] = [];\n let resBody: BodyInit | null = null;\n let ended = false;\n let resolveResponse!: (value: Response) => void;\n const responsePromise = new Promise<Response>((resolve) => {\n resolveResponse = resolve;\n });\n\n const res: PagesReqResResponse = {\n get statusCode() {\n return resStatusCode;\n },\n set statusCode(code) {\n resStatusCode = code;\n },\n get headersSent() {\n return ended;\n },\n writeHead(code, headers) {\n resStatusCode = code;\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === \"set-cookie\") {\n if (Array.isArray(value)) {\n setCookieHeaders.push(...value.map(String));\n } else {\n setCookieHeaders.push(String(value));\n }\n } else {\n resHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : value;\n }\n }\n }\n return res;\n },\n setHeader(name, value) {\n if (name.toLowerCase() === \"set-cookie\") {\n // Node.js res.setHeader() replaces the existing value entirely.\n setCookieHeaders.length = 0;\n if (Array.isArray(value)) {\n setCookieHeaders.push(...value.map(String));\n } else {\n setCookieHeaders.push(String(value));\n }\n } else {\n resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : value;\n }\n return res;\n },\n getHeader(name) {\n if (name.toLowerCase() === \"set-cookie\") {\n return setCookieHeaders.length > 0 ? setCookieHeaders : undefined;\n }\n return resHeaders[name.toLowerCase()];\n },\n end(data) {\n if (ended) {\n return;\n }\n ended = true;\n if (data !== undefined && data !== null) {\n resBody = data;\n }\n const headers = new Headers();\n for (const [key, value] of Object.entries(resHeaders)) {\n headers.set(key, String(value));\n }\n for (const cookie of setCookieHeaders) {\n headers.append(\"set-cookie\", cookie);\n }\n resolveResponse(new Response(resBody, { status: resStatusCode, headers }));\n },\n status(code) {\n resStatusCode = code;\n return res;\n },\n json(data) {\n resHeaders[\"content-type\"] = \"application/json\";\n res.end(JSON.stringify(data));\n },\n send(data) {\n if (Buffer.isBuffer(data)) {\n if (!resHeaders[\"content-type\"]) {\n resHeaders[\"content-type\"] = \"application/octet-stream\";\n }\n resHeaders[\"content-length\"] = String(data.length);\n res.end(new Uint8Array(data));\n return;\n }\n\n if (typeof data === \"object\" && data !== null) {\n resHeaders[\"content-type\"] = \"application/json\";\n res.end(JSON.stringify(data));\n return;\n }\n\n if (!resHeaders[\"content-type\"]) {\n resHeaders[\"content-type\"] = \"text/plain\";\n }\n res.end(String(data));\n },\n redirect(statusOrUrl, url) {\n if (typeof statusOrUrl === \"string\") {\n res.writeHead(307, { Location: statusOrUrl });\n } else {\n res.writeHead(statusOrUrl, { Location: url ?? \"\" });\n }\n res.end();\n },\n getHeaders() {\n const headers: PagesReqResHeaders = { ...resHeaders };\n if (setCookieHeaders.length > 0) {\n headers[\"set-cookie\"] = setCookieHeaders;\n }\n return headers;\n },\n };\n\n return { req, res, responsePromise };\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
+ import { VinextNextData } from "../client/vinext-next-data.js";
2
3
  import { CachedPagesValue } from "../shims/cache.js";
3
4
  import { ISRCacheEntry } from "./isr-cache.js";
4
5
  import { PagesGsspResponse, PagesI18nRenderContext } from "./pages-page-response.js";
@@ -38,8 +39,19 @@ type PagesPageModule = {
38
39
  locales: string[];
39
40
  defaultLocale: string;
40
41
  }) => Promise<PagesStaticPathsResult> | PagesStaticPathsResult;
42
+ /**
43
+ * Pages Router data-fetching context.
44
+ *
45
+ * `params` is `null` for non-dynamic routes (no `[param]` segments) to
46
+ * match Next.js. User code typically falls back via `params || null`, so
47
+ * passing `null` (rather than `{}`) is required for the value to be
48
+ * observable as `null` once the data flows through to the page props.
49
+ *
50
+ * See: test/e2e/edge-pages-support/index.test.ts in Next.js for the
51
+ * authoritative assertion (`expect(props.params).toBe(null)`).
52
+ */
41
53
  getServerSideProps?: (context: {
42
- params: Record<string, unknown>;
54
+ params: Record<string, unknown> | null;
43
55
  req: unknown;
44
56
  res: PagesMutableGsspResponse;
45
57
  query: Record<string, unknown>;
@@ -49,10 +61,22 @@ type PagesPageModule = {
49
61
  defaultLocale?: string;
50
62
  }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;
51
63
  getStaticProps?: (context: {
52
- params: Record<string, unknown>;
64
+ params: Record<string, unknown> | null;
53
65
  locale?: string;
54
66
  locales?: string[];
55
67
  defaultLocale?: string;
68
+ /**
69
+ * Indicates why `getStaticProps` was invoked.
70
+ *
71
+ * - `"build"`: initial build-time prerender (before runtime traffic).
72
+ * - `"on-demand"`: triggered by `res.revalidate()` from an API route.
73
+ * - `"stale"`: stale-while-revalidate background regeneration.
74
+ *
75
+ * Mirrors Next.js `render.tsx`'s `revalidateReason` on the
76
+ * `GetStaticPropsContext` type — see
77
+ * `.nextjs-ref/packages/next/src/types.ts`.
78
+ */
79
+ revalidateReason?: "build" | "on-demand" | "stale";
56
80
  }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;
57
81
  };
58
82
  type RenderPagesIsrHtmlOptions = {
@@ -65,10 +89,20 @@ type RenderPagesIsrHtmlOptions = {
65
89
  renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;
66
90
  routePattern: string;
67
91
  safeJsonStringify: (value: unknown) => string;
92
+ vinext?: VinextNextData["__vinext"];
68
93
  };
69
94
  type ResolvePagesPageDataOptions = {
70
95
  applyRequestContexts: () => void;
71
96
  buildId: string | null;
97
+ /**
98
+ * When true, this is a `/_next/data/<buildId>/<page>.json` request. Callers
99
+ * that respond with a JSON envelope (`{ pageProps }`) instead of HTML must
100
+ * bypass the HTML ISR cache: a cached HTML body cannot be reshaped into the
101
+ * expected JSON shape, and storing JSON in the HTML cache would corrupt
102
+ * subsequent HTML hits. Next.js handles this the same way — see
103
+ * `isNextDataRequest` checks in `packages/next/src/server/base-server.ts`.
104
+ */
105
+ isDataReq?: boolean;
72
106
  createGsspReqRes: () => PagesGsspContextResponse;
73
107
  createPageElement: (pageProps: Record<string, unknown>) => ReactNode;
74
108
  fontLinkHeader: string;
@@ -77,6 +111,30 @@ type ResolvePagesPageDataOptions = {
77
111
  isrGet: (key: string) => Promise<ISRCacheEntry | null>;
78
112
  isrSet: (key: string, data: CachedPagesValue, revalidateSeconds: number, tags?: string[], expireSeconds?: number) => Promise<void>;
79
113
  expireSeconds?: number;
114
+ /**
115
+ * When true, this dispatch corresponds to a build-time prerender (the
116
+ * `vinext` build phase fetches each statically generated page through the
117
+ * production server). Maps to `revalidateReason: "build"` when
118
+ * `getStaticProps` is invoked. Mirrors Next.js's
119
+ * `renderOpts.isBuildTimePrerendering` flag — see
120
+ * `.nextjs-ref/packages/next/src/server/render.tsx`.
121
+ */
122
+ isBuildTimePrerendering?: boolean;
123
+ /**
124
+ * When true, this dispatch was triggered by an on-demand revalidation
125
+ * request (e.g. `res.revalidate()` in a Pages Router API route, or an
126
+ * equivalent webhook). Maps to `revalidateReason: "on-demand"` when
127
+ * `getStaticProps` is invoked. Mirrors Next.js's
128
+ * `renderOpts.isOnDemandRevalidate` flag — see
129
+ * `.nextjs-ref/packages/next/src/server/render.tsx`.
130
+ *
131
+ * Forward-looking plumbing: no caller currently sets this — `res.revalidate()`
132
+ * is not yet implemented in vinext. The `"on-demand"` branch in the
133
+ * `revalidateReason` resolver is intentionally unreachable today; keeping the
134
+ * typed contract here means wiring it up will be a one-line change once the
135
+ * trigger lands.
136
+ */
137
+ isOnDemandRevalidate?: boolean;
80
138
  pageModule: PagesPageModule;
81
139
  params: Record<string, unknown>;
82
140
  query: Record<string, unknown>;
@@ -87,18 +145,27 @@ type ResolvePagesPageDataOptions = {
87
145
  safeJsonStringify: (value: unknown) => string;
88
146
  sanitizeDestination: (destination: string) => string;
89
147
  scriptNonce?: string;
148
+ statusCode?: number;
90
149
  triggerBackgroundRegeneration: (key: string, renderFn: () => Promise<void>, errorContext?: {
91
150
  routerKind: "Pages Router";
92
151
  routePath: string;
93
152
  routeType: "render";
94
153
  }) => void;
95
154
  renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;
155
+ vinext?: VinextNextData["__vinext"];
96
156
  };
97
157
  type ResolvePagesPageDataRenderResult = {
98
158
  kind: "render";
99
159
  gsspRes: PagesGsspResponse | null;
100
160
  isrRevalidateSeconds: number | null;
101
161
  pageProps: Record<string, unknown>;
162
+ /**
163
+ * True when `getStaticPaths` returned `fallback: true` AND the requested path
164
+ * is not in the pre-rendered list. The caller renders a loading shell with
165
+ * empty props and `useRouter().isFallback === true` (matching Next.js's
166
+ * `render.tsx` — `getStaticProps` is skipped on the fallback render).
167
+ */
168
+ isFallback: boolean;
102
169
  };
103
170
  type ResolvePagesPageDataResponseResult = {
104
171
  kind: "response";
@@ -1,17 +1,18 @@
1
- import { VINEXT_CACHE_HEADER } from "./headers.js";
2
1
  import { normalizeStaticPathname } from "../routing/route-pattern.js";
2
+ import { buildCacheStateHeaders } from "./cache-headers.js";
3
3
  import { buildPagesCacheValue } from "./isr-cache.js";
4
+ import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
4
5
  import { buildCachedRevalidateCacheControl } from "./cache-control.js";
5
6
  import { buildPagesNextDataScript } from "./pages-page-response.js";
6
7
  //#region src/server/pages-page-data.ts
7
8
  function buildPagesNotFoundResponse() {
8
- return new Response("<!DOCTYPE html><html><body><h1>404 - Page not found</h1></body></html>", {
9
- status: 404,
10
- headers: { "Content-Type": "text/html" }
11
- });
9
+ return buildDefaultPagesNotFoundResponse();
12
10
  }
13
11
  function buildPagesDataNotFoundResponse() {
14
- return new Response("404", { status: 404 });
12
+ return new Response("{}", {
13
+ status: 404,
14
+ headers: { "Content-Type": "application/json" }
15
+ });
15
16
  }
16
17
  function resolvePagesRedirectStatus(redirect) {
17
18
  return redirect.statusCode != null ? redirect.statusCode : redirect.permanent ? 308 : 307;
@@ -41,17 +42,17 @@ function matchesPagesStaticPath(pathEntry, params, routeUrl) {
41
42
  return String(value) === String(actual);
42
43
  });
43
44
  }
44
- function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSeconds, expireSeconds, cacheControl) {
45
+ function buildPagesCacheResponse(html, cacheState, fontLinkHeader, revalidateSeconds, expireSeconds, cacheControl, status) {
45
46
  const effectiveRevalidateSeconds = cacheControl?.revalidate ?? revalidateSeconds ?? 60;
46
47
  const effectiveExpireSeconds = cacheControl === void 0 ? void 0 : cacheControl.expire ?? expireSeconds;
47
48
  const headers = {
48
49
  "Content-Type": "text/html",
49
- [VINEXT_CACHE_HEADER]: cacheState,
50
+ ...buildCacheStateHeaders(cacheState),
50
51
  "Cache-Control": buildCachedRevalidateCacheControl(cacheState, effectiveRevalidateSeconds, effectiveExpireSeconds)
51
52
  };
52
53
  if (fontLinkHeader) headers.Link = fontLinkHeader;
53
54
  return new Response(html, {
54
- status: 200,
55
+ status: status ?? 200,
55
56
  headers
56
57
  });
57
58
  }
@@ -77,29 +78,40 @@ async function renderPagesIsrHtml(options) {
77
78
  pageProps: options.pageProps,
78
79
  params: options.params,
79
80
  routePattern: options.routePattern,
80
- safeJsonStringify: options.safeJsonStringify
81
+ safeJsonStringify: options.safeJsonStringify,
82
+ vinext: options.vinext
81
83
  });
82
84
  return rewritePagesCachedHtml(options.cachedHtml, freshBody, nextDataScript);
83
85
  }
84
86
  async function resolvePagesPageData(options) {
87
+ const userFacingParams = options.route.isDynamic ? options.params : null;
88
+ let isFallback = false;
85
89
  if (typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
86
90
  const pathsResult = await options.pageModule.getStaticPaths({
87
91
  locales: options.i18n.locales ?? [],
88
92
  defaultLocale: options.i18n.defaultLocale ?? ""
89
93
  });
90
- if ((pathsResult?.fallback ?? false) === false) {
91
- if (!(pathsResult?.paths ?? []).some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, options.routeUrl))) return {
92
- kind: "response",
93
- response: buildPagesNotFoundResponse()
94
- };
95
- }
94
+ const fallback = pathsResult?.fallback ?? false;
95
+ const isValidPath = (pathsResult?.paths ?? []).some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, options.routeUrl));
96
+ if (fallback === false && !isValidPath) return {
97
+ kind: "response",
98
+ response: options.isDataReq ? buildPagesDataNotFoundResponse() : buildPagesNotFoundResponse()
99
+ };
100
+ if (fallback === true && !isValidPath && !options.isDataReq) isFallback = true;
96
101
  }
97
102
  let pageProps = {};
98
103
  let gsspRes = null;
104
+ if (isFallback) return {
105
+ kind: "render",
106
+ gsspRes: null,
107
+ isrRevalidateSeconds: null,
108
+ pageProps,
109
+ isFallback: true
110
+ };
99
111
  if (typeof options.pageModule.getServerSideProps === "function") {
100
112
  const { req, res, responsePromise } = options.createGsspReqRes();
101
113
  const result = await options.pageModule.getServerSideProps({
102
- params: options.params,
114
+ params: userFacingParams,
103
115
  req,
104
116
  res,
105
117
  query: options.query,
@@ -112,7 +124,7 @@ async function resolvePagesPageData(options) {
112
124
  kind: "response",
113
125
  response: await responsePromise
114
126
  };
115
- if (result?.props) pageProps = result.props;
127
+ if (result?.props) pageProps = await Promise.resolve(result.props);
116
128
  if (result?.redirect) return {
117
129
  kind: "response",
118
130
  response: new Response(null, {
@@ -122,7 +134,7 @@ async function resolvePagesPageData(options) {
122
134
  };
123
135
  if (result?.notFound) return {
124
136
  kind: "response",
125
- response: buildPagesDataNotFoundResponse()
137
+ response: options.isDataReq ? buildPagesDataNotFoundResponse() : buildPagesNotFoundResponse()
126
138
  };
127
139
  gsspRes = res;
128
140
  }
@@ -132,18 +144,19 @@ async function resolvePagesPageData(options) {
132
144
  const cacheKey = options.isrCacheKey("pages", pathname);
133
145
  const cached = await options.isrGet(cacheKey);
134
146
  const cachedValue = cached?.value.value;
135
- if (cachedValue?.kind === "PAGES" && cached && !cached.isStale && !options.scriptNonce) return {
147
+ if (cachedValue?.kind === "PAGES" && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq) return {
136
148
  kind: "response",
137
- response: buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl)
149
+ response: buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status)
138
150
  };
139
- if (cachedValue?.kind === "PAGES" && cached && cached.isStale && !options.scriptNonce) {
151
+ if (cachedValue?.kind === "PAGES" && cached && cached.isStale && !options.scriptNonce && !options.isDataReq) {
140
152
  options.triggerBackgroundRegeneration(cacheKey, async function() {
141
153
  return options.runInFreshUnifiedContext(async () => {
142
154
  const freshResult = await options.pageModule.getStaticProps?.({
143
- params: options.params,
155
+ params: userFacingParams,
144
156
  locale: options.i18n.locale,
145
157
  locales: options.i18n.locales,
146
- defaultLocale: options.i18n.defaultLocale
158
+ defaultLocale: options.i18n.defaultLocale,
159
+ revalidateReason: "stale"
147
160
  });
148
161
  if (freshResult?.props && typeof freshResult.revalidate === "number" && freshResult.revalidate > 0) {
149
162
  options.applyRequestContexts();
@@ -156,9 +169,10 @@ async function resolvePagesPageData(options) {
156
169
  params: options.params,
157
170
  renderIsrPassToStringAsync: options.renderIsrPassToStringAsync,
158
171
  routePattern: options.routePattern,
159
- safeJsonStringify: options.safeJsonStringify
172
+ safeJsonStringify: options.safeJsonStringify,
173
+ vinext: options.vinext
160
174
  });
161
- await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshResult.props), freshResult.revalidate, void 0, options.expireSeconds);
175
+ await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshResult.props, options.statusCode), freshResult.revalidate, void 0, options.expireSeconds);
162
176
  }
163
177
  });
164
178
  }, {
@@ -168,14 +182,15 @@ async function resolvePagesPageData(options) {
168
182
  });
169
183
  return {
170
184
  kind: "response",
171
- response: buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl)
185
+ response: buildPagesCacheResponse(cachedValue.html, "STALE", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status)
172
186
  };
173
187
  }
174
188
  const result = await options.pageModule.getStaticProps({
175
- params: options.params,
189
+ params: userFacingParams,
176
190
  locale: options.i18n.locale,
177
191
  locales: options.i18n.locales,
178
- defaultLocale: options.i18n.defaultLocale
192
+ defaultLocale: options.i18n.defaultLocale,
193
+ revalidateReason: options.isOnDemandRevalidate ? "on-demand" : options.isBuildTimePrerendering ? "build" : "stale"
179
194
  });
180
195
  if (result?.props) pageProps = result.props;
181
196
  if (result?.redirect) return {
@@ -187,7 +202,7 @@ async function resolvePagesPageData(options) {
187
202
  };
188
203
  if (result?.notFound) return {
189
204
  kind: "response",
190
- response: buildPagesDataNotFoundResponse()
205
+ response: options.isDataReq ? buildPagesDataNotFoundResponse() : buildPagesNotFoundResponse()
191
206
  };
192
207
  if (typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
193
208
  }
@@ -195,7 +210,8 @@ async function resolvePagesPageData(options) {
195
210
  kind: "render",
196
211
  gsspRes,
197
212
  isrRevalidateSeconds,
198
- pageProps
213
+ pageProps,
214
+ isFallback: false
199
215
  };
200
216
  }
201
217
  //#endregion