vinext 0.0.50 → 0.0.52

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 (462) hide show
  1. package/dist/build/google-fonts/fallback-metrics-data.js +14031 -0
  2. package/dist/build/google-fonts/fallback-metrics-data.js.map +1 -0
  3. package/dist/build/google-fonts/fallback-metrics.d.ts +13 -0
  4. package/dist/build/google-fonts/fallback-metrics.js +46 -0
  5. package/dist/build/google-fonts/fallback-metrics.js.map +1 -0
  6. package/dist/build/precompress.d.ts +13 -2
  7. package/dist/build/precompress.js +23 -13
  8. package/dist/build/precompress.js.map +1 -1
  9. package/dist/build/prerender.d.ts +4 -15
  10. package/dist/build/prerender.js +83 -53
  11. package/dist/build/prerender.js.map +1 -1
  12. package/dist/build/report.d.ts +5 -4
  13. package/dist/build/report.js +196 -348
  14. package/dist/build/report.js.map +1 -1
  15. package/dist/check.js +5 -0
  16. package/dist/check.js.map +1 -1
  17. package/dist/cli-args.d.ts +1 -0
  18. package/dist/cli-args.js +5 -0
  19. package/dist/cli-args.js.map +1 -1
  20. package/dist/cli.js +99 -3
  21. package/dist/cli.js.map +1 -1
  22. package/dist/client/navigation-runtime.d.ts +47 -0
  23. package/dist/client/navigation-runtime.js +156 -0
  24. package/dist/client/navigation-runtime.js.map +1 -0
  25. package/dist/client/pages-router-link-navigation.d.ts +26 -0
  26. package/dist/client/pages-router-link-navigation.js +14 -0
  27. package/dist/client/pages-router-link-navigation.js.map +1 -0
  28. package/dist/client/vinext-next-data.d.ts +12 -2
  29. package/dist/client/vinext-next-data.js +50 -1
  30. package/dist/client/vinext-next-data.js.map +1 -0
  31. package/dist/client/window-next.d.ts +3 -1
  32. package/dist/client/window-next.js.map +1 -1
  33. package/dist/cloudflare/kv-cache-handler.js +2 -1
  34. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  35. package/dist/config/config-matchers.d.ts +63 -16
  36. package/dist/config/config-matchers.js +143 -8
  37. package/dist/config/config-matchers.js.map +1 -1
  38. package/dist/config/dotenv.d.ts +11 -1
  39. package/dist/config/dotenv.js.map +1 -1
  40. package/dist/config/next-config.d.ts +107 -5
  41. package/dist/config/next-config.js +233 -7
  42. package/dist/config/next-config.js.map +1 -1
  43. package/dist/config/tsconfig-paths.d.ts +13 -0
  44. package/dist/config/tsconfig-paths.js +117 -0
  45. package/dist/config/tsconfig-paths.js.map +1 -0
  46. package/dist/deploy.js +104 -41
  47. package/dist/deploy.js.map +1 -1
  48. package/dist/entries/app-browser-entry.d.ts +2 -2
  49. package/dist/entries/app-browser-entry.js +34 -3
  50. package/dist/entries/app-browser-entry.js.map +1 -1
  51. package/dist/entries/app-rsc-entry.d.ts +19 -1
  52. package/dist/entries/app-rsc-entry.js +89 -23
  53. package/dist/entries/app-rsc-entry.js.map +1 -1
  54. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  55. package/dist/entries/app-rsc-manifest.js +57 -7
  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 +21 -7
  61. package/dist/entries/pages-client-entry.js.map +1 -1
  62. package/dist/entries/pages-server-entry.js +77 -9
  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 +260 -75
  68. package/dist/index.js.map +1 -1
  69. package/dist/plugins/client-reference-dedup.d.ts +15 -2
  70. package/dist/plugins/client-reference-dedup.js +138 -16
  71. package/dist/plugins/client-reference-dedup.js.map +1 -1
  72. package/dist/plugins/css-data-url.d.ts +7 -0
  73. package/dist/plugins/css-data-url.js +81 -0
  74. package/dist/plugins/css-data-url.js.map +1 -0
  75. package/dist/plugins/fonts.d.ts +2 -2
  76. package/dist/plugins/fonts.js +20 -9
  77. package/dist/plugins/fonts.js.map +1 -1
  78. package/dist/plugins/middleware-server-only.d.ts +54 -0
  79. package/dist/plugins/middleware-server-only.js +91 -0
  80. package/dist/plugins/middleware-server-only.js.map +1 -0
  81. package/dist/plugins/optimize-imports.js +4 -4
  82. package/dist/plugins/optimize-imports.js.map +1 -1
  83. package/dist/plugins/sass.d.ts +34 -0
  84. package/dist/plugins/sass.js +22 -0
  85. package/dist/plugins/sass.js.map +1 -0
  86. package/dist/plugins/strip-server-exports.js +5 -8
  87. package/dist/plugins/strip-server-exports.js.map +1 -1
  88. package/dist/routing/app-route-graph.d.ts +50 -2
  89. package/dist/routing/app-route-graph.js +140 -16
  90. package/dist/routing/app-route-graph.js.map +1 -1
  91. package/dist/routing/app-router.d.ts +2 -2
  92. package/dist/routing/app-router.js +2 -2
  93. package/dist/routing/app-router.js.map +1 -1
  94. package/dist/routing/route-pattern.d.ts +56 -1
  95. package/dist/routing/route-pattern.js +60 -1
  96. package/dist/routing/route-pattern.js.map +1 -1
  97. package/dist/routing/utils.d.ts +2 -1
  98. package/dist/routing/utils.js +4 -1
  99. package/dist/routing/utils.js.map +1 -1
  100. package/dist/server/api-handler.js +139 -37
  101. package/dist/server/api-handler.js.map +1 -1
  102. package/dist/server/app-browser-action-result.d.ts +27 -2
  103. package/dist/server/app-browser-action-result.js +63 -2
  104. package/dist/server/app-browser-action-result.js.map +1 -1
  105. package/dist/server/app-browser-entry.js +493 -195
  106. package/dist/server/app-browser-entry.js.map +1 -1
  107. package/dist/server/app-browser-hydration.d.ts +13 -1
  108. package/dist/server/app-browser-hydration.js +9 -1
  109. package/dist/server/app-browser-hydration.js.map +1 -1
  110. package/dist/server/app-browser-interception-context.d.ts +24 -0
  111. package/dist/server/app-browser-interception-context.js +32 -0
  112. package/dist/server/app-browser-interception-context.js.map +1 -0
  113. package/dist/server/app-browser-navigation-controller.d.ts +17 -2
  114. package/dist/server/app-browser-navigation-controller.js +33 -10
  115. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  116. package/dist/server/app-browser-popstate.d.ts +16 -0
  117. package/dist/server/app-browser-popstate.js +17 -0
  118. package/dist/server/app-browser-popstate.js.map +1 -0
  119. package/dist/server/app-browser-rsc-redirect.d.ts +29 -0
  120. package/dist/server/app-browser-rsc-redirect.js +37 -0
  121. package/dist/server/app-browser-rsc-redirect.js.map +1 -0
  122. package/dist/server/app-browser-state.d.ts +28 -7
  123. package/dist/server/app-browser-state.js +63 -27
  124. package/dist/server/app-browser-state.js.map +1 -1
  125. package/dist/server/app-browser-stream.d.ts +9 -17
  126. package/dist/server/app-browser-stream.js +18 -13
  127. package/dist/server/app-browser-stream.js.map +1 -1
  128. package/dist/server/app-browser-visible-commit.d.ts +7 -1
  129. package/dist/server/app-browser-visible-commit.js +39 -5
  130. package/dist/server/app-browser-visible-commit.js.map +1 -1
  131. package/dist/server/app-elements-wire.d.ts +43 -6
  132. package/dist/server/app-elements-wire.js +189 -7
  133. package/dist/server/app-elements-wire.js.map +1 -1
  134. package/dist/server/app-elements.d.ts +3 -2
  135. package/dist/server/app-elements.js +3 -2
  136. package/dist/server/app-elements.js.map +1 -1
  137. package/dist/server/app-fallback-renderer.d.ts +10 -1
  138. package/dist/server/app-fallback-renderer.js +41 -3
  139. package/dist/server/app-fallback-renderer.js.map +1 -1
  140. package/dist/server/app-history-state.d.ts +26 -0
  141. package/dist/server/app-history-state.js +53 -0
  142. package/dist/server/app-history-state.js.map +1 -0
  143. package/dist/server/app-middleware.d.ts +13 -0
  144. package/dist/server/app-middleware.js +3 -1
  145. package/dist/server/app-middleware.js.map +1 -1
  146. package/dist/server/app-optimistic-routing.d.ts +54 -0
  147. package/dist/server/app-optimistic-routing.js +200 -0
  148. package/dist/server/app-optimistic-routing.js.map +1 -0
  149. package/dist/server/app-page-boundary-render.d.ts +10 -1
  150. package/dist/server/app-page-boundary-render.js +13 -6
  151. package/dist/server/app-page-boundary-render.js.map +1 -1
  152. package/dist/server/app-page-boundary.js +3 -2
  153. package/dist/server/app-page-boundary.js.map +1 -1
  154. package/dist/server/app-page-cache.d.ts +26 -1
  155. package/dist/server/app-page-cache.js +86 -14
  156. package/dist/server/app-page-cache.js.map +1 -1
  157. package/dist/server/app-page-dispatch.d.ts +7 -0
  158. package/dist/server/app-page-dispatch.js +96 -12
  159. package/dist/server/app-page-dispatch.js.map +1 -1
  160. package/dist/server/app-page-element-builder.d.ts +7 -0
  161. package/dist/server/app-page-element-builder.js +34 -5
  162. package/dist/server/app-page-element-builder.js.map +1 -1
  163. package/dist/server/app-page-execution.d.ts +28 -1
  164. package/dist/server/app-page-execution.js +91 -7
  165. package/dist/server/app-page-execution.js.map +1 -1
  166. package/dist/server/app-page-head.d.ts +7 -0
  167. package/dist/server/app-page-head.js +23 -3
  168. package/dist/server/app-page-head.js.map +1 -1
  169. package/dist/server/app-page-probe.d.ts +23 -1
  170. package/dist/server/app-page-probe.js +29 -1
  171. package/dist/server/app-page-probe.js.map +1 -1
  172. package/dist/server/app-page-render-observation.d.ts +35 -0
  173. package/dist/server/app-page-render-observation.js +68 -0
  174. package/dist/server/app-page-render-observation.js.map +1 -0
  175. package/dist/server/app-page-render.d.ts +7 -1
  176. package/dist/server/app-page-render.js +81 -4
  177. package/dist/server/app-page-render.js.map +1 -1
  178. package/dist/server/app-page-request.d.ts +1 -0
  179. package/dist/server/app-page-request.js.map +1 -1
  180. package/dist/server/app-page-response.js +7 -5
  181. package/dist/server/app-page-response.js.map +1 -1
  182. package/dist/server/app-page-route-wiring.d.ts +3 -1
  183. package/dist/server/app-page-route-wiring.js +59 -24
  184. package/dist/server/app-page-route-wiring.js.map +1 -1
  185. package/dist/server/app-page-stream.d.ts +5 -0
  186. package/dist/server/app-page-stream.js +2 -0
  187. package/dist/server/app-page-stream.js.map +1 -1
  188. package/dist/server/app-prerender-static-params.d.ts +2 -1
  189. package/dist/server/app-prerender-static-params.js +44 -8
  190. package/dist/server/app-prerender-static-params.js.map +1 -1
  191. package/dist/server/app-route-handler-cache.d.ts +2 -2
  192. package/dist/server/app-route-handler-cache.js +3 -2
  193. package/dist/server/app-route-handler-cache.js.map +1 -1
  194. package/dist/server/app-route-handler-dispatch.d.ts +6 -1
  195. package/dist/server/app-route-handler-dispatch.js +1 -1
  196. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  197. package/dist/server/app-route-handler-execution.d.ts +17 -2
  198. package/dist/server/app-route-handler-execution.js.map +1 -1
  199. package/dist/server/app-route-handler-response.js +5 -4
  200. package/dist/server/app-route-handler-response.js.map +1 -1
  201. package/dist/server/app-router-entry.js +7 -15
  202. package/dist/server/app-router-entry.js.map +1 -1
  203. package/dist/server/app-rsc-cache-busting.d.ts +19 -1
  204. package/dist/server/app-rsc-cache-busting.js +36 -1
  205. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  206. package/dist/server/app-rsc-embedded-chunks.d.ts +9 -0
  207. package/dist/server/app-rsc-embedded-chunks.js +34 -0
  208. package/dist/server/app-rsc-embedded-chunks.js.map +1 -0
  209. package/dist/server/app-rsc-errors.d.ts +4 -1
  210. package/dist/server/app-rsc-errors.js +1 -1
  211. package/dist/server/app-rsc-errors.js.map +1 -1
  212. package/dist/server/app-rsc-handler.d.ts +21 -5
  213. package/dist/server/app-rsc-handler.js +38 -15
  214. package/dist/server/app-rsc-handler.js.map +1 -1
  215. package/dist/server/app-rsc-render-mode.d.ts +4 -3
  216. package/dist/server/app-rsc-render-mode.js +7 -1
  217. package/dist/server/app-rsc-render-mode.js.map +1 -1
  218. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  219. package/dist/server/app-rsc-request-normalization.js +4 -1
  220. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  221. package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
  222. package/dist/server/app-rsc-response-finalizer.js +10 -3
  223. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  224. package/dist/server/app-rsc-route-matching.d.ts +23 -0
  225. package/dist/server/app-rsc-route-matching.js +47 -25
  226. package/dist/server/app-rsc-route-matching.js.map +1 -1
  227. package/dist/server/app-server-action-execution.d.ts +35 -3
  228. package/dist/server/app-server-action-execution.js +87 -33
  229. package/dist/server/app-server-action-execution.js.map +1 -1
  230. package/dist/server/app-ssr-entry.d.ts +3 -0
  231. package/dist/server/app-ssr-entry.js +83 -58
  232. package/dist/server/app-ssr-entry.js.map +1 -1
  233. package/dist/server/app-ssr-error-meta.d.ts +14 -0
  234. package/dist/server/app-ssr-error-meta.js +50 -0
  235. package/dist/server/app-ssr-error-meta.js.map +1 -0
  236. package/dist/server/app-ssr-stream.d.ts +7 -2
  237. package/dist/server/app-ssr-stream.js +26 -15
  238. package/dist/server/app-ssr-stream.js.map +1 -1
  239. package/dist/server/artifact-compatibility.d.ts +13 -3
  240. package/dist/server/artifact-compatibility.js +12 -8
  241. package/dist/server/artifact-compatibility.js.map +1 -1
  242. package/dist/server/cache-headers.d.ts +7 -0
  243. package/dist/server/cache-headers.js +19 -0
  244. package/dist/server/cache-headers.js.map +1 -0
  245. package/dist/server/cache-proof.d.ts +170 -5
  246. package/dist/server/cache-proof.js +472 -18
  247. package/dist/server/cache-proof.js.map +1 -1
  248. package/dist/server/client-reuse-manifest.d.ts +99 -0
  249. package/dist/server/client-reuse-manifest.js +212 -0
  250. package/dist/server/client-reuse-manifest.js.map +1 -0
  251. package/dist/server/default-global-error-module.d.ts +20 -0
  252. package/dist/server/default-global-error-module.js +20 -0
  253. package/dist/server/default-global-error-module.js.map +1 -0
  254. package/dist/server/dev-lockfile.d.ts +110 -0
  255. package/dist/server/dev-lockfile.js +180 -0
  256. package/dist/server/dev-lockfile.js.map +1 -0
  257. package/dist/server/dev-server.d.ts +9 -1
  258. package/dist/server/dev-server.js +76 -19
  259. package/dist/server/dev-server.js.map +1 -1
  260. package/dist/server/edge-api-runtime.d.ts +5 -0
  261. package/dist/server/edge-api-runtime.js +8 -0
  262. package/dist/server/edge-api-runtime.js.map +1 -0
  263. package/dist/server/file-based-metadata.d.ts +13 -0
  264. package/dist/server/file-based-metadata.js +49 -2
  265. package/dist/server/file-based-metadata.js.map +1 -1
  266. package/dist/server/headers.d.ts +20 -1
  267. package/dist/server/headers.js +22 -2
  268. package/dist/server/headers.js.map +1 -1
  269. package/dist/server/html.js +1 -1
  270. package/dist/server/html.js.map +1 -1
  271. package/dist/server/http-error-responses.d.ts +26 -1
  272. package/dist/server/http-error-responses.js +32 -2
  273. package/dist/server/http-error-responses.js.map +1 -1
  274. package/dist/server/isr-cache.d.ts +8 -3
  275. package/dist/server/isr-cache.js +24 -6
  276. package/dist/server/isr-cache.js.map +1 -1
  277. package/dist/server/metadata-route-response.js +22 -5
  278. package/dist/server/metadata-route-response.js.map +1 -1
  279. package/dist/server/metadata-routes.js +27 -8
  280. package/dist/server/metadata-routes.js.map +1 -1
  281. package/dist/server/middleware-runtime.d.ts +15 -0
  282. package/dist/server/middleware-runtime.js +60 -7
  283. package/dist/server/middleware-runtime.js.map +1 -1
  284. package/dist/server/middleware.d.ts +13 -1
  285. package/dist/server/middleware.js +16 -2
  286. package/dist/server/middleware.js.map +1 -1
  287. package/dist/server/navigation-planner.d.ts +26 -6
  288. package/dist/server/navigation-planner.js +358 -24
  289. package/dist/server/navigation-planner.js.map +1 -1
  290. package/dist/server/navigation-trace.d.ts +9 -1
  291. package/dist/server/navigation-trace.js +8 -0
  292. package/dist/server/navigation-trace.js.map +1 -1
  293. package/dist/server/normalize-path.d.ts +2 -1
  294. package/dist/server/normalize-path.js +4 -1
  295. package/dist/server/normalize-path.js.map +1 -1
  296. package/dist/server/pages-api-route.d.ts +27 -1
  297. package/dist/server/pages-api-route.js +25 -3
  298. package/dist/server/pages-api-route.js.map +1 -1
  299. package/dist/server/pages-data-route.d.ts +77 -0
  300. package/dist/server/pages-data-route.js +97 -0
  301. package/dist/server/pages-data-route.js.map +1 -0
  302. package/dist/server/pages-i18n.d.ts +51 -1
  303. package/dist/server/pages-i18n.js +61 -1
  304. package/dist/server/pages-i18n.js.map +1 -1
  305. package/dist/server/pages-page-data.d.ts +32 -4
  306. package/dist/server/pages-page-data.js +52 -19
  307. package/dist/server/pages-page-data.js.map +1 -1
  308. package/dist/server/pages-page-response.d.ts +11 -1
  309. package/dist/server/pages-page-response.js +6 -4
  310. package/dist/server/pages-page-response.js.map +1 -1
  311. package/dist/server/prod-server.d.ts +26 -1
  312. package/dist/server/prod-server.js +150 -44
  313. package/dist/server/prod-server.js.map +1 -1
  314. package/dist/server/request-pipeline.d.ts +11 -2
  315. package/dist/server/request-pipeline.js +28 -11
  316. package/dist/server/request-pipeline.js.map +1 -1
  317. package/dist/server/seed-cache.d.ts +12 -31
  318. package/dist/server/seed-cache.js +22 -35
  319. package/dist/server/seed-cache.js.map +1 -1
  320. package/dist/server/server-action-not-found.d.ts +16 -3
  321. package/dist/server/server-action-not-found.js +27 -4
  322. package/dist/server/server-action-not-found.js.map +1 -1
  323. package/dist/server/server-globals.d.ts +5 -0
  324. package/dist/server/server-globals.js +37 -0
  325. package/dist/server/server-globals.js.map +1 -0
  326. package/dist/server/skip-cache-proof.d.ts +41 -0
  327. package/dist/server/skip-cache-proof.js +101 -0
  328. package/dist/server/skip-cache-proof.js.map +1 -0
  329. package/dist/server/static-file-cache.d.ts +1 -1
  330. package/dist/server/static-file-cache.js +7 -6
  331. package/dist/server/static-file-cache.js.map +1 -1
  332. package/dist/shims/cache-runtime.d.ts +19 -2
  333. package/dist/shims/cache-runtime.js +67 -11
  334. package/dist/shims/cache-runtime.js.map +1 -1
  335. package/dist/shims/cache.d.ts +5 -18
  336. package/dist/shims/cache.js +2 -0
  337. package/dist/shims/cache.js.map +1 -1
  338. package/dist/shims/client-locale.d.ts +15 -0
  339. package/dist/shims/client-locale.js +13 -0
  340. package/dist/shims/client-locale.js.map +1 -0
  341. package/dist/shims/default-global-error.d.ts +32 -0
  342. package/dist/shims/default-global-error.js +181 -0
  343. package/dist/shims/default-global-error.js.map +1 -0
  344. package/dist/shims/document.d.ts +59 -3
  345. package/dist/shims/document.js +36 -5
  346. package/dist/shims/document.js.map +1 -1
  347. package/dist/shims/error-boundary.d.ts +2 -2
  348. package/dist/shims/error-boundary.js +6 -8
  349. package/dist/shims/error-boundary.js.map +1 -1
  350. package/dist/shims/error.d.ts +18 -1
  351. package/dist/shims/error.js +56 -1
  352. package/dist/shims/error.js.map +1 -1
  353. package/dist/shims/fetch-cache.d.ts +4 -1
  354. package/dist/shims/fetch-cache.js +40 -5
  355. package/dist/shims/fetch-cache.js.map +1 -1
  356. package/dist/shims/font-google-base.d.ts +22 -8
  357. package/dist/shims/font-google-base.js +41 -71
  358. package/dist/shims/font-google-base.js.map +1 -1
  359. package/dist/shims/font-local.d.ts +3 -20
  360. package/dist/shims/font-local.js +23 -75
  361. package/dist/shims/font-local.js.map +1 -1
  362. package/dist/shims/font-utils.d.ts +51 -0
  363. package/dist/shims/font-utils.js +97 -0
  364. package/dist/shims/font-utils.js.map +1 -0
  365. package/dist/shims/form.js +13 -6
  366. package/dist/shims/form.js.map +1 -1
  367. package/dist/shims/hash-scroll.d.ts +7 -0
  368. package/dist/shims/hash-scroll.js +30 -0
  369. package/dist/shims/hash-scroll.js.map +1 -0
  370. package/dist/shims/headers.d.ts +8 -11
  371. package/dist/shims/headers.js +22 -2
  372. package/dist/shims/headers.js.map +1 -1
  373. package/dist/shims/image.d.ts +1 -0
  374. package/dist/shims/image.js +144 -78
  375. package/dist/shims/image.js.map +1 -1
  376. package/dist/shims/internal/app-router-context.d.ts +6 -6
  377. package/dist/shims/internal/app-router-context.js +17 -6
  378. package/dist/shims/internal/app-router-context.js.map +1 -1
  379. package/dist/shims/link-prefetch.d.ts +9 -1
  380. package/dist/shims/link-prefetch.js +11 -6
  381. package/dist/shims/link-prefetch.js.map +1 -1
  382. package/dist/shims/link.d.ts +33 -5
  383. package/dist/shims/link.js +205 -50
  384. package/dist/shims/link.js.map +1 -1
  385. package/dist/shims/metadata.d.ts +16 -30
  386. package/dist/shims/metadata.js +91 -32
  387. package/dist/shims/metadata.js.map +1 -1
  388. package/dist/shims/navigation.d.ts +164 -17
  389. package/dist/shims/navigation.js +355 -84
  390. package/dist/shims/navigation.js.map +1 -1
  391. package/dist/shims/navigation.react-server.d.ts +3 -2
  392. package/dist/shims/navigation.react-server.js +5 -2
  393. package/dist/shims/navigation.react-server.js.map +1 -1
  394. package/dist/shims/og.d.ts +18 -2
  395. package/dist/shims/og.js +49 -1
  396. package/dist/shims/og.js.map +1 -0
  397. package/dist/shims/pages-router-runtime.d.ts +7 -0
  398. package/dist/shims/pages-router-runtime.js +16 -0
  399. package/dist/shims/pages-router-runtime.js.map +1 -0
  400. package/dist/shims/request-state-types.d.ts +1 -1
  401. package/dist/shims/root-params.d.ts +3 -1
  402. package/dist/shims/root-params.js +11 -3
  403. package/dist/shims/root-params.js.map +1 -1
  404. package/dist/shims/router-state.d.ts +1 -0
  405. package/dist/shims/router-state.js.map +1 -1
  406. package/dist/shims/router.d.ts +40 -7
  407. package/dist/shims/router.js +355 -250
  408. package/dist/shims/router.js.map +1 -1
  409. package/dist/shims/script.js +110 -32
  410. package/dist/shims/script.js.map +1 -1
  411. package/dist/shims/server.d.ts +21 -4
  412. package/dist/shims/server.js +31 -10
  413. package/dist/shims/server.js.map +1 -1
  414. package/dist/shims/slot.d.ts +1 -0
  415. package/dist/shims/slot.js +45 -1
  416. package/dist/shims/slot.js.map +1 -1
  417. package/dist/shims/unified-request-context.d.ts +1 -1
  418. package/dist/shims/unified-request-context.js +2 -0
  419. package/dist/shims/unified-request-context.js.map +1 -1
  420. package/dist/shims/unrecognized-action-error.d.ts +35 -0
  421. package/dist/shims/unrecognized-action-error.js +41 -0
  422. package/dist/shims/unrecognized-action-error.js.map +1 -0
  423. package/dist/shims/url-safety.d.ts +23 -1
  424. package/dist/shims/url-safety.js +29 -2
  425. package/dist/shims/url-safety.js.map +1 -1
  426. package/dist/shims/url-utils.d.ts +21 -1
  427. package/dist/shims/url-utils.js +67 -3
  428. package/dist/shims/url-utils.js.map +1 -1
  429. package/dist/typegen.d.ts +10 -0
  430. package/dist/typegen.js +242 -0
  431. package/dist/typegen.js.map +1 -0
  432. package/dist/utils/asset-prefix.d.ts +97 -0
  433. package/dist/utils/asset-prefix.js +124 -0
  434. package/dist/utils/asset-prefix.js.map +1 -0
  435. package/dist/utils/base-path.d.ts +7 -1
  436. package/dist/utils/base-path.js +10 -1
  437. package/dist/utils/base-path.js.map +1 -1
  438. package/dist/utils/cache-control-metadata.d.ts +2 -1
  439. package/dist/utils/cache-control-metadata.js +1 -3
  440. package/dist/utils/cache-control-metadata.js.map +1 -1
  441. package/dist/utils/domain-locale.d.ts +2 -1
  442. package/dist/utils/domain-locale.js +9 -1
  443. package/dist/utils/domain-locale.js.map +1 -1
  444. package/dist/utils/lazy-chunks.d.ts +1 -1
  445. package/dist/utils/lazy-chunks.js +1 -1
  446. package/dist/utils/lazy-chunks.js.map +1 -1
  447. package/dist/utils/navigation-signal.d.ts +1 -2
  448. package/dist/utils/navigation-signal.js +1 -1
  449. package/dist/utils/navigation-signal.js.map +1 -1
  450. package/dist/utils/prerender-output-paths.d.ts +15 -0
  451. package/dist/utils/prerender-output-paths.js +24 -0
  452. package/dist/utils/prerender-output-paths.js.map +1 -0
  453. package/dist/utils/query.d.ts +17 -1
  454. package/dist/utils/query.js +36 -1
  455. package/dist/utils/query.js.map +1 -1
  456. package/dist/utils/record.d.ts +5 -0
  457. package/dist/utils/record.js +8 -0
  458. package/dist/utils/record.js.map +1 -0
  459. package/dist/utils/sorted-array.d.ts +9 -0
  460. package/dist/utils/sorted-array.js +22 -0
  461. package/dist/utils/sorted-array.js.map +1 -0
  462. package/package.json +13 -5
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n commitCurrent: \"NC_COMMIT\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n commitCurrent: \"NC_COMMIT\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,eAAe;CACf,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AASD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AA0CD,SAAgB,qCAAqC,SAO3B;CACxB,OAAO;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,2BAA2B,QAAQ;EACnC,6BAA6B,QAAQ;EACrC,wBAAwB,QAAQ;EAChC,GAAI,QAAQ,wBAAwB,KAAA,IAChC,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,6BAA6B,QAAQ;EACtC;;AAGH,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;CACtB,OAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
1
+ {"version":3,"file":"navigation-trace.js","names":[],"sources":["../../src/server/navigation-trace.ts"],"sourcesContent":["export const NAVIGATION_TRACE_SCHEMA_VERSION = 0;\n\nexport type NavigationTraceSchemaVersion = 0;\n\nexport const NavigationTraceReasonCodes = {\n cacheProofRejected: \"NC_CACHE_REJECT\",\n commitCurrent: \"NC_COMMIT\",\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\",\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\",\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\",\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\",\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\",\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\",\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\",\n prefetchOnly: \"NC_PREFETCH_ONLY\",\n requestWork: \"NC_REQUEST\",\n rootBoundaryChanged: \"NC_ROOT\",\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\",\n staleOperation: \"NC_STALE\",\n} satisfies Readonly<{\n cacheProofRejected: \"NC_CACHE_REJECT\";\n commitCurrent: \"NC_COMMIT\";\n interceptedCommitCurrent: \"NC_INTERCEPT_COMMIT\";\n interceptedRejectedIncompatibleRoot: \"NC_INTERCEPT_REJECT_ROOT\";\n interceptedRejectedMissingProof: \"NC_INTERCEPT_REJECT_MISSING_PROOF\";\n interceptedRejectedMissingSlotProof: \"NC_INTERCEPT_REJECT_SLOT\";\n interceptedRejectedTargetMismatch: \"NC_INTERCEPT_REJECT_TARGET\";\n interceptedRejectedUndeclaredTopology: \"NC_INTERCEPT_REJECT_GRAPH\";\n interceptedRejectedUnknownSource: \"NC_INTERCEPT_REJECT_SOURCE\";\n prefetchOnly: \"NC_PREFETCH_ONLY\";\n requestWork: \"NC_REQUEST\";\n rootBoundaryChanged: \"NC_ROOT\";\n rootBoundaryUnknown: \"NC_ROOT_UNKNOWN\";\n staleOperation: \"NC_STALE\";\n}>;\n\nexport const NavigationTraceTransactionCodes = {\n hardNavigate: \"NT_HARD_NAVIGATE\",\n noCommit: \"NT_NO_COMMIT\",\n visibleCommit: \"NT_VISIBLE_COMMIT\",\n} satisfies Readonly<{\n hardNavigate: \"NT_HARD_NAVIGATE\";\n noCommit: \"NT_NO_COMMIT\";\n visibleCommit: \"NT_VISIBLE_COMMIT\";\n}>;\n\nexport type NavigationTraceReasonCode =\n (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];\n\nexport type NavigationTraceTransactionCode =\n (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];\n\nexport type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;\n\nexport type NavigationTraceFieldName =\n | \"activeNavigationId\"\n | \"cacheProofCode\"\n | \"cacheProofMode\"\n | \"cacheProofReuseClass\"\n | \"cacheProofScope\"\n | \"currentRootLayoutTreePath\"\n | \"currentVisibleCommitVersion\"\n | \"nextRootLayoutTreePath\"\n | \"eventKind\"\n | \"operationLane\"\n | \"pendingOperationId\"\n | \"startedVisibleCommitVersion\"\n | \"startedNavigationId\"\n | \"targetHref\"\n | \"traverseDirection\";\n\nexport type NavigationTraceFieldValue = string | number | boolean | null;\n\nexport type NavigationTraceFields = Readonly<\n Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>\n>;\n\nexport type NavigationTraceEntry = Readonly<{\n code: NavigationTraceCode;\n fields: NavigationTraceFields;\n}>;\n\nexport type NavigationTrace = Readonly<{\n schemaVersion: NavigationTraceSchemaVersion;\n entries: readonly NavigationTraceEntry[];\n}>;\n\nexport function createNavigationLifecycleTraceFields(options: {\n activeNavigationId?: number;\n currentRootLayoutTreePath: string | null;\n currentVisibleCommitVersion: number;\n nextRootLayoutTreePath: string | null;\n startedNavigationId?: number;\n startedVisibleCommitVersion: number;\n}): NavigationTraceFields {\n return {\n ...(options.activeNavigationId !== undefined\n ? { activeNavigationId: options.activeNavigationId }\n : {}),\n currentRootLayoutTreePath: options.currentRootLayoutTreePath,\n currentVisibleCommitVersion: options.currentVisibleCommitVersion,\n nextRootLayoutTreePath: options.nextRootLayoutTreePath,\n ...(options.startedNavigationId !== undefined\n ? { startedNavigationId: options.startedNavigationId }\n : {}),\n startedVisibleCommitVersion: options.startedVisibleCommitVersion,\n };\n}\n\nfunction createNavigationTraceEntry(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTraceEntry {\n return {\n code,\n fields: { ...fields },\n };\n}\n\nexport function createNavigationTrace(\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: NAVIGATION_TRACE_SCHEMA_VERSION,\n entries: [createNavigationTraceEntry(code, fields)],\n };\n}\n\nexport function prependNavigationTraceEntry(\n trace: NavigationTrace,\n code: NavigationTraceCode,\n fields: NavigationTraceFields = {},\n): NavigationTrace {\n return {\n schemaVersion: trace.schemaVersion,\n entries: [createNavigationTraceEntry(code, fields), ...trace.entries],\n };\n}\n"],"mappings":";AAAA,MAAa,kCAAkC;AAI/C,MAAa,6BAA6B;CACxC,oBAAoB;CACpB,eAAe;CACf,0BAA0B;CAC1B,qCAAqC;CACrC,iCAAiC;CACjC,qCAAqC;CACrC,mCAAmC;CACnC,uCAAuC;CACvC,kCAAkC;CAClC,cAAc;CACd,aAAa;CACb,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CACjB;AAiBD,MAAa,kCAAkC;CAC7C,cAAc;CACd,UAAU;CACV,eAAe;CAChB;AA+CD,SAAgB,qCAAqC,SAO3B;CACxB,OAAO;EACL,GAAI,QAAQ,uBAAuB,KAAA,IAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,2BAA2B,QAAQ;EACnC,6BAA6B,QAAQ;EACrC,wBAAwB,QAAQ;EAChC,GAAI,QAAQ,wBAAwB,KAAA,IAChC,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,6BAA6B,QAAQ;EACtC;;AAGH,SAAS,2BACP,MACA,SAAgC,EAAE,EACZ;CACtB,OAAO;EACL;EACA,QAAQ,EAAE,GAAG,QAAQ;EACtB;;AAGH,SAAgB,sBACd,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAA;EACA,SAAS,CAAC,2BAA2B,MAAM,OAAO,CAAC;EACpD;;AAGH,SAAgB,4BACd,OACA,MACA,SAAgC,EAAE,EACjB;CACjB,OAAO;EACL,eAAe,MAAM;EACrB,SAAS,CAAC,2BAA2B,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EACtE"}
@@ -20,6 +20,7 @@ declare function escapePathDelimiters(segment: string, escapeEncoded?: boolean):
20
20
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts
21
21
  */
