vinext 1.0.0-beta.0 → 1.0.0-beta.2

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 (305) hide show
  1. package/README.md +21 -2
  2. package/dist/build/assets-ignore.js +1 -1
  3. package/dist/build/clean-output.js +1 -1
  4. package/dist/build/client-build-config.js +7 -4
  5. package/dist/build/css-url-assets.js +3 -3
  6. package/dist/build/google-fonts/fallback-metrics.js +1 -1
  7. package/dist/build/google-fonts/font-metadata.js +1 -1
  8. package/dist/build/inject-pregenerated-paths.js +1 -1
  9. package/dist/build/inline-css.js +2 -5
  10. package/dist/build/module-dependency-cache.d.ts +4 -0
  11. package/dist/build/module-dependency-cache.js +13 -0
  12. package/dist/build/next-client-runtime-manifests.js +1 -1
  13. package/dist/build/pages-client-assets-module.js +1 -1
  14. package/dist/build/precompress.js +7 -7
  15. package/dist/build/prerender-paths.d.ts +2 -2
  16. package/dist/build/prerender-paths.js +10 -15
  17. package/dist/build/prerender-server-pool.js +2 -2
  18. package/dist/build/prerender.js +1 -1
  19. package/dist/build/preview-credentials.d.ts +11 -0
  20. package/dist/build/preview-credentials.js +19 -0
  21. package/dist/build/report.d.ts +8 -4
  22. package/dist/build/report.js +14 -6
  23. package/dist/build/run-prerender.d.ts +2 -11
  24. package/dist/build/run-prerender.js +2 -10
  25. package/dist/build/server-manifest.js +1 -1
  26. package/dist/build/ssr-manifest.d.ts +4 -0
  27. package/dist/build/ssr-manifest.js +10 -6
  28. package/dist/build/standalone.js +37 -37
  29. package/dist/cache/cache-adapters-virtual.d.ts +1 -17
  30. package/dist/cache/cache-adapters-virtual.js +20 -11
  31. package/dist/check.d.ts +0 -16
  32. package/dist/check.js +27 -36
  33. package/dist/cli.js +61 -55
  34. package/dist/client/instrumentation-client-inject.js +1 -1
  35. package/dist/client/pages-router-link-navigation.js +1 -1
  36. package/dist/config/config-matchers.d.ts +13 -37
  37. package/dist/config/config-matchers.js +33 -123
  38. package/dist/config/dotenv.js +1 -1
  39. package/dist/config/next-config.d.ts +7 -3
  40. package/dist/config/next-config.js +84 -15
  41. package/dist/config/prerender.d.ts +2 -2
  42. package/dist/config/prerender.js +7 -15
  43. package/dist/config/request-context.d.ts +14 -0
  44. package/dist/config/request-context.js +26 -0
  45. package/dist/config/server-external-packages.js +1 -1
  46. package/dist/config/tsconfig-paths.js +2 -2
  47. package/dist/{node_modules/.pnpm/am-i-vibing@0.5.0/node_modules → deps/.pnpm/am-i-vibing@0.5.0/deps}/am-i-vibing/dist/detector-1yx2Hoe0.js +2 -2
  48. package/dist/deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js +50 -0
  49. package/dist/entries/app-rsc-entry.js +39 -14
  50. package/dist/entries/app-rsc-manifest.js +21 -4
  51. package/dist/entries/pages-client-entry.js +6 -5
  52. package/dist/entries/pages-server-entry.js +18 -28
  53. package/dist/entries/runtime-entry-module.js +2 -2
  54. package/dist/index.js +314 -230
  55. package/dist/init-cloudflare.js +1 -1
  56. package/dist/init-platform.js +1 -1
  57. package/dist/init.d.ts +6 -4
  58. package/dist/init.js +25 -27
  59. package/dist/plugins/ast-utils.js +1 -1
  60. package/dist/plugins/dynamic-preload-metadata.js +7 -7
  61. package/dist/plugins/extensionless-dynamic-import.js +1 -1
  62. package/dist/plugins/fonts.js +3 -3
  63. package/dist/plugins/ignore-dynamic-requests.js +13 -8
  64. package/dist/plugins/import-meta-url.js +16 -17
  65. package/dist/plugins/middleware-export-validation.js +1 -1
  66. package/dist/plugins/middleware-server-only.js +2 -2
  67. package/dist/plugins/og-asset-ownership.js +7 -6
  68. package/dist/plugins/og-assets.js +5 -6
  69. package/dist/plugins/optimize-imports.js +12 -13
  70. package/dist/plugins/postcss.js +1 -1
  71. package/dist/plugins/remove-console.js +1 -1
  72. package/dist/plugins/require-context.js +1 -1
  73. package/dist/plugins/sass.js +2 -2
  74. package/dist/plugins/server-externals-manifest.js +1 -1
  75. package/dist/plugins/strip-server-exports.js +1 -1
  76. package/dist/plugins/styled-jsx.js +3 -2
  77. package/dist/plugins/typeof-window.js +1 -1
  78. package/dist/routing/app-route-graph.d.ts +16 -15
  79. package/dist/routing/app-route-graph.js +86 -88
  80. package/dist/routing/app-router.d.ts +0 -5
  81. package/dist/routing/app-router.js +12 -11
  82. package/dist/routing/file-matcher.d.ts +13 -28
  83. package/dist/routing/file-matcher.js +31 -44
  84. package/dist/routing/pages-router.js +26 -32
  85. package/dist/routing/route-matching.d.ts +14 -1
  86. package/dist/routing/route-matching.js +13 -1
  87. package/dist/routing/route-pattern.d.ts +2 -1
  88. package/dist/routing/route-pattern.js +7 -4
  89. package/dist/routing/route-trie.d.ts +5 -1
  90. package/dist/routing/route-trie.js +5 -2
  91. package/dist/server/api-handler.js +41 -33
  92. package/dist/server/app-browser-entry.js +18 -11
  93. package/dist/server/app-browser-history-controller.d.ts +1 -1
  94. package/dist/server/app-browser-history-controller.js +3 -3
  95. package/dist/server/app-browser-navigation-controller.js +4 -2
  96. package/dist/server/app-browser-server-action-client.js +1 -1
  97. package/dist/server/app-elements-wire.d.ts +2 -1
  98. package/dist/server/app-fallback-renderer.d.ts +11 -0
  99. package/dist/server/app-fallback-renderer.js +16 -2
  100. package/dist/server/app-middleware.js +2 -1
  101. package/dist/server/app-page-boundary-render.d.ts +26 -2
  102. package/dist/server/app-page-boundary-render.js +190 -55
  103. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  104. package/dist/server/app-page-cache.d.ts +1 -1
  105. package/dist/server/app-page-dispatch.d.ts +12 -2
  106. package/dist/server/app-page-dispatch.js +37 -51
  107. package/dist/server/app-page-element-builder.d.ts +8 -2
  108. package/dist/server/app-page-element-builder.js +112 -27
  109. package/dist/server/app-page-execution.d.ts +3 -1
  110. package/dist/server/app-page-execution.js +31 -39
  111. package/dist/server/app-page-head.d.ts +54 -2
  112. package/dist/server/app-page-head.js +164 -78
  113. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  114. package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
  115. package/dist/server/app-page-render.d.ts +2 -2
  116. package/dist/server/app-page-render.js +1 -1
  117. package/dist/server/app-page-request.d.ts +12 -0
  118. package/dist/server/app-page-request.js +134 -14
  119. package/dist/server/app-page-route-wiring.d.ts +9 -0
  120. package/dist/server/app-page-route-wiring.js +44 -4
  121. package/dist/server/app-post-middleware-context.d.ts +1 -1
  122. package/dist/server/app-post-middleware-context.js +1 -1
  123. package/dist/server/app-route-handler-dispatch.js +31 -17
  124. package/dist/server/app-route-handler-execution.d.ts +6 -1
  125. package/dist/server/app-route-handler-execution.js +41 -15
  126. package/dist/server/app-route-handler-policy.d.ts +2 -0
  127. package/dist/server/app-route-handler-policy.js +3 -3
  128. package/dist/server/app-route-module-loader.d.ts +3 -1
  129. package/dist/server/app-route-module-loader.js +1 -0
  130. package/dist/server/app-route-tree-prefetch.js +1 -1
  131. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  132. package/dist/server/app-rsc-cache-busting.js +1 -1
  133. package/dist/server/app-rsc-errors.d.ts +1 -1
  134. package/dist/server/app-rsc-errors.js +12 -2
  135. package/dist/server/app-rsc-handler.d.ts +10 -5
  136. package/dist/server/app-rsc-handler.js +51 -23
  137. package/dist/server/app-rsc-redirect-flight.d.ts +66 -0
  138. package/dist/server/app-rsc-redirect-flight.js +71 -0
  139. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  140. package/dist/server/app-rsc-request-normalization.js +8 -2
  141. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  142. package/dist/server/app-rsc-response-finalizer.js +5 -11
  143. package/dist/server/app-rsc-route-matching.d.ts +20 -0
  144. package/dist/server/app-rsc-route-matching.js +87 -11
  145. package/dist/server/app-segment-config.js +15 -5
  146. package/dist/server/app-server-action-execution.d.ts +3 -1
  147. package/dist/server/app-server-action-execution.js +8 -6
  148. package/dist/server/app-ssr-entry.js +4 -1
  149. package/dist/server/app-ssr-stream.d.ts +2 -7
  150. package/dist/server/app-ssr-stream.js +5 -10
  151. package/dist/server/cache-proof.js +1 -1
  152. package/dist/server/config-headers.d.ts +24 -0
  153. package/dist/server/config-headers.js +52 -0
  154. package/dist/server/default-global-error-module.d.ts +3 -1
  155. package/dist/server/default-not-found-module.d.ts +3 -1
  156. package/dist/server/dev-initial-server-error.d.ts +1 -1
  157. package/dist/server/dev-lockfile.js +2 -3
  158. package/dist/server/dev-route-files.js +1 -1
  159. package/dist/server/dev-server.js +281 -173
  160. package/dist/server/dev-stack-sourcemap.js +4 -3
  161. package/dist/server/headers.d.ts +3 -1
  162. package/dist/server/headers.js +3 -1
  163. package/dist/server/image-optimization.js +2 -2
  164. package/dist/server/implicit-tags.js +2 -1
  165. package/dist/server/instrumentation.js +2 -2
  166. package/dist/server/isr-cache.d.ts +1 -1
  167. package/dist/server/isr-cache.js +1 -1
  168. package/dist/server/metadata-routes.js +4 -4
  169. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  170. package/dist/server/middleware-matcher-pattern.js +219 -0
  171. package/dist/server/middleware-matcher.d.ts +2 -7
  172. package/dist/server/middleware-matcher.js +13 -60
  173. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  174. package/dist/server/middleware-path-to-regexp.js +228 -0
  175. package/dist/server/middleware-response-headers.js +1 -1
  176. package/dist/server/middleware-runtime.js +5 -4
  177. package/dist/server/middleware.d.ts +2 -1
  178. package/dist/server/middleware.js +3 -2
  179. package/dist/server/navigation-planner.d.ts +2 -0
  180. package/dist/server/navigation-planner.js +8 -2
  181. package/dist/server/next-error-digest.d.ts +9 -24
  182. package/dist/server/next-error-digest.js +23 -15
  183. package/dist/server/operation-token.js +1 -1
  184. package/dist/server/pages-body-parser-config.js +2 -1
  185. package/dist/server/pages-data-route.d.ts +11 -1
  186. package/dist/server/pages-data-route.js +16 -1
  187. package/dist/server/pages-dev-hydration.d.ts +14 -0
  188. package/dist/server/pages-dev-hydration.js +83 -0
  189. package/dist/server/pages-dev-module-url.js +2 -2
  190. package/dist/server/pages-get-initial-props.d.ts +15 -2
  191. package/dist/server/pages-get-initial-props.js +16 -6
  192. package/dist/server/pages-node-compat.d.ts +13 -6
  193. package/dist/server/pages-node-compat.js +44 -45
  194. package/dist/server/pages-page-data.d.ts +4 -2
  195. package/dist/server/pages-page-data.js +20 -10
  196. package/dist/server/pages-page-handler.d.ts +4 -2
  197. package/dist/server/pages-page-handler.js +74 -43
  198. package/dist/server/pages-page-response.d.ts +2 -2
  199. package/dist/server/pages-page-response.js +1 -1
  200. package/dist/server/pages-preview.d.ts +26 -0
  201. package/dist/server/pages-preview.js +165 -0
  202. package/dist/server/pages-readiness.d.ts +5 -4
  203. package/dist/server/pages-readiness.js +4 -2
  204. package/dist/server/pages-request-pipeline.d.ts +1 -0
  205. package/dist/server/pages-request-pipeline.js +25 -11
  206. package/dist/server/pages-router-entry.js +6 -0
  207. package/dist/server/prerender-route-params.js +2 -2
  208. package/dist/server/prod-server.d.ts +1 -4
  209. package/dist/server/prod-server.js +44 -30
  210. package/dist/server/request-pipeline.d.ts +15 -29
  211. package/dist/server/request-pipeline.js +25 -60
  212. package/dist/server/rsc-stream-hints.js +122 -18
  213. package/dist/server/seed-cache.js +1 -1
  214. package/dist/server/socket-error-backstop.js +1 -1
  215. package/dist/server/static-file-cache.js +7 -8
  216. package/dist/server/worker-utils.js +1 -1
  217. package/dist/shims/app.d.ts +1 -1
  218. package/dist/shims/cache-request-state.d.ts +27 -1
  219. package/dist/shims/cache-request-state.js +60 -1
  220. package/dist/shims/cache-runtime.d.ts +12 -1
  221. package/dist/shims/cache-runtime.js +22 -7
  222. package/dist/shims/cache.d.ts +5 -5
  223. package/dist/shims/cache.js +28 -11
  224. package/dist/shims/constants.js +1 -1
  225. package/dist/shims/document.d.ts +42 -83
  226. package/dist/shims/document.js +62 -53
  227. package/dist/shims/dynamic.d.ts +5 -25
  228. package/dist/shims/dynamic.js +29 -8
  229. package/dist/shims/error-boundary.d.ts +4 -4
  230. package/dist/shims/error.d.ts +22 -6
  231. package/dist/shims/error.js +53 -15
  232. package/dist/shims/fetch-cache.js +13 -4
  233. package/dist/shims/font-google-base.d.ts +11 -4
  234. package/dist/shims/font-local.d.ts +10 -3
  235. package/dist/shims/font-utils.js +1 -1
  236. package/dist/shims/form.d.ts +1 -1
  237. package/dist/shims/head.d.ts +13 -2
  238. package/dist/shims/head.js +6 -6
  239. package/dist/shims/headers.d.ts +28 -31
  240. package/dist/shims/headers.js +115 -53
  241. package/dist/shims/image.d.ts +27 -37
  242. package/dist/shims/image.js +21 -14
  243. package/dist/shims/internal/cookie-serialize.d.ts +3 -1
  244. package/dist/shims/internal/cookie-serialize.js +3 -1
  245. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  246. package/dist/shims/internal/pages-data-fetch-dedup.js +5 -3
  247. package/dist/shims/internal/utils.d.ts +3 -3
  248. package/dist/shims/layout-segment-context.d.ts +1 -1
  249. package/dist/shims/legacy-image.d.ts +3 -37
  250. package/dist/shims/legacy-image.js +6 -16
  251. package/dist/shims/link.d.ts +16 -21
  252. package/dist/shims/link.js +25 -13
  253. package/dist/shims/navigation-context-state.d.ts +1 -1
  254. package/dist/shims/navigation-errors.d.ts +2 -1
  255. package/dist/shims/navigation-errors.js +9 -13
  256. package/dist/shims/navigation.d.ts +8 -4
  257. package/dist/shims/navigation.js +29 -18
  258. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  259. package/dist/shims/next-shims-public.d.ts +1 -0
  260. package/dist/shims/public-shim-map.json.js +103 -0
  261. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  262. package/dist/shims/readonly-url-search-params.js +3 -3
  263. package/dist/shims/request-state-types.d.ts +1 -1
  264. package/dist/shims/router-state.d.ts +1 -0
  265. package/dist/shims/router.d.ts +57 -22
  266. package/dist/shims/router.js +178 -46
  267. package/dist/shims/script.d.ts +6 -10
  268. package/dist/shims/script.js +7 -4
  269. package/dist/shims/server.d.ts +45 -22
  270. package/dist/shims/server.js +46 -7
  271. package/dist/shims/slot.d.ts +1 -1
  272. package/dist/shims/thenable-params.js +1 -1
  273. package/dist/shims/unified-request-context.d.ts +1 -1
  274. package/dist/shims/unified-request-context.js +2 -0
  275. package/dist/shims/url-safety.d.ts +1 -1
  276. package/dist/shims/url-safety.js +2 -2
  277. package/dist/typegen.d.ts +8 -2
  278. package/dist/typegen.js +84 -25
  279. package/dist/utils/client-build-manifest.js +2 -2
  280. package/dist/utils/client-entry-manifest.js +1 -1
  281. package/dist/utils/client-runtime-metadata.js +1 -1
  282. package/dist/utils/commonjs-loader.js +3 -3
  283. package/dist/utils/domain-locale.d.ts +2 -2
  284. package/dist/utils/external-url.d.ts +5 -0
  285. package/dist/utils/external-url.js +7 -0
  286. package/dist/utils/mdx-scan.js +1 -1
  287. package/dist/utils/path.d.ts +1 -13
  288. package/dist/utils/path.js +1 -15
  289. package/dist/utils/plugin-options.d.ts +4 -0
  290. package/dist/utils/plugin-options.js +8 -0
  291. package/dist/utils/project.d.ts +0 -6
  292. package/dist/utils/project.js +2 -8
  293. package/dist/utils/public-routes.js +2 -2
  294. package/dist/utils/react-version.js +1 -1
  295. package/dist/utils/redirect-digest.d.ts +9 -0
  296. package/dist/utils/redirect-digest.js +25 -0
  297. package/dist/utils/regex-safety.d.ts +8 -0
  298. package/dist/utils/regex-safety.js +737 -0
  299. package/dist/utils/vinext-root.js +1 -1
  300. package/dist/utils/vite-version.d.ts +5 -2
  301. package/dist/utils/vite-version.js +43 -17
  302. package/package.json +16 -4
  303. /package/dist/build/google-fonts/{fallback-metrics-data.js → fallback-metrics-data.json.js} +0 -0
  304. /package/dist/build/google-fonts/{font-data.js → font-data.json.js} +0 -0
  305. /package/dist/{node_modules/.pnpm/process-ancestry@0.1.0/node_modules → deps/.pnpm/process-ancestry@0.1.0/deps}/process-ancestry/dist/index.js +0 -0
