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
@@ -20,7 +20,9 @@ import { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamName
20
20
  let cachedGraph = null;
21
21
  let cachedAppDir = null;
22
22
  let cachedPageExtensionsKey = null;
23
+ let cacheGeneration = 0;
23
24
  function invalidateAppRouteCache() {
25
+ cacheGeneration++;
24
26
  cachedGraph = null;
25
27
  cachedAppDir = null;
26
28
  cachedPageExtensionsKey = null;
@@ -30,25 +32,24 @@ function invalidateAppRouteCache() {
30
32
  * TODO(#726): Layer 4 should consume this read model directly once the
31
33
  * navigation planner owns route graph facts.
32
34
  *
33
- * `appDir` must be forward-slash — callers normalize it at their entry, and it
34
- * flows into `buildAppRouteGraph`, which builds every path with `path.posix.*`.
35
- *
36
35
  * @internal
37
36
  */
38
37
  async function appRouteGraph(appDir, pageExtensions, matcher) {
39
38
  matcher ??= createValidFileMatcher(pageExtensions);
40
39
  const pageExtensionsKey = JSON.stringify(matcher.extensions);
41
- if (cachedGraph && cachedAppDir === appDir && cachedPageExtensionsKey === pageExtensionsKey) return cachedGraph;
42
- const graph = await buildAppRouteGraph(appDir, matcher);
43
- cachedGraph = graph;
44
- cachedAppDir = appDir;
45
- cachedPageExtensionsKey = pageExtensionsKey;
46
- return graph;
40
+ while (true) {
41
+ if (cachedGraph && cachedAppDir === appDir && cachedPageExtensionsKey === pageExtensionsKey) return cachedGraph;
42
+ const scanGeneration = cacheGeneration;
43
+ const graph = await buildAppRouteGraph(appDir, matcher);
44
+ if (scanGeneration !== cacheGeneration) continue;
45
+ cachedGraph = graph;
46
+ cachedAppDir = appDir;
47
+ cachedPageExtensionsKey = pageExtensionsKey;
48
+ return graph;
49
+ }
47
50
  }
48
51
  /**
49
52
  * Scan the app/ directory and return a list of routes.
50
- *
51
- * `appDir` must be forward-slash — it is forwarded to `appRouteGraph`.
52
53
  */
53
54
  async function appRouter(appDir, pageExtensions, matcher) {
54
55
  return (await appRouteGraph(appDir, pageExtensions, matcher)).routes;
@@ -21,38 +21,24 @@ declare function findFileWithExtensions(basePath: string, matcher: ValidFileMatc
21
21
  /**
22
22
  * Find a file by basename and configured page extension in a directory.
23
23
  * Returns the first matching absolute path, or null if not found.
24
- *
25
- * `dir` must be forward-slash. The returned path is built with `path.posix.join`,
26
- * so it is forward-slash too.
27
24
  */
28
25
  declare function findFileWithExts(dir: string, name: string, matcher: ValidFileMatcher): string | null;
29
26
  /**
30
- * Vite's default `resolve.extensions` covers `.tsx/.ts/.jsx/.js/.json` (and
31
- * `.mjs/.mts`). When the user configures `pageExtensions` with values Vite
32
- * does not know about — e.g. `["platform.tsx", "tsx", "mdx"]` from the
33
- * Next.js `resolve-extensions` fixture — extensionless imports of those
34
- * files fail to resolve, and the build crashes with "Custom deploy script
35
- * failed: undefined (1)".
36
- *
37
- * Build the merged extension list that Vite should use:
27
+ * Add the config extensions produced by `vinext init` to vinext's resolver.
38
28
  *
39
- * 1. User-configured pageExtensions go first (each prefixed with `.`) so
40
- * the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
41
- * 2. Vite's defaults follow, with duplicates removed.
42
- * 3. `.cjs`/`.cts` go last (lowest priority). Neither Vite's defaults nor the
43
- * user's pageExtensions include them, but `vinext init` renames CJS config
44
- * files (e.g. `tailwind.config.js` → `tailwind.config.cjs`) when it adds
45
- * `"type": "module"`, and app code imports those extensionlessly
46
- * (`import cfg from "../tailwind.config"`). Without these, the bundle fails
47
- * with "[UNRESOLVED_IMPORT] Could not resolve '../tailwind.config'".
29
+ * `pageExtensions` is intentionally not part of module resolution. Next.js
30
+ * uses it to discover route files; custom module extensions are configured
31
+ * separately through `turbopack.resolveExtensions` or webpack
32
+ * `resolve.extensions`.
48
33
  *
49
- * The user's pageExtensions retain their relative order, which is what
50
- * Next.js / Turbopack do via the `resolveExtensions` config option.
34
+ * The default order preserves vinext's existing module-resolution behavior
35
+ * and matches Next.js Turbopack for overlapping JavaScript and TypeScript
36
+ * extensions.
51
37
  *
52
- * See: cloudflare/vinext#1502 for page-extension ordering, and
53
- * cloudflare/vinext#2435 for extensionless `.cjs` config imports.
38
+ * `.cjs`/`.cts` go last because `vinext init` renames CJS config files when it
39
+ * adds `"type": "module"`, and app code may import those files extensionlessly.
54
40
  */
55
- declare function buildViteResolveExtensions(pageExtensions?: readonly string[] | null, viteDefaults?: readonly string[]): string[];
41
+ declare function buildViteResolveExtensions(viteExtensions?: readonly string[]): string[];
56
42
  /**
57
43
  * Normalize an explicit Next.js resolver extension list for Vite.
58
44
  *
@@ -66,9 +52,8 @@ declare function normalizeViteResolveExtensions(extensions: readonly string[]):
66
52
  * Use function-form exclude for Node < 22.14 compatibility.
67
53
  *
68
54
  * Yields forward-slash relative paths: node's glob emits native (backslash)
69
- * separators on Windows, so each match is normalized — this is the entry point
70
- * that lets downstream consumers treat the scanned paths as canonical
71
- * forward-slash ids.
55
+ * separators on Windows, so each match goes through `toSlash` — this is the
56
+ * boundary where external fs output enters the canonical forward-slash space.
72
57
  */
73
58
  declare function scanWithExtensions(stem: string, cwd: string, extensions: readonly string[], exclude?: (name: string) => boolean): AsyncGenerator<string>;
74
59
  //#endregion
@@ -1,7 +1,6 @@
1
- import { normalizePathSeparators } from "../utils/path.js";
1
+ import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { escapeRegExp } from "../utils/regex.js";
3
3
  import { existsSync } from "node:fs";
4
- import path from "node:path";
5
4
  import { glob } from "node:fs/promises";
6
5
  //#region src/routing/file-matcher.ts
7
6
  const DEFAULT_PAGE_EXTENSIONS = [
@@ -10,6 +9,15 @@ const DEFAULT_PAGE_EXTENSIONS = [
10
9
  "jsx",
11
10
  "js"
12
11
  ];
12
+ const DEFAULT_VINEXT_RESOLVE_EXTENSIONS = [
13
+ ".tsx",
14
+ ".ts",
15
+ ".jsx",
16
+ ".js",
17
+ ".mjs",
18
+ ".mts",
19
+ ".json"
20
+ ];
13
21
  function normalizePageExtensions(pageExtensions) {
14
22
  if (!Array.isArray(pageExtensions) || pageExtensions.length === 0) return [...DEFAULT_PAGE_EXTENSIONS];
15
23
  const filtered = pageExtensions.filter((ext) => typeof ext === "string").map((ext) => ext.trim().replace(/^\.+/, "")).filter((ext) => ext.length > 0);
@@ -19,6 +27,10 @@ function buildExtensionGlob(stem, extensions) {
19
27
  if (extensions.length === 1) return `${stem}.${extensions[0]}`;
20
28
  return `${stem}.{${extensions.join(",")}}`;
21
29
  }
30
+ function includeDotDirectoryMatches(pattern) {
31
+ if (!pattern.startsWith("**/")) return pattern;
32
+ return `{**,**/.*/**}/${pattern.slice(3)}`;
33
+ }
22
34
  /**
23
35
  * Ported in spirit from Next.js createValidFileMatcher:
24
36
  * packages/next/src/server/lib/find-page-file.ts
@@ -67,58 +79,34 @@ function findFileWithExtensions(basePath, matcher) {
67
79
  /**
68
80
  * Find a file by basename and configured page extension in a directory.
69
81
  * Returns the first matching absolute path, or null if not found.
70
- *
71
- * `dir` must be forward-slash. The returned path is built with `path.posix.join`,
72
- * so it is forward-slash too.
73
82
  */
74
83
  function findFileWithExts(dir, name, matcher) {
75
84
  for (const ext of matcher.dottedExtensions) {
76
- const filePath = path.posix.join(dir, name + ext);
85
+ const filePath = path.join(dir, name + ext);
77
86
  if (existsSync(filePath)) return filePath;
78
87
  }
79
88
  return null;
80
89
  }
81
90
  /**
82
- * Vite's default `resolve.extensions` covers `.tsx/.ts/.jsx/.js/.json` (and
83
- * `.mjs/.mts`). When the user configures `pageExtensions` with values Vite
84
- * does not know about — e.g. `["platform.tsx", "tsx", "mdx"]` from the
85
- * Next.js `resolve-extensions` fixture — extensionless imports of those
86
- * files fail to resolve, and the build crashes with "Custom deploy script
87
- * failed: undefined (1)".
88
- *
89
- * Build the merged extension list that Vite should use:
91
+ * Add the config extensions produced by `vinext init` to vinext's resolver.
90
92
  *
91
- * 1. User-configured pageExtensions go first (each prefixed with `.`) so
92
- * the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
93
- * 2. Vite's defaults follow, with duplicates removed.
94
- * 3. `.cjs`/`.cts` go last (lowest priority). Neither Vite's defaults nor the
95
- * user's pageExtensions include them, but `vinext init` renames CJS config
96
- * files (e.g. `tailwind.config.js` → `tailwind.config.cjs`) when it adds
97
- * `"type": "module"`, and app code imports those extensionlessly
98
- * (`import cfg from "../tailwind.config"`). Without these, the bundle fails
99
- * with "[UNRESOLVED_IMPORT] Could not resolve '../tailwind.config'".
93
+ * `pageExtensions` is intentionally not part of module resolution. Next.js
94
+ * uses it to discover route files; custom module extensions are configured
95
+ * separately through `turbopack.resolveExtensions` or webpack
96
+ * `resolve.extensions`.
100
97
  *
101
- * The user's pageExtensions retain their relative order, which is what
102
- * Next.js / Turbopack do via the `resolveExtensions` config option.
98
+ * The default order preserves vinext's existing module-resolution behavior
99
+ * and matches Next.js Turbopack for overlapping JavaScript and TypeScript
100
+ * extensions.
103
101
  *
104
- * See: cloudflare/vinext#1502 for page-extension ordering, and
105
- * cloudflare/vinext#2435 for extensionless `.cjs` config imports.
102
+ * `.cjs`/`.cts` go last because `vinext init` renames CJS config files when it
103
+ * adds `"type": "module"`, and app code may import those files extensionlessly.
106
104
  */
107
- function buildViteResolveExtensions(pageExtensions, viteDefaults = [
108
- ".mjs",
109
- ".js",
110
- ".mts",
111
- ".ts",
112
- ".jsx",
113
- ".tsx",
114
- ".json"
115
- ]) {
116
- const dotted = normalizePageExtensions(pageExtensions).map((ext) => `.${ext}`);
105
+ function buildViteResolveExtensions(viteExtensions = DEFAULT_VINEXT_RESOLVE_EXTENSIONS) {
117
106
  const seen = /* @__PURE__ */ new Set();
118
107
  const result = [];
119
108
  for (const ext of [
120
- ...dotted,
121
- ...viteDefaults,
109
+ ...viteExtensions,
122
110
  ".cjs",
123
111
  ".cts"
124
112
  ]) {
@@ -153,16 +141,15 @@ function normalizeViteResolveExtensions(extensions) {
153
141
  * Use function-form exclude for Node < 22.14 compatibility.
154
142
  *
155
143
  * Yields forward-slash relative paths: node's glob emits native (backslash)
156
- * separators on Windows, so each match is normalized — this is the entry point
157
- * that lets downstream consumers treat the scanned paths as canonical
158
- * forward-slash ids.
144
+ * separators on Windows, so each match goes through `toSlash` — this is the
145
+ * boundary where external fs output enters the canonical forward-slash space.
159
146
  */
160
147
  async function* scanWithExtensions(stem, cwd, extensions, exclude) {
161
- const pattern = buildExtensionGlob(stem, extensions);
148
+ const pattern = includeDotDirectoryMatches(buildExtensionGlob(stem, extensions));
162
149
  for await (const file of glob(pattern, {
163
150
  cwd,
164
151
  ...exclude ? { exclude } : {}
165
- })) yield normalizePathSeparators(file);
152
+ })) yield toSlash(file);
166
153
  }
167
154
  //#endregion
168
155
  export { buildViteResolveExtensions, createValidFileMatcher, findFileWithExtensions, findFileWithExts, normalizePageExtensions, normalizeViteResolveExtensions, scanWithExtensions };
@@ -1,21 +1,23 @@
1
+ import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
1
2
  import { decodeRouteSegment, sortRoutes } from "./utils.js";
2
3
  import { createValidFileMatcher, scanWithExtensions } from "./file-matcher.js";
3
4
  import { patternToNextFormat, validateRoutePatterns } from "./route-validation.js";
4
- import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
5
- import path from "node:path";
5
+ import { createRouteTrieCache, matchRouteWithTrieRawPathname } from "./route-matching.js";
6
6
  //#region src/routing/pages-router.ts
7
7
  /** Next.js special pages that should not produce routes. */
8
- const RESERVED_PAGE_NAMES = new Set([
8
+ const RESERVED_PAGE_NAMES = /* @__PURE__ */ new Set([
9
9
  "_app",
10
10
  "_document",
11
11
  "_error"
12
12
  ]);
13
13
  const routeCache = /* @__PURE__ */ new Map();
14
+ let routeCacheGeneration = 0;
14
15
  /**
15
16
  * Invalidate cached routes for a given pages directory.
16
17
  * Called by the file watcher when pages are added/removed.
17
18
  */
18
19
  function invalidateRouteCache(pagesDir) {
20
+ routeCacheGeneration++;
19
21
  for (const key of routeCache.keys()) if (key.startsWith(`pages:${pagesDir}:`) || key.startsWith(`api:${pagesDir}:`)) routeCache.delete(key);
20
22
  }
21
23
  /**
@@ -32,20 +34,7 @@ function invalidateRouteCache(pagesDir) {
32
34
  */
33
35
  async function pagesRouter(pagesDir, pageExtensions, matcher) {
34
36
  matcher ??= createValidFileMatcher(pageExtensions);
35
- const cacheKey = `pages:${pagesDir}:${JSON.stringify(matcher.extensions)}`;
36
- const cached = routeCache.get(cacheKey);
37
- if (cached) return cached.promise;
38
- const promise = scanPageRoutes(pagesDir, matcher);
39
- routeCache.set(cacheKey, {
40
- routes: [],
41
- promise
42
- });
43
- const routes = await promise;
44
- routeCache.set(cacheKey, {
45
- routes,
46
- promise
47
- });
48
- return routes;
37
+ return getCachedRoutes(`pages:${pagesDir}:${JSON.stringify(matcher.extensions)}`, () => scanPageRoutes(pagesDir, matcher));
49
38
  }
50
39
  async function scanPageRoutes(pagesDir, matcher) {
51
40
  const routes = [];
@@ -114,7 +103,7 @@ const trieCache = createRouteTrieCache();
114
103
  * Returns the matched params or null if no match.
115
104
  */
116
105
  function matchRoute(url, routes) {
117
- return matchRouteWithTrie(url, routes, trieCache);
106
+ return matchRouteWithTrieRawPathname(url, routes, trieCache);
118
107
  }
119
108
  /**
120
109
  * Scan the pages/api/ directory and return API routes.
@@ -126,20 +115,25 @@ function matchRoute(url, routes) {
126
115
  */
127
116
  async function apiRouter(pagesDir, pageExtensions, matcher) {
128
117
  matcher ??= createValidFileMatcher(pageExtensions);
129
- const cacheKey = `api:${pagesDir}:${JSON.stringify(matcher.extensions)}`;
118
+ return getCachedRoutes(`api:${pagesDir}:${JSON.stringify(matcher.extensions)}`, () => scanApiRoutes(pagesDir, matcher));
119
+ }
120
+ async function getCachedRoutes(cacheKey, scan) {
130
121
  const cached = routeCache.get(cacheKey);
131
- if (cached) return cached.promise;
132
- const promise = scanApiRoutes(pagesDir, matcher);
133
- routeCache.set(cacheKey, {
134
- routes: [],
135
- promise
136
- });
137
- const routes = await promise;
138
- routeCache.set(cacheKey, {
139
- routes,
140
- promise
141
- });
142
- return routes;
122
+ if (cached) return cached;
123
+ const promise = (async () => {
124
+ while (true) {
125
+ const scanGeneration = routeCacheGeneration;
126
+ const routes = await scan();
127
+ if (scanGeneration === routeCacheGeneration) return routes;
128
+ }
129
+ })();
130
+ routeCache.set(cacheKey, promise);
131
+ try {
132
+ return await promise;
133
+ } catch (error) {
134
+ if (routeCache.get(cacheKey) === promise) routeCache.delete(cacheKey);
135
+ throw error;
136
+ }
143
137
  }
144
138
  async function scanApiRoutes(pagesDir, matcher) {
145
139
  const apiDir = path.join(pagesDir, "api");
@@ -152,7 +146,7 @@ async function scanApiRoutes(pagesDir, matcher) {
152
146
  }
153
147
  const routes = [];
154
148
  for (const file of files) {
155
- const route = fileToRoute(path.posix.join("api", file), pagesDir, matcher);
149
+ const route = fileToRoute(path.join("api", file), pagesDir, matcher);
156
150
  if (route) routes.push(route);
157
151
  }
158
152
  validateRoutePatterns(routes.map((route) => route.pattern));
@@ -23,5 +23,18 @@ declare function matchRouteWithTrie<R extends {
23
23
  route: R;
24
24
  params: Record<string, string | string[]>;
25
25
  } | null;
26
+ /**
27
+ * Match a filesystem route against the request's raw encoded pathname.
28
+ *
29
+ * Next.js compares static route identity before decoding, so `/%61bout` does
30
+ * not select the filesystem route `/about`. Dynamic captures are still decoded
31
+ * exactly once by `trieMatch`, matching `getRouteMatcher` upstream.
32
+ */
33
+ declare function matchRouteWithTrieRawPathname<R extends {
34
+ patternParts: string[];
35
+ }>(url: string, routes: R[], cache: RouteTrieCache<R>): {
36
+ route: R;
37
+ params: Record<string, string | string[]>;
38
+ } | null;
26
39
  //#endregion
27
- export { createRouteTrieCache, matchRouteWithTrie };
40
+ export { createRouteTrieCache, matchRouteWithTrie, matchRouteWithTrieRawPathname };
@@ -38,5 +38,17 @@ function matchRouteWithTrie(url, routes, cache) {
38
38
  const urlParts = normalizedUrl.split("/").filter(Boolean);
39
39
  return trieMatch(getOrBuildTrie(cache, routes), urlParts);
40
40
  }
41
+ /**
42
+ * Match a filesystem route against the request's raw encoded pathname.
43
+ *
44
+ * Next.js compares static route identity before decoding, so `/%61bout` does
45
+ * not select the filesystem route `/about`. Dynamic captures are still decoded
46
+ * exactly once by `trieMatch`, matching `getRouteMatcher` upstream.
47
+ */
48
+ function matchRouteWithTrieRawPathname(url, routes, cache) {
49
+ const pathname = url.split("?")[0];
50
+ const urlParts = (pathname === "/" ? "/" : pathname.replace(/\/$/, "")).split("/").filter(Boolean);
51
+ return trieMatch(getOrBuildTrie(cache, routes), urlParts);
52
+ }
41
53
  //#endregion
42
- export { createRouteTrieCache, matchRouteWithTrie };
54
+ export { createRouteTrieCache, matchRouteWithTrie, matchRouteWithTrieRawPathname };
@@ -4,6 +4,7 @@ declare function routePatternParts(pathname: string): string[];
4
4
  declare function routePattern(pathname: string): string;
5
5
  declare function fillRoutePatternSegments(pathname: string, params: RoutePatternParams): string | null;
6
6
  declare function matchRoutePattern(urlParts: readonly string[], patternParts: readonly string[]): RoutePatternParams | null;
7
+ declare function matchRoutePatternRaw(urlParts: readonly string[], patternParts: readonly string[]): RoutePatternParams | null;
7
8
  declare function matchRoutePatternPrefix(pathParts: readonly string[], patternParts: readonly string[]): boolean;
8
9
  declare function matchRoutePatternWithOptionalDynamicSegments(pathParts: readonly string[], patternParts: readonly string[]): boolean;
9
10
  /**
@@ -61,4 +62,4 @@ declare function normalizeStaticPathname(pathname: string): string;
61
62
  */
62
63
  declare function normalizeStaticPathsEntry(entry: StaticPathsEntry, routePattern: string): NormalizedStaticPathsEntry;
63
64
  //#endregion
64
- export { RoutePatternParams, StaticPathsEntry, fillRoutePatternSegments, matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternWithOptionalDynamicSegments, normalizeStaticPathname, normalizeStaticPathsEntry, routePattern, routePatternParts };
65
+ export { RoutePatternParams, StaticPathsEntry, fillRoutePatternSegments, matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternRaw, matchRoutePatternWithOptionalDynamicSegments, normalizeStaticPathname, normalizeStaticPathsEntry, routePattern, routePatternParts };
@@ -56,6 +56,11 @@ function fillRoutePatternSegments(pathname, params) {
56
56
  return resolvedSegments.length > 0 ? `/${resolvedSegments.join("/")}` : "/";
57
57
  }
58
58
  function matchRoutePattern(urlParts, patternParts) {
59
+ const params = matchRoutePatternRaw(urlParts, patternParts);
60
+ if (params) decodeMatchedParams(params);
61
+ return params;
62
+ }
63
+ function matchRoutePatternRaw(urlParts, patternParts) {
59
64
  const params = Object.create(null);
60
65
  function matchFrom(urlIndex, patternIndex) {
61
66
  if (patternIndex === patternParts.length) return urlIndex === urlParts.length;
@@ -83,9 +88,7 @@ function matchRoutePattern(urlParts, patternParts) {
83
88
  if (urlIndex >= urlParts.length || urlParts[urlIndex] !== patternPart) return false;
84
89
  return matchFrom(urlIndex + 1, patternIndex + 1);
85
90
  }
86
- if (!matchFrom(0, 0)) return null;
87
- decodeMatchedParams(params);
88
- return params;
91
+ return matchFrom(0, 0) ? params : null;
89
92
  }
90
93
  function matchRoutePatternPrefix(pathParts, patternParts) {
91
94
  let pathIndex = 0;
@@ -162,4 +165,4 @@ function normalizeStaticPathsEntry(entry, routePattern) {
162
165
  return { params };
163
166
  }
164
167
  //#endregion
165
- export { fillRoutePatternSegments, matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternWithOptionalDynamicSegments, normalizeStaticPathname, normalizeStaticPathsEntry, routePattern, routePatternParts };
168
+ export { fillRoutePatternSegments, matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternRaw, matchRoutePatternWithOptionalDynamicSegments, normalizeStaticPathname, normalizeStaticPathsEntry, routePattern, routePatternParts };
@@ -63,5 +63,9 @@ declare function trieMatch<R>(root: TrieNode<R>, urlParts: string[]): {
63
63
  route: R;
64
64
  params: Record<string, string | string[]>;
65
65
  } | null;
66
+ declare function trieMatchRaw<R>(root: TrieNode<R>, urlParts: string[]): {
67
+ route: R;
68
+ params: Record<string, string | string[]>;
69
+ } | null;
66
70
  //#endregion
67
- export { TrieNode, buildRouteTrie, trieMatch };
71
+ export { TrieNode, buildRouteTrie, trieMatch, trieMatchRaw };
@@ -92,10 +92,13 @@ function buildRouteTrie(routes) {
92
92
  * @returns Match result with route and extracted params, or null
93
93
  */
94
94
  function trieMatch(root, urlParts) {
95
- const result = match(root, urlParts, 0, []);
95
+ const result = trieMatchRaw(root, urlParts);
96
96
  if (result) decodeMatchedParams(result.params);
97
97
  return result;
98
98
  }
99
+ function trieMatchRaw(root, urlParts) {
100
+ return match(root, urlParts, 0, []);
101
+ }
99
102
  function match(node, urlParts, index, entries) {
100
103
  if (index === urlParts.length) {
101
104
  if (node.route !== null) return {
@@ -140,4 +143,4 @@ function match(node, urlParts, index, entries) {
140
143
  return null;
141
144
  }
142
145
  //#endregion
143
- export { buildRouteTrie, trieMatch };
146
+ export { buildRouteTrie, trieMatch, trieMatchRaw };
@@ -8,7 +8,7 @@ import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT, resolveBodyParserConfig } from "./pa
8
8
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
9
9
  import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
10
10
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
11
- import { attachPagesRequestCookies } from "./pages-node-compat.js";
11
+ import { attachPagesPreviewApi, attachPagesRequestCookies } from "./pages-node-compat.js";
12
12
  import { isEdgeApiRuntime } from "./edge-api-runtime.js";
13
13
  import { decode } from "node:querystring";
14
14
  import { Buffer } from "node:buffer";
@@ -166,41 +166,49 @@ function enhanceApiObjects(req, res, query, body) {
166
166
  query
167
167
  });
168
168
  attachPagesRequestCookies(apiReq);
169
- return {
170
- apiReq,
171
- apiRes: Object.assign(res, {
172
- status(code) {
173
- this.statusCode = code;
174
- return this;
175
- },
176
- json(data) {
169
+ const apiRes = Object.assign(res, {
170
+ status(code) {
171
+ this.statusCode = code;
172
+ return this;
173
+ },
174
+ json(data) {
175
+ this.setHeader("Content-Type", "application/json");
176
+ this.end(JSON.stringify(data));
177
+ },
178
+ send(data) {
179
+ if (Buffer.isBuffer(data)) {
180
+ if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "application/octet-stream");
181
+ this.setHeader("Content-Length", String(data.length));
182
+ this.end(data);
183
+ return;
184
+ }
185
+ if (typeof data === "object" && data !== null) {
177
186
  this.setHeader("Content-Type", "application/json");
178
187
  this.end(JSON.stringify(data));
179
- },
180
- send(data) {
181
- if (Buffer.isBuffer(data)) {
182
- if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "application/octet-stream");
183
- this.setHeader("Content-Length", String(data.length));
184
- this.end(data);
185
- return;
186
- }
187
- if (typeof data === "object" && data !== null) {
188
- this.setHeader("Content-Type", "application/json");
189
- this.end(JSON.stringify(data));
190
- } else {
191
- if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "text/plain");
192
- this.end(String(data));
193
- }
194
- },
195
- redirect(statusOrUrl, url) {
196
- if (typeof statusOrUrl === "string") this.writeHead(307, { Location: statusOrUrl });
197
- else this.writeHead(statusOrUrl, { Location: url ?? "" });
198
- this.end();
199
- },
200
- async revalidate(urlPath, opts) {
201
- await performOnDemandRevalidate(req, urlPath, opts);
188
+ } else {
189
+ if (!this.getHeader("Content-Type")) this.setHeader("Content-Type", "text/plain");
190
+ this.end(String(data));
191
+ }
192
+ },
193
+ redirect(statusOrUrl, url) {
194
+ if (typeof statusOrUrl === "string") {
195
+ url = statusOrUrl;
196
+ statusOrUrl = 307;
202
197
  }
203
- })
198
+ if (typeof statusOrUrl !== "number" || typeof url !== "string") throw new Error("Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').");
199
+ this.writeHead(statusOrUrl, { Location: url });
200
+ this.write(url);
201
+ this.end();
202
+ return this;
203
+ },
204
+ async revalidate(urlPath, opts) {
205
+ await performOnDemandRevalidate(req, urlPath, opts);
206
+ }
207
+ });
208
+ attachPagesPreviewApi(apiReq, apiRes);
209
+ return {
210
+ apiReq,
211
+ apiRes
204
212
  };
205
213
  }
206
214
  /**