22
22
  declare function decodePathParams(pathname: string): string;
23
+ declare function isInterceptionMatchedUrlPath(value: string): boolean;
23
24
  /**
24
25
  * Path normalization utility for request handling.
25
26
  *
@@ -42,5 +43,5 @@ declare function decodePathParams(pathname: string): string;
42
43
  */
43
44
  declare function normalizePath(pathname: string): string;
44
45
  //#endregion
45
- export { decodePathParams, escapePathDelimiters, normalizePath };
46
+ export { decodePathParams, escapePathDelimiters, isInterceptionMatchedUrlPath, normalizePath };
46
47
  //# sourceMappingURL=normalize-path.d.ts.map
@@ -30,6 +30,9 @@ function decodePathParams(pathname) {
30
30
  }
31
31
  }).join("/");
32
32
  }
33
+ function isInterceptionMatchedUrlPath(value) {
34
+ return value.startsWith("/") && !value.startsWith("//") && !value.includes("?") && !value.includes("#") && !value.includes("\0");
35
+ }
33
36
  /**
34
37
  * Path normalization utility for request handling.
35
38
  *
@@ -62,6 +65,6 @@ function normalizePath(pathname) {
62
65
  return "/" + resolved.join("/");
63
66
  }
64
67
  //#endregion
65
- export { decodePathParams, escapePathDelimiters, normalizePath };
68
+ export { decodePathParams, escapePathDelimiters, isInterceptionMatchedUrlPath, normalizePath };
66
69
 
67
70
  //# sourceMappingURL=normalize-path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-path.js","names":[],"sources":["../../src/server/normalize-path.ts"],"sourcesContent":["/**\n * Re-encode path delimiter characters that were decoded by decodeURIComponent.\n * After decoding a URL segment, characters like / # ? \\ need to be re-encoded\n * so they don't change the path structure.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n */\nexport function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string {\n return segment.replace(\n new RegExp(`([/#?]${escapeEncoded ? \"|%(2f|23|3f|5c)\" : \"\"})`, \"gi\"),\n (char: string) => encodeURIComponent(char),\n );\n}\n\n/**\n * Decode a URL pathname segment-by-segment, preserving encoded path delimiters.\n * Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters\n * like %2F (/) %23 (#) %3F (?) %5C (\\) are re-encoded after decoding.\n *\n * This prevents encoded slashes from changing the path structure (e.g.\n * /admin%2Fpanel stays as a single segment, not /admin/panel).\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts\n */\nexport function decodePathParams(pathname: string): string {\n return pathname\n .split(\"/\")\n .map((seg) => {\n try {\n return escapePathDelimiters(decodeURIComponent(seg), true);\n } catch {\n return seg;\n }\n })\n .join(\"/\");\n}\n\n/**\n * Path normalization utility for request handling.\n *\n * Normalizes URL pathnames to a canonical form BEFORE any matching occurs\n * (middleware, routing, redirects, rewrites). This ensures middleware and\n * the router always see the same path, preventing path-confusion issues like\n * double-slash mismatches.\n *\n * Normalization rules:\n * 1. Collapse consecutive slashes: //foo///bar → /foo/bar\n * 2. Resolve single-dot segments: /foo/./bar → /foo/bar\n * 3. Resolve double-dot segments: /foo/../bar → /bar\n * 4. Ensure leading slash: foo/bar → /foo/bar\n * 5. Preserve root: / → /\n *\n * This function does NOT:\n * - Strip or add trailing slashes (handled separately by trailingSlash config)\n * - Decode percent-encoded characters (callers should decode before calling this)\n * - Lowercase the path (route matching is case-sensitive)\n */\nexport function normalizePath(pathname: string): string {\n // Fast path: already canonical (single leading /, no //, no /./, no /../)\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n\n const segments = pathname.split(\"/\");\n const resolved: string[] = [];\n\n for (const segment of segments) {\n if (segment === \"\" || segment === \".\") {\n // Skip empty segments (from // or leading /) and single-dot segments\n continue;\n }\n if (segment === \"..\") {\n // Go up one level, but never above root\n resolved.pop();\n } else {\n resolved.push(segment);\n }\n }\n\n return \"/\" + resolved.join(\"/\");\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,qBAAqB,SAAiB,eAAiC;CACrF,OAAO,QAAQ,QACb,IAAI,OAAO,SAAS,gBAAgB,oBAAoB,GAAG,IAAI,KAAK,GACnE,SAAiB,mBAAmB,KAAK,CAC3C;;;;;;;;;;;;;AAcH,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,SACJ,MAAM,IAAI,CACV,KAAK,QAAQ;EACZ,IAAI;GACF,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,KAAK;UACpD;GACN,OAAO;;GAET,CACD,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;AAuBd,SAAgB,cAAc,UAA0B;CAEtD,IACE,aAAa,OACZ,SAAS,SAAS,KACjB,SAAS,OAAO,OAChB,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,IACzB,CAAC,SAAS,SAAS,OAAO,IAC1B,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,EAE3B,OAAO;CAGT,MAAM,WAAW,SAAS,MAAM,IAAI;CACpC,MAAM,WAAqB,EAAE;CAE7B,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,YAAY,MAAM,YAAY,KAEhC;EAEF,IAAI,YAAY,MAEd,SAAS,KAAK;OAEd,SAAS,KAAK,QAAQ;;CAI1B,OAAO,MAAM,SAAS,KAAK,IAAI"}
1
+ {"version":3,"file":"normalize-path.js","names":[],"sources":["../../src/server/normalize-path.ts"],"sourcesContent":["/**\n * Re-encode path delimiter characters that were decoded by decodeURIComponent.\n * After decoding a URL segment, characters like / # ? \\ need to be re-encoded\n * so they don't change the path structure.\n *\n * Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts\n */\nexport function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string {\n return segment.replace(\n new RegExp(`([/#?]${escapeEncoded ? \"|%(2f|23|3f|5c)\" : \"\"})`, \"gi\"),\n (char: string) => encodeURIComponent(char),\n );\n}\n\n/**\n * Decode a URL pathname segment-by-segment, preserving encoded path delimiters.\n * Non-ASCII characters (e.g. %C3%A9 -> e) are decoded, but structural characters\n * like %2F (/) %23 (#) %3F (?) %5C (\\) are re-encoded after decoding.\n *\n * This prevents encoded slashes from changing the path structure (e.g.\n * /admin%2Fpanel stays as a single segment, not /admin/panel).\n *\n * Ported from Next.js: packages/next/src/server/lib/router-utils/decode-path-params.ts\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/decode-path-params.ts\n */\nexport function decodePathParams(pathname: string): string {\n return pathname\n .split(\"/\")\n .map((seg) => {\n try {\n return escapePathDelimiters(decodeURIComponent(seg), true);\n } catch {\n return seg;\n }\n })\n .join(\"/\");\n}\n\nexport function isInterceptionMatchedUrlPath(value: string): boolean {\n return (\n value.startsWith(\"/\") &&\n !value.startsWith(\"//\") &&\n !value.includes(\"?\") &&\n !value.includes(\"#\") &&\n !value.includes(\"\\0\")\n );\n}\n\n/**\n * Path normalization utility for request handling.\n *\n * Normalizes URL pathnames to a canonical form BEFORE any matching occurs\n * (middleware, routing, redirects, rewrites). This ensures middleware and\n * the router always see the same path, preventing path-confusion issues like\n * double-slash mismatches.\n *\n * Normalization rules:\n * 1. Collapse consecutive slashes: //foo///bar → /foo/bar\n * 2. Resolve single-dot segments: /foo/./bar → /foo/bar\n * 3. Resolve double-dot segments: /foo/../bar → /bar\n * 4. Ensure leading slash: foo/bar → /foo/bar\n * 5. Preserve root: / → /\n *\n * This function does NOT:\n * - Strip or add trailing slashes (handled separately by trailingSlash config)\n * - Decode percent-encoded characters (callers should decode before calling this)\n * - Lowercase the path (route matching is case-sensitive)\n */\nexport function normalizePath(pathname: string): string {\n // Fast path: already canonical (single leading /, no //, no /./, no /../)\n if (\n pathname === \"/\" ||\n (pathname.length > 1 &&\n pathname[0] === \"/\" &&\n !pathname.includes(\"//\") &&\n !pathname.includes(\"/./\") &&\n !pathname.includes(\"/../\") &&\n !pathname.endsWith(\"/.\") &&\n !pathname.endsWith(\"/..\"))\n ) {\n return pathname;\n }\n\n const segments = pathname.split(\"/\");\n const resolved: string[] = [];\n\n for (const segment of segments) {\n if (segment === \"\" || segment === \".\") {\n // Skip empty segments (from // or leading /) and single-dot segments\n continue;\n }\n if (segment === \"..\") {\n // Go up one level, but never above root\n resolved.pop();\n } else {\n resolved.push(segment);\n }\n }\n\n return \"/\" + resolved.join(\"/\");\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,qBAAqB,SAAiB,eAAiC;CACrF,OAAO,QAAQ,QACb,IAAI,OAAO,SAAS,gBAAgB,oBAAoB,GAAG,IAAI,KAAK,GACnE,SAAiB,mBAAmB,KAAK,CAC3C;;;;;;;;;;;;;AAcH,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,SACJ,MAAM,IAAI,CACV,KAAK,QAAQ;EACZ,IAAI;GACF,OAAO,qBAAqB,mBAAmB,IAAI,EAAE,KAAK;UACpD;GACN,OAAO;;GAET,CACD,KAAK,IAAI;;AAGd,SAAgB,6BAA6B,OAAwB;CACnE,OACE,MAAM,WAAW,IAAI,IACrB,CAAC,MAAM,WAAW,KAAK,IACvB,CAAC,MAAM,SAAS,IAAI,IACpB,CAAC,MAAM,SAAS,IAAI,IACpB,CAAC,MAAM,SAAS,KAAK;;;;;;;;;;;;;;;;;;;;;;AAwBzB,SAAgB,cAAc,UAA0B;CAEtD,IACE,aAAa,OACZ,SAAS,SAAS,KACjB,SAAS,OAAO,OAChB,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,IACzB,CAAC,SAAS,SAAS,OAAO,IAC1B,CAAC,SAAS,SAAS,KAAK,IACxB,CAAC,SAAS,SAAS,MAAM,EAE3B,OAAO;CAGT,MAAM,WAAW,SAAS,MAAM,IAAI;CACpC,MAAM,WAAqB,EAAE;CAE7B,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,YAAY,MAAM,YAAY,KAEhC;EAEF,IAAI,YAAY,MAEd,SAAS,KAAK;OAEd,SAAS,KAAK,QAAQ;;CAI1B,OAAO,MAAM,SAAS,KAAK,IAAI"}
@@ -1,9 +1,27 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
+ import { ExecutionContextLike } from "../shims/request-context.js";
2
3
  import { PagesReqResRequest, PagesReqResResponse, PagesRequestQuery } from "./pages-node-compat.js";
3
4
 
4
5
  //#region src/server/pages-api-route.d.ts
6
+ type PagesApiRouteConfig = {
7
+ runtime?: string;
8
+ };
9
+ type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;
10
+ type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
5
11
  type PagesApiRouteModule = {
6
- default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;
12
+ /**
13
+ * `export const config = { runtime: 'edge' }` — historical Pages Router form.
14
+ */
15
+ config?: PagesApiRouteConfig;
16
+ /**
17
+ * `export const runtime = 'edge'` — bare export form. Next.js resolves the
18
+ * effective runtime as `config.runtime ?? config.config?.runtime`, so a
19
+ * top-level `runtime` export takes precedence over the nested config form.
20
+ *
21
+ * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts
22
+ */
23
+ runtime?: string;
24
+ default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;
7
25
  };
8
26
  type PagesApiRouteMatch = {
9
27
  params: PagesRequestQuery;
@@ -12,6 +30,14 @@ type PagesApiRouteMatch = {
12
30
  };
13
31
  };
14
32
  type HandlePagesApiRouteOptions = {
33
+ /**
34
+ * Per-request Cloudflare Workers `ExecutionContext`. When provided, the
35
+ * API route runs inside `runWithExecutionContext(ctx, ...)` so any
36
+ * `after()` (or other shim) call inside the handler can reach
37
+ * `ctx.waitUntil()` via the ALS and keep the isolate alive past the
38
+ * response. Omit on Node.js dev where no Workers lifecycle exists.
39
+ */
40
+ ctx?: ExecutionContextLike;
15
41
  match: PagesApiRouteMatch | null;
16
42
  reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;
17
43
  request: Request;
@@ -1,17 +1,39 @@
1
+ import "./server-globals.js";
2
+ import { runWithExecutionContext } from "../shims/request-context.js";
3
+ import { NextRequest } from "../shims/server.js";
1
4
  import { internalServerErrorResponse } from "./http-error-responses.js";
2
5
  import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
3
6
  import { PagesBodyParseError } from "./pages-media-type.js";
7
+ import { isEdgeApiRuntime } from "./edge-api-runtime.js";
4
8
  import { createPagesReqRes, parsePagesApiBody } from "./pages-node-compat.js";
5
9
  //#region src/server/pages-api-route.ts
10
+ function resolveModuleRuntime(module) {
11
+ return module.runtime ?? module.config?.runtime;
12
+ }
6
13
  function buildPagesApiQuery(url, params) {
7
14
  return mergeRouteParamsIntoQuery(parseQueryString(url), params);
8
15
  }
16
+ function isEdgeApiRouteModule(module) {
17
+ return typeof module.default === "function" && isEdgeApiRuntime(resolveModuleRuntime(module));
18
+ }
19
+ function isNodeApiRouteModule(module) {
20
+ return typeof module.default === "function" && !isEdgeApiRuntime(resolveModuleRuntime(module));
21
+ }
9
22
  async function handlePagesApiRoute(options) {
23
+ if (options.ctx) return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));
24
+ return _handlePagesApiRoute(options);
25
+ }
26
+ async function _handlePagesApiRoute(options) {
10
27
  if (!options.match) return new Response("404 - API route not found", { status: 404 });
11
28
  const { route, params } = options.match;
12
- const handler = route.module.default;
13
- if (typeof handler !== "function") return new Response("API route does not export a default function", { status: 500 });
14
29
  try {
30
+ if (isEdgeApiRouteModule(route.module)) {
31
+ const nextRequest = new NextRequest(options.request);
32
+ const response = await route.module.default(nextRequest);
33
+ if (response instanceof Response) return response;
34
+ throw new Error("Edge API route did not return a Response");
35
+ }
36
+ if (!isNodeApiRouteModule(route.module)) return new Response("API route does not export a default function", { status: 500 });
15
37
  const query = buildPagesApiQuery(options.url, params);
16
38
  const { req, res, responsePromise } = createPagesReqRes({
17
39
  body: await parsePagesApiBody(options.request),
@@ -19,7 +41,7 @@ async function handlePagesApiRoute(options) {
19
41
  request: options.request,
20
42
  url: options.url
21
43
  });
22
- await handler(req, res);
44
+ await route.module.default(req, res);
23
45
  res.end();
24
46
  return await responsePromise;
25
47
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\n\ntype PagesApiRouteModule = {\n default?: (req: PagesReqResRequest, res: PagesReqResResponse) => void | Promise<void>;\n};\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n return mergeRouteParamsIntoQuery(parseQueryString(url), params);\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n const handler = route.module.default;\n if (typeof handler !== \"function\") {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n try {\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await handler(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;AA8BA,SAAS,mBAAmB,KAAa,QAA8C;CACrF,OAAO,0BAA0B,iBAAiB,IAAI,EAAE,OAAO;;AAGjE,eAAsB,oBAAoB,SAAwD;CAChG,IAAI,CAAC,QAAQ,OACX,OAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAClC,MAAM,UAAU,MAAM,OAAO;CAC7B,IAAI,OAAO,YAAY,YACrB,OAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;CAGtF,IAAI;EACF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAAA,MAFiB,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;EAEF,MAAM,QAAQ,KAAK,IAAI;EACvB,IAAI,KAAK;EACT,OAAO,MAAM;UACN,OAAO;EACd,IAAI,iBAAiBA,qBACnB,OAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;EAGJ,QAAa,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;EACD,OAAO,6BAA6B"}
1
+ {"version":3,"file":"pages-api-route.js","names":["PagesApiBodyParseError"],"sources":["../../src/server/pages-api-route.ts"],"sourcesContent":["import \"./server-globals.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { mergeRouteParamsIntoQuery, parseQueryString } from \"../utils/query.js\";\nimport {\n createPagesReqRes,\n parsePagesApiBody,\n type PagesRequestQuery,\n type PagesReqResRequest,\n type PagesReqResResponse,\n PagesApiBodyParseError,\n} from \"./pages-node-compat.js\";\nimport { internalServerErrorResponse } from \"./http-error-responses.js\";\nimport { isEdgeApiRuntime } from \"./edge-api-runtime.js\";\nimport { runWithExecutionContext, type ExecutionContextLike } from \"vinext/shims/request-context\";\nimport { NextRequest } from \"vinext/shims/server\";\n\ntype PagesApiRouteConfig = {\n runtime?: string;\n};\n\ntype PagesNodeApiRouteHandler = (\n req: PagesReqResRequest,\n res: PagesReqResResponse,\n) => void | Promise<void>;\n\ntype PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;\n\ntype PagesApiRouteModule = {\n /**\n * `export const config = { runtime: 'edge' }` — historical Pages Router form.\n */\n config?: PagesApiRouteConfig;\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 * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/build/analysis/get-page-static-info.ts\n */\n runtime?: string;\n default?: PagesNodeApiRouteHandler | PagesEdgeApiRouteHandler;\n};\n\nfunction resolveModuleRuntime(module: PagesApiRouteModule): string | undefined {\n return module.runtime ?? module.config?.runtime;\n}\n\nexport type PagesApiRouteMatch = {\n params: PagesRequestQuery;\n route: Pick<Route, \"pattern\"> & {\n module: PagesApiRouteModule;\n };\n};\n\ntype HandlePagesApiRouteOptions = {\n /**\n * Per-request Cloudflare Workers `ExecutionContext`. When provided, the\n * API route runs inside `runWithExecutionContext(ctx, ...)` so any\n * `after()` (or other shim) call inside the handler can reach\n * `ctx.waitUntil()` via the ALS and keep the isolate alive past the\n * response. Omit on Node.js dev where no Workers lifecycle exists.\n */\n ctx?: ExecutionContextLike;\n match: PagesApiRouteMatch | null;\n reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;\n request: Request;\n url: string;\n};\n\nfunction buildPagesApiQuery(url: string, params: PagesRequestQuery): PagesRequestQuery {\n return mergeRouteParamsIntoQuery(parseQueryString(url), params);\n}\n\nfunction isEdgeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesEdgeApiRouteHandler } {\n return typeof module.default === \"function\" && isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nfunction isNodeApiRouteModule(\n module: PagesApiRouteModule,\n): module is PagesApiRouteModule & { default: PagesNodeApiRouteHandler } {\n return typeof module.default === \"function\" && !isEdgeApiRuntime(resolveModuleRuntime(module));\n}\n\nexport async function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (options.ctx) {\n return runWithExecutionContext(options.ctx, () => _handlePagesApiRoute(options));\n }\n return _handlePagesApiRoute(options);\n}\n\nasync function _handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response> {\n if (!options.match) {\n return new Response(\"404 - API route not found\", { status: 404 });\n }\n\n const { route, params } = options.match;\n\n try {\n if (isEdgeApiRouteModule(route.module)) {\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(options.request);\n const response = await route.module.default(nextRequest);\n if (response instanceof Response) {\n return response;\n }\n\n throw new Error(\"Edge API route did not return a Response\");\n }\n\n // This is redundant at runtime after the edge branch for function exports, but it\n // keeps the Node handler ABI narrowed without a production type assertion.\n if (!isNodeApiRouteModule(route.module)) {\n return new Response(\"API route does not export a default function\", { status: 500 });\n }\n\n const query = buildPagesApiQuery(options.url, params);\n const body = await parsePagesApiBody(options.request);\n const { req, res, responsePromise } = createPagesReqRes({\n body,\n query,\n request: options.request,\n url: options.url,\n });\n\n await route.module.default(req, res);\n res.end();\n return await responsePromise;\n } catch (error) {\n if (error instanceof PagesApiBodyParseError) {\n return new Response(error.message, {\n status: error.statusCode,\n statusText: error.message,\n });\n }\n\n void options.reportRequestError?.(\n error instanceof Error ? error : new Error(String(error)),\n route.pattern,\n );\n return internalServerErrorResponse();\n }\n}\n"],"mappings":";;;;;;;;;AA2CA,SAAS,qBAAqB,QAAiD;CAC7E,OAAO,OAAO,WAAW,OAAO,QAAQ;;AAyB1C,SAAS,mBAAmB,KAAa,QAA8C;CACrF,OAAO,0BAA0B,iBAAiB,IAAI,EAAE,OAAO;;AAGjE,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,iBAAiB,qBAAqB,OAAO,CAAC;;AAG/F,SAAS,qBACP,QACuE;CACvE,OAAO,OAAO,OAAO,YAAY,cAAc,CAAC,iBAAiB,qBAAqB,OAAO,CAAC;;AAGhG,eAAsB,oBAAoB,SAAwD;CAChG,IAAI,QAAQ,KACV,OAAO,wBAAwB,QAAQ,WAAW,qBAAqB,QAAQ,CAAC;CAElF,OAAO,qBAAqB,QAAQ;;AAGtC,eAAe,qBAAqB,SAAwD;CAC1F,IAAI,CAAC,QAAQ,OACX,OAAO,IAAI,SAAS,6BAA6B,EAAE,QAAQ,KAAK,CAAC;CAGnE,MAAM,EAAE,OAAO,WAAW,QAAQ;CAElC,IAAI;EACF,IAAI,qBAAqB,MAAM,OAAO,EAAE;GAItC,MAAM,cAAc,IAAI,YAAY,QAAQ,QAAQ;GACpD,MAAM,WAAW,MAAM,MAAM,OAAO,QAAQ,YAAY;GACxD,IAAI,oBAAoB,UACtB,OAAO;GAGT,MAAM,IAAI,MAAM,2CAA2C;;EAK7D,IAAI,CAAC,qBAAqB,MAAM,OAAO,EACrC,OAAO,IAAI,SAAS,gDAAgD,EAAE,QAAQ,KAAK,CAAC;EAGtF,MAAM,QAAQ,mBAAmB,QAAQ,KAAK,OAAO;EAErD,MAAM,EAAE,KAAK,KAAK,oBAAoB,kBAAkB;GACtD,MAAA,MAFiB,kBAAkB,QAAQ,QAAQ;GAGnD;GACA,SAAS,QAAQ;GACjB,KAAK,QAAQ;GACd,CAAC;EAEF,MAAM,MAAM,OAAO,QAAQ,KAAK,IAAI;EACpC,IAAI,KAAK;EACT,OAAO,MAAM;UACN,OAAO;EACd,IAAI,iBAAiBA,qBACnB,OAAO,IAAI,SAAS,MAAM,SAAS;GACjC,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC;EAGJ,QAAa,qBACX,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,MAAM,QACP;EACD,OAAO,6BAA6B"}
@@ -0,0 +1,77 @@
1
+ //#region src/server/pages-data-route.d.ts
2
+ /**
3
+ * Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
4
+ *
5
+ * Next.js uses this endpoint for client-side navigations in the Pages Router:
6
+ * `next/link` and `router.push()` fetch `pageProps` from this URL instead of
7
+ * doing a full HTML navigation. The server must:
8
+ * 1. Match the URL pattern and extract the page pathname (with the buildId
9
+ * and `.json` extension removed, locale prefix preserved).
10
+ * 2. Normalize the URL BEFORE middleware runs so middleware sees the page
11
+ * path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.
12
+ * 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as
13
+ * the HTML page and serialize the resulting props as a JSON envelope:
14
+ * `{ pageProps: ... }` with `Content-Type: application/json`.
15
+ *
16
+ * Ported from Next.js:
17
+ * - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.
18
+ * - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.
19
+ * - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).
20
+ */
21
+ type NextDataMatch = {
22
+ /**
23
+ * The normalized page pathname (with leading slash, no trailing slash,
24
+ * `.json` stripped, buildId stripped). For locale-prefixed requests like
25
+ * `/_next/data/<buildId>/en/about.json` this is `/en/about` — locale
26
+ * handling is done downstream by the existing `resolvePagesI18nRequest`
27
+ * pipeline so this helper does not need to know about i18n config.
28
+ */
29
+ pagePathname: string;
30
+ };
31
+ /**
32
+ * Returns true if the pathname looks like a `_next/data` request, regardless
33
+ * of buildId. Used by the request pipeline to short-circuit before middleware
34
+ * even when the buildId is wrong (so we can still return a 404 JSON response).
35
+ */
36
+ declare function isNextDataPathname(pathname: string): boolean;
37
+ /**
38
+ * Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page
39
+ * pathname. Returns `null` if the pathname does not match the pattern or if
40
+ * the buildId segment does not match the server's buildId.
41
+ *
42
+ * The returned `pagePathname` is the page route path Next.js would render for
43
+ * the equivalent HTML navigation — including any locale prefix, which is then
44
+ * stripped by `resolvePagesI18nRequest` downstream.
45
+ *
46
+ * `/_next/data/<buildId>/about.json` → `/about`
47
+ * `/_next/data/<buildId>/en/about.json` → `/en/about`
48
+ * `/_next/data/<buildId>/index.json` → `/`
49
+ * `/_next/data/<buildId>/en.json` → `/en`
50
+ * `/_next/data/<wrong-id>/about.json` → null
51
+ * `/_next/data/<buildId>/about` → null (missing .json suffix)
52
+ */
53
+ declare function parseNextDataPathname(pathname: string, buildId: string): NextDataMatch | null;
54
+ /**
55
+ * Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.
56
+ * Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in
57
+ * `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).
58
+ *
59
+ * The envelope is the outer `props` object the React tree would receive:
60
+ * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
61
+ */
62
+ declare function buildNextDataJsonResponse(pageProps: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
63
+ /**
64
+ * Build the 404 response Next.js returns for an unknown `_next/data` page.
65
+ * Next.js renders this as a normal 404 page, but the body shape that clients
66
+ * see for a missing page-data endpoint is the literal string `"{ }"` for the
67
+ * body and a 404 status with `application/json` so client-side hard-navigation
68
+ * fallback fires (see `__N_SSP` handling in `router.ts`).
69
+ *
70
+ * We match Next.js' behavior: 404 status + JSON content type. The body is an
71
+ * empty JSON object so clients that blindly call `res.json()` do not throw
72
+ * before checking the status code.
73
+ */
74
+ declare function buildNextDataNotFoundResponse(): Response;
75
+ //#endregion
76
+ export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname };
77
+ //# sourceMappingURL=pages-data-route.d.ts.map
@@ -0,0 +1,97 @@
1
+ //#region src/server/pages-data-route.ts
2
+ /**
3
+ * Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
4
+ *
5
+ * Next.js uses this endpoint for client-side navigations in the Pages Router:
6
+ * `next/link` and `router.push()` fetch `pageProps` from this URL instead of
7
+ * doing a full HTML navigation. The server must:
8
+ * 1. Match the URL pattern and extract the page pathname (with the buildId
9
+ * and `.json` extension removed, locale prefix preserved).
10
+ * 2. Normalize the URL BEFORE middleware runs so middleware sees the page
11
+ * path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.
12
+ * 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as
13
+ * the HTML page and serialize the resulting props as a JSON envelope:
14
+ * `{ pageProps: ... }` with `Content-Type: application/json`.
15
+ *
16
+ * Ported from Next.js:
17
+ * - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.
18
+ * - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.
19
+ * - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).
20
+ */
21
+ const NEXT_DATA_PREFIX = "/_next/data/";
22
+ const NEXT_DATA_SUFFIX = ".json";
23
+ /**
24
+ * Returns true if the pathname looks like a `_next/data` request, regardless
25
+ * of buildId. Used by the request pipeline to short-circuit before middleware
26
+ * even when the buildId is wrong (so we can still return a 404 JSON response).
27
+ */
28
+ function isNextDataPathname(pathname) {
29
+ return pathname.startsWith(NEXT_DATA_PREFIX) && pathname.endsWith(NEXT_DATA_SUFFIX);
30
+ }
31
+ /**
32
+ * Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page
33
+ * pathname. Returns `null` if the pathname does not match the pattern or if
34
+ * the buildId segment does not match the server's buildId.
35
+ *
36
+ * The returned `pagePathname` is the page route path Next.js would render for
37
+ * the equivalent HTML navigation — including any locale prefix, which is then
38
+ * stripped by `resolvePagesI18nRequest` downstream.
39
+ *
40
+ * `/_next/data/<buildId>/about.json` → `/about`
41
+ * `/_next/data/<buildId>/en/about.json` → `/en/about`
42
+ * `/_next/data/<buildId>/index.json` → `/`
43
+ * `/_next/data/<buildId>/en.json` → `/en`
44
+ * `/_next/data/<wrong-id>/about.json` → null
45
+ * `/_next/data/<buildId>/about` → null (missing .json suffix)
46
+ */
47
+ function parseNextDataPathname(pathname, buildId) {
48
+ if (!buildId) return null;
49
+ if (!isNextDataPathname(pathname)) return null;
50
+ const expectedPrefix = `${NEXT_DATA_PREFIX}${buildId}/`;
51
+ if (!pathname.startsWith(expectedPrefix)) return null;
52
+ const rest = pathname.slice(expectedPrefix.length, -5);
53
+ if (rest.length === 0) return null;
54
+ if (rest === "index") return { pagePathname: "/" };
55
+ if (rest.endsWith("/index")) return { pagePathname: `/${rest.slice(0, -6)}` };
56
+ return { pagePathname: `/${rest}` };
57
+ }
58
+ /**
59
+ * Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.
60
+ * Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in
61
+ * `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).
62
+ *
63
+ * The envelope is the outer `props` object the React tree would receive:
64
+ * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
65
+ */
66
+ function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
67
+ const body = safeJsonStringify({ pageProps });
68
+ return new Response(body, {
69
+ status: init?.status ?? 200,
70
+ statusText: init?.statusText,
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ ...init?.headers
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * Build the 404 response Next.js returns for an unknown `_next/data` page.
79
+ * Next.js renders this as a normal 404 page, but the body shape that clients
80
+ * see for a missing page-data endpoint is the literal string `"{ }"` for the
81
+ * body and a 404 status with `application/json` so client-side hard-navigation
82
+ * fallback fires (see `__N_SSP` handling in `router.ts`).
83
+ *
84
+ * We match Next.js' behavior: 404 status + JSON content type. The body is an
85
+ * empty JSON object so clients that blindly call `res.json()` do not throw
86
+ * before checking the status code.
87
+ */
88
+ function buildNextDataNotFoundResponse() {
89
+ return new Response("{}", {
90
+ status: 404,
91
+ headers: { "Content-Type": "application/json" }
92
+ });
93
+ }
94
+ //#endregion
95
+ export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname };
96
+
97
+ //# sourceMappingURL=pages-data-route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages-data-route.js","names":[],"sources":["../../src/server/pages-data-route.ts"],"sourcesContent":["/**\n * Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.\n *\n * Next.js uses this endpoint for client-side navigations in the Pages Router:\n * `next/link` and `router.push()` fetch `pageProps` from this URL instead of\n * doing a full HTML navigation. The server must:\n * 1. Match the URL pattern and extract the page pathname (with the buildId\n * and `.json` extension removed, locale prefix preserved).\n * 2. Normalize the URL BEFORE middleware runs so middleware sees the page\n * path (e.g. `/about`) rather than the raw `/_next/data/.../about.json`.\n * 3. Invoke the same `getServerSideProps` / `getStaticProps` machinery as\n * the HTML page and serialize the resulting props as a JSON envelope:\n * `{ pageProps: ... }` with `Content-Type: application/json`.\n *\n * Ported from Next.js:\n * - `packages/next/src/server/normalizers/request/next-data.ts` — prefix/suffix matcher.\n * - `packages/next/src/server/base-server.ts` (`handleNextDataRequest`) — pipeline normalization.\n * - `packages/next/src/server/render.tsx` — JSON envelope emission (`isNextDataRequest`).\n */\n\nconst NEXT_DATA_PREFIX = \"/_next/data/\";\nconst NEXT_DATA_SUFFIX = \".json\";\n\ntype NextDataMatch = {\n /**\n * The normalized page pathname (with leading slash, no trailing slash,\n * `.json` stripped, buildId stripped). For locale-prefixed requests like\n * `/_next/data/<buildId>/en/about.json` this is `/en/about` — locale\n * handling is done downstream by the existing `resolvePagesI18nRequest`\n * pipeline so this helper does not need to know about i18n config.\n */\n pagePathname: string;\n};\n\n/**\n * Returns true if the pathname looks like a `_next/data` request, regardless\n * of buildId. Used by the request pipeline to short-circuit before middleware\n * even when the buildId is wrong (so we can still return a 404 JSON response).\n */\nexport function isNextDataPathname(pathname: string): boolean {\n return pathname.startsWith(NEXT_DATA_PREFIX) && pathname.endsWith(NEXT_DATA_SUFFIX);\n}\n\n/**\n * Parse `/_next/data/<buildId>/<...page>.json` and return the normalized page\n * pathname. Returns `null` if the pathname does not match the pattern or if\n * the buildId segment does not match the server's buildId.\n *\n * The returned `pagePathname` is the page route path Next.js would render for\n * the equivalent HTML navigation — including any locale prefix, which is then\n * stripped by `resolvePagesI18nRequest` downstream.\n *\n * `/_next/data/<buildId>/about.json` → `/about`\n * `/_next/data/<buildId>/en/about.json` → `/en/about`\n * `/_next/data/<buildId>/index.json` → `/`\n * `/_next/data/<buildId>/en.json` → `/en`\n * `/_next/data/<wrong-id>/about.json` → null\n * `/_next/data/<buildId>/about` → null (missing .json suffix)\n */\nexport function parseNextDataPathname(pathname: string, buildId: string): NextDataMatch | null {\n if (!buildId) return null;\n if (!isNextDataPathname(pathname)) return null;\n\n const expectedPrefix = `${NEXT_DATA_PREFIX}${buildId}/`;\n // `/_next/data/<buildId>.json` (no trailing slash) is not a valid data req.\n if (!pathname.startsWith(expectedPrefix)) return null;\n\n const rest = pathname.slice(expectedPrefix.length, -NEXT_DATA_SUFFIX.length);\n\n // Empty rest (`/_next/data/<buildId>/.json`) is not a valid page path.\n if (rest.length === 0) return null;\n\n // Next.js denormalizes `index` to `/` to mirror file-system page paths\n // (`pages/index.tsx` → `/`). See `denormalizePagePath` in Next.js.\n if (rest === \"index\") return { pagePathname: \"/\" };\n if (rest.endsWith(\"/index\")) return { pagePathname: `/${rest.slice(0, -\"/index\".length)}` };\n\n return { pagePathname: `/${rest}` };\n}\n\n/**\n * Build the JSON envelope returned by `/_next/data/<buildId>/<page>.json`.\n * Mirrors Next.js' `RenderResult(JSON.stringify(props))` path in\n * `packages/next/src/server/render.tsx` (search for `isNextDataRequest`).\n *\n * The envelope is the outer `props` object the React tree would receive:\n * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\\/ }\n */\nexport function buildNextDataJsonResponse(\n pageProps: Record<string, unknown>,\n safeJsonStringify: (value: unknown) => string,\n init?: ResponseInit,\n): Response {\n const body = safeJsonStringify({ pageProps });\n return new Response(body, {\n status: init?.status ?? 200,\n statusText: init?.statusText,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(init?.headers as Record<string, string> | undefined),\n },\n });\n}\n\n/**\n * Build the 404 response Next.js returns for an unknown `_next/data` page.\n * Next.js renders this as a normal 404 page, but the body shape that clients\n * see for a missing page-data endpoint is the literal string `\"{ }\"` for the\n * body and a 404 status with `application/json` so client-side hard-navigation\n * fallback fires (see `__N_SSP` handling in `router.ts`).\n *\n * We match Next.js' behavior: 404 status + JSON content type. The body is an\n * empty JSON object so clients that blindly call `res.json()` do not throw\n * before checking the status code.\n */\nexport function buildNextDataNotFoundResponse(): Response {\n return new Response(\"{}\", {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;;;;;;AAkBzB,SAAgB,mBAAmB,UAA2B;CAC5D,OAAO,SAAS,WAAW,iBAAiB,IAAI,SAAS,SAAS,iBAAiB;;;;;;;;;;;;;;;;;;AAmBrF,SAAgB,sBAAsB,UAAkB,SAAuC;CAC7F,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,CAAC,mBAAmB,SAAS,EAAE,OAAO;CAE1C,MAAM,iBAAiB,GAAG,mBAAmB,QAAQ;CAErD,IAAI,CAAC,SAAS,WAAW,eAAe,EAAE,OAAO;CAEjD,MAAM,OAAO,SAAS,MAAM,eAAe,QAAQ,GAAyB;CAG5E,IAAI,KAAK,WAAW,GAAG,OAAO;CAI9B,IAAI,SAAS,SAAS,OAAO,EAAE,cAAc,KAAK;CAClD,IAAI,KAAK,SAAS,SAAS,EAAE,OAAO,EAAE,cAAc,IAAI,KAAK,MAAM,GAAG,GAAiB,IAAI;CAE3F,OAAO,EAAE,cAAc,IAAI,QAAQ;;;;;;;;;;AAWrC,SAAgB,0BACd,WACA,mBACA,MACU;CACV,MAAM,OAAO,kBAAkB,EAAE,WAAW,CAAC;CAC7C,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ,MAAM,UAAU;EACxB,YAAY,MAAM;EAClB,SAAS;GACP,gBAAgB;GAChB,GAAI,MAAM;GACX;EACF,CAAC;;;;;;;;;;;;;AAcJ,SAAgB,gCAA0C;CACxD,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS,EAAE,gBAAgB,oBAAoB;EAChD,CAAC"}
@@ -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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"}