@@ -2,7 +2,7 @@ import { stripBasePath } from "../utils/base-path.js";
2
2
  import { getLocalePathPrefix } from "../utils/domain-locale.js";
3
3
  //#region src/client/pages-router-link-navigation.ts
4
4
  function resolvePagesRouterQueryOnlyHref(href, { asPath, basePath, fallbackHref, locales }) {
5
- if (!href.startsWith("?")) return href;
5
+ if (!href.startsWith("?") && !href.startsWith("#")) return href;
6
6
  try {
7
7
  const fallbackUrl = new URL(fallbackHref);
8
8
  const base = new URL(asPath ?? `${stripBasePath(fallbackUrl.pathname, basePath)}${fallbackUrl.search}${fallbackUrl.hash}`, "http://vinext.local");
@@ -1,17 +1,20 @@
1
1
  import { HasCondition, NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "./next-config.js";
2
+ import { RequestContext, normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
3
+ import { isExternalUrl } from "../utils/external-url.js";
2
4
 
3
5
  //#region src/config/config-matchers.d.ts
4
6
  /**
5
7
  * Detect regex patterns vulnerable to catastrophic backtracking (ReDoS).
6
8
  *
7
- * Uses a lightweight heuristic: scans the pattern string for nested quantifiers
8
- * (a quantifier applied to a group that itself contains a quantifier). This
9
- * catches the most common pathological patterns like `(a+)+`, `(.*)*`,
10
- * `([^/]+)+`, `(a|a+)+` without needing a full regex parser.
9
+ * Uses the same deterministic structural analysis as middleware matcher
10
+ * validation. Nested bounded repetition is accepted only when its repeated
11
+ * language has fixed width and unambiguous branches; a fixed outer count can
12
+ * otherwise still cause polynomially catastrophic backtracking on long near
13
+ * misses.
11
14
  *
12
15
  * Returns true if the pattern appears safe, false if it's potentially dangerous.
13
16
  */
14
- declare function isSafeRegex(pattern: string): boolean;
17
+ declare function isSafeRegex(pattern: string, flags?: string): boolean;
15
18
  /**
16
19
  * Compile a regex pattern safely. Returns the compiled RegExp or null if the
17
20
  * pattern is invalid or vulnerable to ReDoS.
@@ -27,16 +30,6 @@ declare function safeRegExp(pattern: string, flags?: string): RegExp | null;
27
30
  * which CodeQL flags as incomplete sanitization), then groups are restored.
28
31
  */
29
32
  declare function escapeHeaderSource(source: string): string;
30
- /**
31
- * Request context needed for evaluating has/missing conditions.
32
- * Callers extract the relevant parts from the incoming Request.
33
- */
34
- type RequestContext = {
35
- readonly headers: Headers;
36
- readonly cookies: Record<string, string>;
37
- readonly query: URLSearchParams;
38
- readonly host: string;
39
- };
40
33
  /**
41
34
  * basePath gating state passed alongside the pathname to every matcher.
42
35
  *
@@ -59,22 +52,6 @@ type BasePathMatchState = {
59
52
  */
60
53
  hadBasePath: boolean;
61
54
  };
62
- /**
63
- * Parse a Cookie header string into a key-value record.
64
- */
65
- declare function parseCookies(cookieHeader: string | null): Record<string, string>;
66
- /**
67
- * Build a RequestContext from a Web Request object.
68
- *
69
- * `cookies` and `query` are lazy memoized getters: they are consumed only by
70
- * `has`/`missing` condition evaluation (`checkHasConditions` /
71
- * `matchesRuleConditions`), and most apps configure no such conditions. The
72
- * cookie split and `searchParams` access are therefore deferred until first
73
- * read and computed at most once. Mirrors `headersContextFromRequest` in
74
- * `shims/headers.ts`.
75
- */
76
- declare function requestContextFromRequest(request: Request): RequestContext;
77
- declare function normalizeHost(hostHeader: string | null, fallbackHostname: string): string;
78
55
  /**
79
56
  * Unpack `x-middleware-request-*` headers from the collected middleware
80
57
  * response headers into the actual request, and strip all `x-middleware-*`
@@ -147,7 +124,7 @@ declare function matchRedirect(pathname: string, redirects: NextRedirect[], ctx:
147
124
  * to evaluate has/missing conditions. Next.js always has request context
148
125
  * when evaluating rewrites, so this parameter is required.
149
126
  */
150
- declare function matchRewrite(pathname: string, rewrites: NextRewrite[], ctx: RequestContext, basePathState?: BasePathMatchState): string | null;
127
+ declare function matchRewrite(pathname: string, rewrites: NextRewrite[], ctx: RequestContext, basePathState?: BasePathMatchState, paramsPathname?: string): string | null;
151
128
  /**
152
129
  * Check whether a rewrite source can match a pathname without evaluating its
153
130
  * request-dependent `has` / `missing` conditions.
@@ -175,7 +152,6 @@ declare function sanitizeDestination(dest: string): string;
175
152
  * Detects any URL scheme (http:, https:, data:, javascript:, blob:, etc.)
176
153
  * per RFC 3986, plus protocol-relative URLs (//).
177
154
  */
178
- declare function isExternalUrl(url: string): boolean;
179
155
  /**
180
156
  * Merge the original request's query params into a config-redirect
181
157
  * destination, preserving them on the resulting `Location`.
@@ -218,8 +194,8 @@ declare function matchHeaders(pathname: string, headers: NextHeader[], ctx: Requ
218
194
  value: string;
219
195
  }>;
220
196
  /**
221
- * Apply Next.js i18n locale-prefix transformation to a set of redirect or
222
- * rewrite rules. Mirrors the relevant slice of Next.js's `processRoutes`
197
+ * Apply Next.js i18n locale-prefix transformation to a set of redirect,
198
+ * rewrite, or header rules. Mirrors the relevant slice of Next.js's `processRoutes`
223
199
  * (load-custom-routes.ts) with one deliberate divergence noted below.
224
200
  *
225
201
  * For each rule:
@@ -250,8 +226,8 @@ declare function matchHeaders(pathname: string, headers: NextHeader[], ctx: Requ
250
226
  * Mirrors the Next.js reference in
251
227
  * packages/next/src/lib/load-custom-routes.ts — see `processRoutes`.
252
228
  */
253
- declare function applyLocaleToRoutes<T extends NextRedirect | NextRewrite>(routes: T[], i18n: NextI18nConfig | null | undefined, type: "redirect" | "rewrite", options?: {
229
+ declare function applyLocaleToRoutes<T extends NextRedirect | NextRewrite | NextHeader>(routes: T[], i18n: NextI18nConfig | null | undefined, type: "redirect" | "rewrite" | "header", options?: {
254
230
  trailingSlash?: boolean;
255
231
  }): T[];
256
232
  //#endregion
257
- export { BasePathMatchState, RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, matchesRewriteSource, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
233
+ export { BasePathMatchState, type RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, matchesRewriteSource, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
@@ -1,6 +1,8 @@
1
1
  import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../utils/protocol-headers.js";
2
2
  import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
3
- import { parseCookieHeader } from "../utils/parse-cookie.js";
3
+ import { analyzeRegexSafety } from "../utils/regex-safety.js";
4
+ import { normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
5
+ import { isExternalUrl } from "../utils/external-url.js";
4
6
  //#region src/config/config-matchers.ts
5
7
  /**
6
8
  * Cache for compiled regex patterns in matchConfigPattern.
@@ -159,7 +161,7 @@ function _getRedirectIndex(redirects) {
159
161
  return index;
160
162
  }
161
163
  /** Hop-by-hop headers that should not be forwarded through a proxy. */
162
- const HOP_BY_HOP_HEADERS = new Set([
164
+ const HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
163
165
  "connection",
164
166
  "keep-alive",
165
167
  "proxy-authenticate",
@@ -175,7 +177,7 @@ const HOP_BY_HOP_HEADERS = new Set([
175
177
  * still forwards proxy auth credentials, while response sanitization strips
176
178
  * them before returning data to the client.
177
179
  */
178
- const REQUEST_HOP_BY_HOP_HEADERS = new Set([
180
+ const REQUEST_HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
179
181
  "connection",
180
182
  "keep-alive",
181
183
  "te",
@@ -191,75 +193,16 @@ function stripHopByHopRequestHeaders(headers) {
191
193
  /**
192
194
  * Detect regex patterns vulnerable to catastrophic backtracking (ReDoS).
193
195
  *
194
- * Uses a lightweight heuristic: scans the pattern string for nested quantifiers
195
- * (a quantifier applied to a group that itself contains a quantifier). This
196
- * catches the most common pathological patterns like `(a+)+`, `(.*)*`,
197
- * `([^/]+)+`, `(a|a+)+` without needing a full regex parser.
196
+ * Uses the same deterministic structural analysis as middleware matcher
197
+ * validation. Nested bounded repetition is accepted only when its repeated
198
+ * language has fixed width and unambiguous branches; a fixed outer count can
199
+ * otherwise still cause polynomially catastrophic backtracking on long near
200
+ * misses.
198
201
  *
199
202
  * Returns true if the pattern appears safe, false if it's potentially dangerous.
200
203
  */
201
- function isSafeRegex(pattern) {
202
- const quantifierAtDepth = [];
203
- let depth = 0;
204
- let i = 0;
205
- while (i < pattern.length) {
206
- const ch = pattern[i];
207
- if (ch === "\\") {
208
- i += 2;
209
- continue;
210
- }
211
- if (ch === "[") {
212
- i++;
213
- while (i < pattern.length && pattern[i] !== "]") {
214
- if (pattern[i] === "\\") i++;
215
- i++;
216
- }
217
- i++;
218
- continue;
219
- }
220
- if (ch === "(") {
221
- depth++;
222
- if (quantifierAtDepth.length <= depth) quantifierAtDepth.push(false);
223
- else quantifierAtDepth[depth] = false;
224
- i++;
225
- continue;
226
- }
227
- if (ch === ")") {
228
- const hadQuantifier = depth > 0 && quantifierAtDepth[depth];
229
- if (depth > 0) depth--;
230
- const next = pattern[i + 1];
231
- if (next === "+" || next === "*" || next === "{") {
232
- if (hadQuantifier) return false;
233
- if (depth >= 0 && depth < quantifierAtDepth.length) quantifierAtDepth[depth] = true;
234
- }
235
- i++;
236
- continue;
237
- }
238
- if (ch === "+" || ch === "*") {
239
- if (depth > 0) quantifierAtDepth[depth] = true;
240
- i++;
241
- continue;
242
- }
243
- if (ch === "?") {
244
- const prev = i > 0 ? pattern[i - 1] : "";
245
- if (prev !== "+" && prev !== "*" && prev !== "?" && prev !== "}") {
246
- if (depth > 0) quantifierAtDepth[depth] = true;
247
- }
248
- i++;
249
- continue;
250
- }
251
- if (ch === "{") {
252
- let j = i + 1;
253
- while (j < pattern.length && /[\d,]/.test(pattern[j])) j++;
254
- if (j < pattern.length && pattern[j] === "}" && j > i + 1) {
255
- if (depth > 0) quantifierAtDepth[depth] = true;
256
- i = j + 1;
257
- continue;
258
- }
259
- }
260
- i++;
261
- }
262
- return true;
204
+ function isSafeRegex(pattern, flags) {
205
+ return analyzeRegexSafety(pattern, { ignoreCase: flags?.includes("i") }) === null;
263
206
  }
264
207
  /**
265
208
  * Compile a regex pattern safely. Returns the compiled RegExp or null if the
@@ -268,8 +211,8 @@ function isSafeRegex(pattern) {
268
211
  * Logs a warning when a pattern is rejected so developers can fix their config.
269
212
  */
270
213
  function safeRegExp(pattern, flags) {
271
- if (!isSafeRegex(pattern)) {
272
- console.warn(`[vinext] Rejecting potentially unsafe regex pattern (ReDoS risk): ${pattern}\n Patterns with nested quantifiers (e.g. (a+)+) can cause catastrophic backtracking.\n Simplify the pattern to avoid nested repetition.`);
214
+ if (!isSafeRegex(pattern, flags)) {
215
+ console.warn(`[vinext] Rejecting potentially unsafe regex pattern (ReDoS risk): ${pattern}\n Nested or ambiguous repetition can cause catastrophic backtracking.\n Simplify the pattern to make repeated matches fixed and unambiguous.`);
273
216
  return null;
274
217
  }
275
218
  try {
@@ -342,40 +285,6 @@ function shouldEvaluateRule(ruleBasePath, state) {
342
285
  return ruleBasePath === false ? !state.hadBasePath : state.hadBasePath;
343
286
  }
344
287
  /**
345
- * Parse a Cookie header string into a key-value record.
346
- */
347
- function parseCookies(cookieHeader) {
348
- return parseCookieHeader(cookieHeader);
349
- }
350
- /**
351
- * Build a RequestContext from a Web Request object.
352
- *
353
- * `cookies` and `query` are lazy memoized getters: they are consumed only by
354
- * `has`/`missing` condition evaluation (`checkHasConditions` /
355
- * `matchesRuleConditions`), and most apps configure no such conditions. The
356
- * cookie split and `searchParams` access are therefore deferred until first
357
- * read and computed at most once. Mirrors `headersContextFromRequest` in
358
- * `shims/headers.ts`.
359
- */
360
- function requestContextFromRequest(request) {
361
- const url = new URL(request.url);
362
- let cookies;
363
- let query;
364
- return {
365
- headers: request.headers,
366
- get cookies() {
367
- return cookies ??= parseCookies(request.headers.get("cookie"));
368
- },
369
- get query() {
370
- return query ??= url.searchParams;
371
- },
372
- host: normalizeHost(request.headers.get("host"), url.hostname)
373
- };
374
- }
375
- function normalizeHost(hostHeader, fallbackHostname) {
376
- return (hostHeader ?? fallbackHostname).split(":", 1)[0].toLowerCase();
377
- }
378
- /**
379
288
  * Unpack `x-middleware-request-*` headers from the collected middleware
380
289
  * response headers into the actual request, and strip all `x-middleware-*`
381
290
  * internal signals so they never reach clients.
@@ -410,7 +319,7 @@ function _emptyParams() {
410
319
  return Object.create(null);
411
320
  }
412
321
  function _matchConditionValue(actualValue, expectedValue) {
413
- if (expectedValue === void 0) return _emptyParams();
322
+ if (!expectedValue) return actualValue ? _emptyParams() : null;
414
323
  const re = _cachedConditionRegex(expectedValue);
415
324
  if (re) {
416
325
  const match = re.exec(actualValue);
@@ -440,9 +349,10 @@ function matchSingleCondition(condition, ctx) {
440
349
  return _matchConditionValue(cookieValue, condition.value);
441
350
  }
442
351
  case "query": {
443
- const queryValue = ctx.query.get(condition.key);
444
- if (queryValue === null) return null;
445
- return _matchConditionValue(queryValue, condition.value);
352
+ const queryValues = ctx.query.getAll(condition.key);
353
+ if (queryValues.length === 0) return null;
354
+ if (!condition.value && queryValues.length > 1) return _emptyParams();
355
+ return _matchConditionValue(queryValues[queryValues.length - 1], condition.value);
446
356
  }
447
357
  case "host":
448
358
  if (condition.value !== void 0) return _matchConditionValue(ctx.host, condition.value);
@@ -710,11 +620,12 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
710
620
  * to evaluate has/missing conditions. Next.js always has request context
711
621
  * when evaluating rewrites, so this parameter is required.
712
622
  */
713
- function matchRewrite(pathname, rewrites, ctx, basePathState = _BASEPATH_DEFAULT) {
623
+ function matchRewrite(pathname, rewrites, ctx, basePathState = _BASEPATH_DEFAULT, paramsPathname = pathname) {
714
624
  for (const rewrite of rewrites) {
715
625
  if (!shouldEvaluateRule(rewrite.basePath, basePathState)) continue;
716
- const params = matchConfigPattern(pathname, rewrite.source);
717
- if (params) {
626
+ const matchedParams = matchConfigPattern(pathname, rewrite.source);
627
+ if (matchedParams) {
628
+ const params = paramsPathname === pathname ? matchedParams : matchConfigPattern(paramsPathname, rewrite.source) ?? matchedParams;
718
629
  const conditionParams = rewrite.has || rewrite.missing ? collectConditionParams(rewrite.has, rewrite.missing, ctx) : _emptyParams();
719
630
  if (!conditionParams) continue;
720
631
  const rewriteParams = {
@@ -868,9 +779,6 @@ function sanitizeDestination(dest) {
868
779
  * Detects any URL scheme (http:, https:, data:, javascript:, blob:, etc.)
869
780
  * per RFC 3986, plus protocol-relative URLs (//).
870
781
  */
871
- function isExternalUrl(url) {
872
- return /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith("//");
873
- }
874
782
  /**
875
783
  * Merge the original request's query params into a config-redirect
876
784
  * destination, preserving them on the resulting `Location`.
@@ -1004,8 +912,8 @@ function _escapeRegexString(value) {
1004
912
  return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
1005
913
  }
1006
914
  /**
1007
- * Apply Next.js i18n locale-prefix transformation to a set of redirect or
1008
- * rewrite rules. Mirrors the relevant slice of Next.js's `processRoutes`
915
+ * Apply Next.js i18n locale-prefix transformation to a set of redirect,
916
+ * rewrite, or header rules. Mirrors the relevant slice of Next.js's `processRoutes`
1009
917
  * (load-custom-routes.ts) with one deliberate divergence noted below.
1010
918
  *
1011
919
  * For each rule:
@@ -1048,7 +956,8 @@ function applyLocaleToRoutes(routes, i18n, type, options = {}) {
1048
956
  out.push(r);
1049
957
  continue;
1050
958
  }
1051
- const isExternal = !!r.destination && !r.destination.startsWith("/");
959
+ const destination = "destination" in r ? r.destination : void 0;
960
+ const isExternal = !!destination && !destination.startsWith("/");
1052
961
  if (!isExternal) for (const locale of defaultLocales) {
1053
962
  const localizedSource = `/${locale}${suffixFor(r.source)}`;
1054
963
  out.push({
@@ -1057,13 +966,14 @@ function applyLocaleToRoutes(routes, i18n, type, options = {}) {
1057
966
  });
1058
967
  }
1059
968
  const internalSource = `${internalLocale}${suffixFor(r.source)}`;
1060
- let internalDestination = r.destination;
969
+ let internalDestination = destination;
1061
970
  if (internalDestination && internalDestination.startsWith("/") && !isExternal) internalDestination = `/:nextInternalLocale${internalDestination === "/" && !trailingSlash ? "" : internalDestination}`;
1062
- out.push({
971
+ const internalRoute = {
1063
972
  ...r,
1064
- source: internalSource,
1065
- destination: internalDestination
1066
- });
973
+ source: internalSource
974
+ };
975
+ if ("destination" in internalRoute && internalDestination !== void 0) internalRoute.destination = internalDestination;
976
+ out.push(internalRoute);
1067
977
  out.push(r);
1068
978
  }
1069
979
  return out;
@@ -1,5 +1,5 @@
1
+ import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
1
2
  import fs from "node:fs";
2
- import path from "node:path";
3
3
  import { parseEnv } from "node:util";
4
4
  //#region src/config/dotenv.ts
5
5
  /**
@@ -1,6 +1,8 @@
1
1
  import { PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
2
+ import { PluginOption } from "vite";
2
3
 
3
4
  //#region src/config/next-config.d.ts
5
+ declare const VINEXT_NEXT_CONFIG_PLUGIN_PROPERTY = "__vinextNextConfig";
4
6
  /**
5
7
  * Parse a body size limit value (string or number) into bytes.
6
8
  * Accepts Next.js-style strings like "1mb", "500kb", "10mb", bare number strings like "1048576" (bytes),
@@ -52,7 +54,8 @@ type NextHeader = {
52
54
  key: string;
53
55
  value: string;
54
56
  }>; /** See {@link NextRedirect.basePath}. */
55
- basePath?: false;
57
+ basePath?: false; /** See {@link NextRedirect.locale}. */
58
+ locale?: false;
56
59
  };
57
60
  type NextI18nConfig = {
58
61
  /** List of supported locales */locales: string[]; /** The default locale (used when no locale prefix is in the URL) */
@@ -69,7 +72,7 @@ type NextI18nConfig = {
69
72
  domain: string;
70
73
  defaultLocale: string;
71
74
  locales?: string[];
72
- http?: boolean;
75
+ http?: true;
73
76
  }>;
74
77
  };
75
78
  /**
@@ -241,6 +244,7 @@ type NextConfigFactory = (phase: string, opts: {
241
244
  defaultConfig: NextConfig;
242
245
  }) => NextConfig | Promise<NextConfig>;
243
246
  type NextConfigInput = NextConfig | NextConfigFactory;
247
+ declare function findVinextNextConfigInPlugins(plugins: PluginOption[] | undefined): Promise<NextConfigInput | null>;
244
248
  /**
245
249
  * Resolved configuration with all async values awaited.
246
250
  */
@@ -564,4 +568,4 @@ declare function extractMdxOptions(config: NextConfig, root?: string): Promise<M
564
568
  */
565
569
  declare function detectNextIntlConfig(root: string, resolved: ResolvedNextConfig): void;
566
570
  //#endregion
567
- export { HasCondition, MdxOptions, NextConfig, NextConfigInput, NextHeader, NextI18nConfig, NextRedirect, NextRewrite, PHASE_PRODUCTION_BUILD, PrefetchInliningConfig, ResolvedNextConfig, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
571
+ export { HasCondition, MdxOptions, NextConfig, NextConfigInput, NextHeader, NextI18nConfig, NextRedirect, NextRewrite, PHASE_PRODUCTION_BUILD, PrefetchInliningConfig, ResolvedNextConfig, VINEXT_NEXT_CONFIG_PLUGIN_PROPERTY, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, findVinextNextConfigInPlugins, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
@@ -1,13 +1,15 @@
1
+ import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
1
2
  import { normalizePageExtensions } from "../routing/file-matcher.js";
2
- import { applyLocaleToRoutes, isExternalUrl } from "./config-matchers.js";
3
+ import { isExternalUrl } from "../utils/external-url.js";
4
+ import { applyLocaleToRoutes } from "./config-matchers.js";
3
5
  import { isUnknownRecord } from "../utils/record.js";
4
6
  import { getHtmlLimitedBotRegex } from "../utils/html-limited-bots.js";
7
+ import { flattenPluginOptions } from "../utils/plugin-options.js";
5
8
  import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
6
9
  import { loadTsconfigResolutionForRoot } from "./tsconfig-paths.js";
7
10
  import { loadCommonJsModule, shouldRetryAsCommonJs } from "../utils/commonjs-loader.js";
8
11
  import { createRequire } from "node:module";
9
12
  import fs from "node:fs";
10
- import path from "node:path";
11
13
  import { fileURLToPath } from "node:url";
12
14
  import { randomUUID } from "node:crypto";
13
15
  import commonjs from "vite-plugin-commonjs";
@@ -18,6 +20,7 @@ import commonjs from "vite-plugin-commonjs";
18
20
  * Loads the Next.js config file (if present) and extracts supported options.
19
21
  * Unsupported options are logged as warnings.
20
22
  */
23
+ const VINEXT_NEXT_CONFIG_PLUGIN_PROPERTY = "__vinextNextConfig";
21
24
  /**
22
25
  * Parse a body size limit value (string or number) into bytes.
23
26
  * Accepts Next.js-style strings like "1mb", "500kb", "10mb", bare number strings like "1048576" (bytes),
@@ -63,6 +66,15 @@ function parseBodySizeLimit(value) {
63
66
  if (bytes < 1) throw new Error(`Body size limit must be a positive number, got ${bytes}`);
64
67
  return bytes;
65
68
  }
69
+ async function findVinextNextConfigInPlugins(plugins) {
70
+ const flattened = await flattenPluginOptions(plugins);
71
+ for (const plugin of flattened) {
72
+ if (!isUnknownRecord(plugin)) continue;
73
+ const nextConfig = plugin[VINEXT_NEXT_CONFIG_PLUGIN_PROPERTY];
74
+ if (nextConfig) return nextConfig;
75
+ }
76
+ return null;
77
+ }
66
78
  const CONFIG_FILES = [
67
79
  "next.config.ts",
68
80
  "next.config.mts",
@@ -150,10 +162,12 @@ async function unwrapConfig(mod, phase = PHASE_DEVELOPMENT_SERVER) {
150
162
  /**
151
163
  * Resolve a path through filesystem symlinks, falling back to the original
152
164
  * path when the file does not exist (e.g. virtual ids, query-suffixed ids).
165
+ * Output is forward-slashed so it compares consistently with pathslash
166
+ * results (fs.realpathSync returns backslashes on Windows).
153
167
  */
154
168
  function safeRealpath(p) {
155
169
  try {
156
- return fs.realpathSync(p);
170
+ return toSlash(fs.realpathSync(p));
157
171
  } catch {
158
172
  return p;
159
173
  }
@@ -439,8 +453,8 @@ function createRscCompatibilityId(nextConfig) {
439
453
  * @returns A filesystem path suitable for path operations
440
454
  */
441
455
  function resolveCacheHandlerPathToFilesystem(filePath) {
442
- if (filePath.startsWith("file://")) return fileURLToPath(filePath);
443
- return filePath;
456
+ if (filePath.startsWith("file://")) return toSlash(fileURLToPath(filePath));
457
+ return toSlash(filePath);
444
458
  }
445
459
  function resolveHtmlLimitedBots(value) {
446
460
  const source = value instanceof RegExp ? value.source : typeof value === "string" ? value : void 0;
@@ -571,11 +585,71 @@ function normalizePrefetchInliningConfig(value) {
571
585
  maxSize: Number.isFinite(normalizedMaxSize) ? normalizedMaxSize : Number.MAX_SAFE_INTEGER
572
586
  };
573
587
  }
588
+ function normalizeI18nConfig(value) {
589
+ if (!value) return null;
590
+ const i18nType = typeof value;
591
+ if (i18nType !== "object") throw new Error(`Specified i18n should be an object received ${i18nType}.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
592
+ const i18n = value;
593
+ if (!Array.isArray(i18n.locales)) throw new Error(`Specified i18n.locales should be an Array received ${typeof i18n.locales}.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
594
+ if (i18n.locales.length > 100) console.warn(`Received ${i18n.locales.length} i18n.locales items which exceeds the recommended max of 100.\nSee more info here: https://nextjs.org/docs/advanced-features/i18n-routing#how-does-this-work-with-static-generation`);
595
+ if (!i18n.defaultLocale || typeof i18n.defaultLocale !== "string") throw new Error("Specified i18n.defaultLocale should be a string.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config");
596
+ if (i18n.domains !== void 0 && !Array.isArray(i18n.domains)) throw new Error(`Specified i18n.domains must be an array of domain objects e.g. [ { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] } ] received ${typeof i18n.domains}.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
597
+ if (i18n.domains) {
598
+ const invalidDomainItems = i18n.domains.filter((item) => {
599
+ if (!isUnknownRecord(item) || !item.defaultLocale) return true;
600
+ if (!item.domain || typeof item.domain !== "string") return true;
601
+ if (item.domain.includes(":")) {
602
+ console.warn(`i18n domain: "${item.domain}" is invalid it should be a valid domain without protocol (https://) or port (:3000) e.g. example.vercel.sh`);
603
+ return true;
604
+ }
605
+ const defaultLocaleDuplicate = i18n.domains.find((other) => isUnknownRecord(other) && other.defaultLocale === item.defaultLocale && other.domain !== item.domain);
606
+ if (defaultLocaleDuplicate && isUnknownRecord(defaultLocaleDuplicate)) {
607
+ console.warn(`Both ${item.domain} and ${String(defaultLocaleDuplicate.domain)} configured the defaultLocale ${item.defaultLocale} but only one can. Change one item's default locale to continue`);
608
+ return true;
609
+ }
610
+ let hasInvalidLocale = false;
611
+ if (Array.isArray(item.locales)) for (const locale of item.locales) {
612
+ if (typeof locale !== "string") hasInvalidLocale = true;
613
+ for (const domainItem of i18n.domains) {
614
+ if (domainItem === item || !isUnknownRecord(domainItem)) continue;
615
+ const domainLocales = domainItem.locales;
616
+ if (domainLocales && domainLocales.includes(locale)) {
617
+ console.warn(`Both ${item.domain} and ${String(domainItem.domain)} configured the locale (${String(locale)}) but only one can. Remove it from one i18n.domains config to continue`);
618
+ hasInvalidLocale = true;
619
+ break;
620
+ }
621
+ }
622
+ }
623
+ return hasInvalidLocale;
624
+ });
625
+ if (invalidDomainItems.length > 0) throw new Error(`Invalid i18n.domains values:\n${invalidDomainItems.map((item) => JSON.stringify(item)).join("\n")}\n\ndomains value must follow format { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] }.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
626
+ }
627
+ const invalidLocales = i18n.locales.filter((locale) => typeof locale !== "string");
628
+ if (invalidLocales.length > 0) throw new Error(`Specified i18n.locales contains invalid values (${invalidLocales.map(String).join(", ")}), locales must be valid locale tags provided as strings e.g. "en-US".\nSee here for list of valid language sub-tags: http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry`);
629
+ const locales = i18n.locales;
630
+ if (!locales.includes(i18n.defaultLocale)) throw new Error("Specified i18n.defaultLocale should be included in i18n.locales.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config");
631
+ const normalizedLocales = /* @__PURE__ */ new Set();
632
+ const duplicateLocales = /* @__PURE__ */ new Set();
633
+ for (const locale of locales) {
634
+ const localeLower = locale.toLowerCase();
635
+ if (normalizedLocales.has(localeLower)) duplicateLocales.add(locale);
636
+ normalizedLocales.add(localeLower);
637
+ }
638
+ if (duplicateLocales.size > 0) throw new Error(`Specified i18n.locales contains the following duplicate locales:\n${[...duplicateLocales].join(", ")}\nEach locale should be listed only once.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
639
+ const localeDetectionType = typeof i18n.localeDetection;
640
+ if (localeDetectionType !== "boolean" && localeDetectionType !== "undefined") throw new Error(`Specified i18n.localeDetection should be undefined or a boolean received ${localeDetectionType}.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`);
641
+ return {
642
+ locales: [i18n.defaultLocale, ...locales.filter((locale) => locale !== i18n.defaultLocale)],
643
+ defaultLocale: i18n.defaultLocale,
644
+ localeDetection: i18n.localeDetection ?? true,
645
+ domains: i18n.domains
646
+ };
647
+ }
574
648
  /**
575
649
  * Resolve a NextConfig into a fully-resolved ResolvedNextConfig.
576
650
  * Awaits async functions for redirects/rewrites/headers.
577
651
  */
578
- async function resolveNextConfig(config, root = process.cwd(), options = {}) {
652
+ async function resolveNextConfig(config, root = toSlash(process.cwd()), options = {}) {
579
653
  if (!config) {
580
654
  const buildId = await resolveBuildId(void 0);
581
655
  const deploymentId = resolveDeploymentId(void 0);
@@ -643,6 +717,7 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
643
717
  return resolved;
644
718
  }
645
719
  warnDeprecatedConfigOptions(config, root);
720
+ const i18n = normalizeI18nConfig(config.i18n);
646
721
  let redirects = [];
647
722
  if (config.redirects) {
648
723
  const result = await config.redirects();
@@ -729,13 +804,6 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
729
804
  const experimentalTurbo = readOptionalRecord(experimental?.turbo);
730
805
  const turbopack = readOptionalRecord(config.turbopack);
731
806
  const resolveExtensions = Array.isArray(turbopack?.resolveExtensions) ? readStringArray(turbopack.resolveExtensions) : Array.isArray(experimentalTurbo?.resolveExtensions) ? readStringArray(experimentalTurbo.resolveExtensions) : null;
732
- let i18n = null;
733
- if (config.i18n) i18n = {
734
- locales: config.i18n.locales,
735
- defaultLocale: config.i18n.defaultLocale,
736
- localeDetection: config.i18n.localeDetection ?? true,
737
- domains: config.i18n.domains
738
- };
739
807
  const buildId = await resolveBuildId(config.generateBuildId);
740
808
  const deploymentId = resolveDeploymentId(config.deploymentId);
741
809
  const cacheHandler = typeof config.cacheHandler === "string" ? resolveCacheHandlerPathToFilesystem(config.cacheHandler) : void 0;
@@ -748,6 +816,7 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
748
816
  afterFiles: applyLocaleToRoutes(rewrites.afterFiles, i18n, "rewrite", opts),
749
817
  fallback: applyLocaleToRoutes(rewrites.fallback, i18n, "rewrite", opts)
750
818
  };
819
+ headers = applyLocaleToRoutes(headers, i18n, "header", opts);
751
820
  }
752
821
  const images = config.images ? {
753
822
  ...config.images,
@@ -996,7 +1065,7 @@ function invokeLoaderSideEffects(rules, root) {
996
1065
  * loader rule. The remark/rehype plugins are captured in that closure.
997
1066
  * We probe the webpack function with a mock config to extract them.
998
1067
  */
999
- async function extractMdxOptions(config, root = process.cwd()) {
1068
+ async function extractMdxOptions(config, root = toSlash(process.cwd())) {
1000
1069
  return (await probeWebpackConfig(config, root, false)).mdx;
1001
1070
  }
1002
1071
  /**
@@ -1090,4 +1159,4 @@ function extractPluginsFromOptions(opts) {
1090
1159
  return null;
1091
1160
  }
1092
1161
  //#endregion
1093
- export { PHASE_PRODUCTION_BUILD, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
1162
+ export { PHASE_PRODUCTION_BUILD, VINEXT_NEXT_CONFIG_PLUGIN_PROPERTY, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, findVinextNextConfigInPlugins, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
@@ -30,8 +30,8 @@ type ViteConfigLoader = {
30
30
  loadConfigFromFile: typeof import("vite").loadConfigFromFile;
31
31
  };
32
32
  declare function normalizeVinextPrerenderConfig(config: VinextPrerenderConfig | undefined): ResolvedVinextPrerenderConfig | null;
33
- declare function findVinextPrerenderConfigInPlugins(plugins: PluginOption[] | undefined): ResolvedVinextPrerenderConfig | null;
34
- declare function findVinextRouteRootConfigInPlugins(plugins: PluginOption[] | undefined): VinextRouteRootConfig | null;
33
+ declare function findVinextPrerenderConfigInPlugins(plugins: PluginOption[] | undefined): Promise<ResolvedVinextPrerenderConfig | null>;
34
+ declare function findVinextRouteRootConfigInPlugins(plugins: PluginOption[] | undefined): Promise<VinextRouteRootConfig | null>;
35
35
  declare function loadVinextPrerenderConfigFromViteConfig(vite: ViteConfigLoader, root: string): Promise<ResolvedVinextPrerenderConfig | null>;
36
36
  declare function loadVinextRouteRootConfigFromViteConfig(vite: ViteConfigLoader, root: string): Promise<VinextRouteRootConfig | null>;
37
37
  declare function resolveVinextPrerenderDecision(options: {