vinext 0.1.8 → 0.2.1

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 (285) hide show
  1. package/README.md +51 -30
  2. package/dist/build/css-url-assets.d.ts +3 -1
  3. package/dist/build/css-url-assets.js +18 -1
  4. package/dist/build/inject-pregenerated-paths.d.ts +7 -0
  5. package/dist/build/inject-pregenerated-paths.js +21 -0
  6. package/dist/build/layout-classification.js +1 -1
  7. package/dist/build/nitro-route-rules.js +1 -1
  8. package/dist/build/pages-client-assets-module.d.ts +11 -0
  9. package/dist/build/pages-client-assets-module.js +27 -0
  10. package/dist/build/prerender-server-entry.d.ts +1 -0
  11. package/dist/build/prerender-server-entry.js +49 -0
  12. package/dist/build/prerender-server-pool.d.ts +44 -0
  13. package/dist/build/prerender-server-pool.js +194 -0
  14. package/dist/build/prerender.d.ts +2 -1
  15. package/dist/build/prerender.js +98 -27
  16. package/dist/build/report.d.ts +13 -2
  17. package/dist/build/report.js +99 -2
  18. package/dist/build/run-prerender.d.ts +7 -0
  19. package/dist/build/run-prerender.js +12 -2
  20. package/dist/build/standalone.js +2 -0
  21. package/dist/cache/cache-adapters-virtual.js +3 -3
  22. package/dist/check.d.ts +4 -6
  23. package/dist/check.js +48 -11
  24. package/dist/cli-args.d.ts +1 -2
  25. package/dist/cli-args.js +1 -1
  26. package/dist/cli-dev-config.d.ts +12 -0
  27. package/dist/cli-dev-config.js +23 -0
  28. package/dist/cli.js +112 -96
  29. package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
  30. package/dist/{server → client}/dev-error-overlay-store.js +1 -1
  31. package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
  32. package/dist/{server → client}/dev-error-overlay.js +2 -2
  33. package/dist/client/navigation-runtime.d.ts +2 -0
  34. package/dist/client/navigation-runtime.js +3 -1
  35. package/dist/client/vinext-next-data.d.ts +4 -1
  36. package/dist/client/window-next.d.ts +2 -1
  37. package/dist/cloudflare/index.d.ts +2 -2
  38. package/dist/cloudflare/index.js +2 -2
  39. package/dist/config/config-matchers.js +45 -19
  40. package/dist/config/next-config.d.ts +41 -9
  41. package/dist/config/next-config.js +60 -3
  42. package/dist/config/prerender.d.ts +34 -0
  43. package/dist/config/prerender.js +55 -0
  44. package/dist/entries/app-browser-entry.js +5 -1
  45. package/dist/entries/app-rsc-entry.d.ts +5 -3
  46. package/dist/entries/app-rsc-entry.js +44 -10
  47. package/dist/entries/app-rsc-manifest.js +2 -0
  48. package/dist/entries/pages-client-entry.d.ts +3 -0
  49. package/dist/entries/pages-client-entry.js +28 -3
  50. package/dist/entries/pages-server-entry.js +23 -6
  51. package/dist/image/image-adapters-virtual.d.ts +59 -0
  52. package/dist/image/image-adapters-virtual.js +59 -0
  53. package/dist/index.d.ts +33 -0
  54. package/dist/index.js +482 -120
  55. package/dist/init-cloudflare.d.ts +43 -0
  56. package/dist/init-cloudflare.js +839 -0
  57. package/dist/init-platform.d.ts +40 -0
  58. package/dist/init-platform.js +195 -0
  59. package/dist/init.d.ts +16 -38
  60. package/dist/init.js +209 -99
  61. package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
  62. package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
  63. package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
  64. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
  65. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +9 -2
  66. package/dist/packages/cloudflare/src/deploy-config.js +150 -0
  67. package/dist/packages/cloudflare/src/deploy-help.js +55 -0
  68. package/dist/packages/cloudflare/src/deploy.js +272 -0
  69. package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
  70. package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +44 -20
  71. package/dist/plugins/ast-scope.d.ts +16 -0
  72. package/dist/plugins/ast-scope.js +62 -0
  73. package/dist/plugins/ast-utils.d.ts +27 -1
  74. package/dist/plugins/ast-utils.js +32 -1
  75. package/dist/plugins/css-module-imports.d.ts +14 -0
  76. package/dist/plugins/css-module-imports.js +59 -0
  77. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  78. package/dist/plugins/fonts.js +1 -1
  79. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  80. package/dist/plugins/ignore-dynamic-requests.js +530 -0
  81. package/dist/plugins/og-assets.js +2 -1
  82. package/dist/plugins/optimize-imports.js +1 -1
  83. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  84. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  85. package/dist/plugins/sass.d.ts +17 -1
  86. package/dist/plugins/sass.js +74 -1
  87. package/dist/plugins/styled-jsx.d.ts +16 -0
  88. package/dist/plugins/styled-jsx.js +149 -0
  89. package/dist/plugins/typeof-window.d.ts +1 -1
  90. package/dist/plugins/typeof-window.js +28 -56
  91. package/dist/routing/app-route-graph.d.ts +23 -2
  92. package/dist/routing/app-route-graph.js +138 -38
  93. package/dist/routing/file-matcher.d.ts +11 -1
  94. package/dist/routing/file-matcher.js +18 -3
  95. package/dist/routing/pages-router.js +2 -2
  96. package/dist/server/api-handler.js +9 -14
  97. package/dist/server/app-browser-action-result.d.ts +4 -1
  98. package/dist/server/app-browser-action-result.js +8 -1
  99. package/dist/server/app-browser-entry.js +198 -57
  100. package/dist/server/app-browser-interception-context.d.ts +1 -0
  101. package/dist/server/app-browser-interception-context.js +4 -2
  102. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  103. package/dist/server/app-browser-navigation-controller.js +60 -31
  104. package/dist/server/app-browser-server-action-client.d.ts +1 -1
  105. package/dist/server/app-browser-server-action-client.js +8 -7
  106. package/dist/server/app-browser-state.d.ts +12 -1
  107. package/dist/server/app-browser-state.js +25 -8
  108. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  109. package/dist/server/app-browser-visible-commit.js +42 -24
  110. package/dist/server/app-elements-wire.d.ts +9 -2
  111. package/dist/server/app-elements-wire.js +8 -1
  112. package/dist/server/app-elements.d.ts +2 -2
  113. package/dist/server/app-elements.js +4 -3
  114. package/dist/server/app-fallback-renderer.d.ts +2 -1
  115. package/dist/server/app-fallback-renderer.js +10 -6
  116. package/dist/server/app-hydration-cache-publication.d.ts +11 -0
  117. package/dist/server/app-hydration-cache-publication.js +43 -0
  118. package/dist/server/app-middleware.d.ts +4 -3
  119. package/dist/server/app-middleware.js +8 -3
  120. package/dist/server/app-optimistic-routing.js +11 -4
  121. package/dist/server/app-page-boundary.js +2 -1
  122. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  123. package/dist/server/app-page-cache-finalizer.js +5 -4
  124. package/dist/server/app-page-cache-render.d.ts +1 -0
  125. package/dist/server/app-page-cache-render.js +8 -4
  126. package/dist/server/app-page-cache.d.ts +1 -0
  127. package/dist/server/app-page-cache.js +27 -7
  128. package/dist/server/app-page-dispatch.d.ts +1 -0
  129. package/dist/server/app-page-dispatch.js +26 -8
  130. package/dist/server/app-page-element-builder.d.ts +2 -1
  131. package/dist/server/app-page-element-builder.js +59 -4
  132. package/dist/server/app-page-execution.js +2 -1
  133. package/dist/server/app-page-probe.js +5 -0
  134. package/dist/server/app-page-render-identity.d.ts +2 -0
  135. package/dist/server/app-page-render-identity.js +3 -2
  136. package/dist/server/app-page-render.d.ts +2 -0
  137. package/dist/server/app-page-render.js +85 -16
  138. package/dist/server/app-page-request.d.ts +14 -0
  139. package/dist/server/app-page-request.js +69 -4
  140. package/dist/server/app-page-response.d.ts +7 -0
  141. package/dist/server/app-page-response.js +16 -4
  142. package/dist/server/app-page-route-wiring.d.ts +8 -1
  143. package/dist/server/app-page-route-wiring.js +32 -18
  144. package/dist/server/app-page-segment-state.d.ts +2 -1
  145. package/dist/server/app-page-segment-state.js +3 -1
  146. package/dist/server/app-page-stream.d.ts +7 -1
  147. package/dist/server/app-page-stream.js +3 -1
  148. package/dist/server/app-route-handler-execution.js +5 -1
  149. package/dist/server/app-route-handler-response.js +1 -0
  150. package/dist/server/app-route-handler-runtime.js +1 -1
  151. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  152. package/dist/server/app-route-tree-prefetch.js +187 -0
  153. package/dist/server/app-router-entry.js +9 -2
  154. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  155. package/dist/server/app-rsc-cache-busting.js +9 -4
  156. package/dist/server/app-rsc-handler.d.ts +7 -0
  157. package/dist/server/app-rsc-handler.js +148 -39
  158. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  159. package/dist/server/app-rsc-render-mode.js +4 -1
  160. package/dist/server/app-rsc-request-normalization.d.ts +6 -6
  161. package/dist/server/app-rsc-request-normalization.js +10 -8
  162. package/dist/server/app-segment-config.d.ts +11 -0
  163. package/dist/server/app-segment-config.js +62 -6
  164. package/dist/server/app-server-action-execution.d.ts +1 -0
  165. package/dist/server/app-server-action-execution.js +61 -30
  166. package/dist/server/app-ssr-entry.d.ts +3 -0
  167. package/dist/server/app-ssr-entry.js +13 -5
  168. package/dist/server/app-ssr-stream.d.ts +7 -3
  169. package/dist/server/app-ssr-stream.js +10 -6
  170. package/dist/server/app-visited-response-cache.d.ts +6 -0
  171. package/dist/server/app-visited-response-cache.js +3 -1
  172. package/dist/server/cache-control.d.ts +3 -1
  173. package/dist/server/cache-control.js +13 -1
  174. package/dist/server/client-trace-metadata.js +26 -0
  175. package/dist/server/default-global-not-found-module.d.ts +14 -0
  176. package/dist/server/default-global-not-found-module.js +14 -0
  177. package/dist/server/dev-route-files.js +4 -0
  178. package/dist/server/dev-server.d.ts +11 -1
  179. package/dist/server/dev-server.js +94 -35
  180. package/dist/server/dev-stack-sourcemap.d.ts +1 -1
  181. package/dist/server/dev-stack-sourcemap.js +1 -1
  182. package/dist/server/fetch-handler.d.ts +2 -0
  183. package/dist/server/fetch-handler.js +18 -0
  184. package/dist/server/headers.d.ts +7 -15
  185. package/dist/server/headers.js +11 -18
  186. package/dist/server/image-optimization.d.ts +51 -1
  187. package/dist/server/image-optimization.js +52 -2
  188. package/dist/server/implicit-tags.js +1 -1
  189. package/dist/server/isr-cache.d.ts +3 -2
  190. package/dist/server/isr-cache.js +9 -5
  191. package/dist/server/metadata-routes.d.ts +3 -1
  192. package/dist/server/metadata-routes.js +12 -2
  193. package/dist/server/middleware-runtime.js +6 -1
  194. package/dist/server/navigation-planner.d.ts +1 -0
  195. package/dist/server/navigation-planner.js +14 -3
  196. package/dist/server/pages-api-route.js +2 -2
  197. package/dist/server/pages-asset-tags.d.ts +4 -6
  198. package/dist/server/pages-asset-tags.js +12 -12
  199. package/dist/server/pages-client-assets.d.ts +12 -0
  200. package/dist/server/pages-client-assets.js +10 -0
  201. package/dist/server/pages-data-route.d.ts +4 -2
  202. package/dist/server/pages-data-route.js +18 -4
  203. package/dist/server/pages-dev-module-url.d.ts +2 -1
  204. package/dist/server/pages-dev-module-url.js +6 -3
  205. package/dist/server/pages-node-compat.d.ts +19 -1
  206. package/dist/server/pages-node-compat.js +81 -4
  207. package/dist/server/pages-page-data.d.ts +33 -1
  208. package/dist/server/pages-page-data.js +62 -33
  209. package/dist/server/pages-page-handler.d.ts +2 -1
  210. package/dist/server/pages-page-handler.js +38 -19
  211. package/dist/server/pages-page-response.d.ts +8 -0
  212. package/dist/server/pages-page-response.js +7 -3
  213. package/dist/server/pages-request-pipeline.d.ts +9 -5
  214. package/dist/server/pages-request-pipeline.js +55 -7
  215. package/dist/server/pages-router-entry.d.ts +30 -0
  216. package/dist/server/pages-router-entry.js +108 -0
  217. package/dist/server/prerender-manifest.d.ts +3 -1
  218. package/dist/server/prerender-route-params.js +1 -1
  219. package/dist/server/prod-server.d.ts +5 -3
  220. package/dist/server/prod-server.js +68 -39
  221. package/dist/server/request-pipeline.js +2 -1
  222. package/dist/server/seed-cache.js +4 -4
  223. package/dist/shims/app-router-scroll-state.d.ts +1 -0
  224. package/dist/shims/app-router-scroll-state.js +1 -0
  225. package/dist/shims/app-router-scroll.js +2 -1
  226. package/dist/shims/cache-handler.js +8 -1
  227. package/dist/shims/cache.js +22 -15
  228. package/dist/shims/cdn-cache.js +1 -1
  229. package/dist/shims/dynamic-preload-chunks.js +2 -1
  230. package/dist/shims/fetch-cache.d.ts +3 -1
  231. package/dist/shims/fetch-cache.js +77 -52
  232. package/dist/shims/form.d.ts +4 -2
  233. package/dist/shims/form.js +37 -43
  234. package/dist/shims/headers.d.ts +7 -1
  235. package/dist/shims/headers.js +17 -3
  236. package/dist/shims/image.js +75 -14
  237. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  238. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  239. package/dist/shims/internal/app-route-detection.d.ts +2 -17
  240. package/dist/shims/internal/app-route-detection.js +4 -17
  241. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
  242. package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
  243. package/dist/shims/internal/hybrid-client-route-owner.d.ts +3 -15
  244. package/dist/shims/internal/hybrid-client-route-owner.js +40 -58
  245. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +10 -5
  246. package/dist/shims/internal/pages-data-fetch-dedup.js +84 -14
  247. package/dist/shims/internal/pages-data-target.d.ts +18 -12
  248. package/dist/shims/internal/pages-data-target.js +97 -13
  249. package/dist/shims/internal/pages-router-components.d.ts +7 -0
  250. package/dist/shims/internal/pages-router-components.js +13 -0
  251. package/dist/shims/layout-segment-context.d.ts +4 -1
  252. package/dist/shims/layout-segment-context.js +18 -4
  253. package/dist/shims/link.d.ts +1 -1
  254. package/dist/shims/link.js +224 -58
  255. package/dist/shims/navigation.d.ts +19 -3
  256. package/dist/shims/navigation.js +245 -47
  257. package/dist/shims/request-context.js +18 -0
  258. package/dist/shims/root-params.d.ts +15 -1
  259. package/dist/shims/root-params.js +21 -1
  260. package/dist/shims/router.d.ts +5 -7
  261. package/dist/shims/router.js +387 -102
  262. package/dist/shims/server.js +3 -2
  263. package/dist/shims/slot.js +3 -6
  264. package/dist/shims/unified-request-context.js +1 -0
  265. package/dist/typegen.js +1 -1
  266. package/dist/utils/client-runtime-metadata.d.ts +2 -18
  267. package/dist/utils/client-runtime-metadata.js +31 -22
  268. package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
  269. package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
  270. package/dist/utils/domain-locale.d.ts +6 -3
  271. package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
  272. package/dist/{server → utils}/middleware-request-headers.js +3 -3
  273. package/dist/utils/project.d.ts +48 -2
  274. package/dist/utils/project.js +225 -4
  275. package/dist/utils/protocol-headers.d.ts +23 -0
  276. package/dist/utils/protocol-headers.js +23 -0
  277. package/dist/utils/react-version.d.ts +4 -0
  278. package/dist/utils/react-version.js +44 -0
  279. package/dist/utils/vite-version.d.ts +2 -0
  280. package/dist/utils/vite-version.js +11 -1
  281. package/package.json +47 -2
  282. package/dist/deploy.d.ts +0 -197
  283. package/dist/deploy.js +0 -1040
  284. package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
  285. /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
@@ -1,5 +1,5 @@
1
- import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
2
1
  import { normalizePathSeparators } from "../utils/path.js";
2
+ import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
3
3
  import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
4
4
  import { validateRoutePatterns } from "./route-validation.js";
5
5
  import { compareStrings } from "../utils/compare.js";
@@ -83,6 +83,19 @@ function createStaticSegmentGraph(routes) {
83
83
  templateIds: [...route.ids.templates],
84
84
  slotIds: route.parallelSlots.map((slot) => slot.id).sort(compareStableStrings)
85
85
  });
86
+ if (route.childrenSlot) {
87
+ const ownerLayoutId = findRouteManifestOwnerLayoutIdByTreePath(route, route.childrenSlot.ownerTreePath);
88
+ routeEntries.get(route.ids.route).slotIds = [...routeEntries.get(route.ids.route).slotIds, route.childrenSlot.id].sort(compareStableStrings);
89
+ slotBindings.set(`${route.ids.route}::${route.childrenSlot.id}`, {
90
+ id: `${route.ids.route}::${route.childrenSlot.id}`,
91
+ routeId: route.ids.route,
92
+ slotId: route.childrenSlot.id,
93
+ ownerLayoutId,
94
+ state: route.childrenSlot.state,
95
+ defaultId: null,
96
+ routeSegments: null
97
+ });
98
+ }
86
99
  if (route.ids.page) pages.set(route.ids.page, {
87
100
  id: route.ids.page,
88
101
  routeId: route.ids.route,
@@ -225,6 +238,10 @@ function findRouteManifestOwnerLayoutId(route, treePosition) {
225
238
  const layoutIndex = route.layoutTreePositions.indexOf(treePosition);
226
239
  return route.ids.layouts[layoutIndex] ?? null;
227
240
  }
241
+ function findRouteManifestOwnerLayoutIdByTreePath(route, treePath) {
242
+ const layoutIndex = route.layoutTreePositions.findIndex((treePosition) => createAppRouteGraphTreePath(route.routeSegments, treePosition) === treePath);
243
+ return route.ids.layouts[layoutIndex] ?? null;
244
+ }
228
245
  function findSlotOwnerLayoutId(route, slot) {
229
246
  if (slot.layoutIndex < 0) return null;
230
247
  return route.ids.layouts[slot.layoutIndex] ?? null;
@@ -344,6 +361,13 @@ function createRouteManifestGraphVersion(segmentGraph) {
344
361
  };
345
362
  return `graph:${createHash("sha256").update(JSON.stringify(stableShape)).digest("hex")}`;
346
363
  }
364
+ /**
365
+ * Build the App Router route graph by scanning `appDir`.
366
+ *
367
+ * `appDir` must be forward-slash. Every path in the graph is derived from it
368
+ * with `path.posix.*` and `findFile`, so a native appDir would produce mixed
369
+ * separators on Windows. Production callers normalize it at their entry.
370
+ */
347
371
  async function buildAppRouteGraph(appDir, matcher) {
348
372
  const routes = [];
349
373
  const scanMatcher = { ...matcher };
@@ -363,9 +387,13 @@ async function buildAppRouteGraph(appDir, matcher) {
363
387
  const dir = path.posix.dirname(file);
364
388
  const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
365
389
  if (!hasParallelSlotDirectory(routeDir)) continue;
366
- if (discoverParallelSlots(routeDir, appDir, scanMatcher).length === 0) continue;
367
- const route = directoryToAppRoute(dir, appDir, scanMatcher, null, null);
390
+ if (discoverParallelSlots(routeDir, appDir, scanMatcher, true).length === 0) continue;
391
+ const route = directoryToAppRoute(dir, appDir, scanMatcher, null, null, true);
368
392
  if (!route) continue;
393
+ if (routes.some((candidate) => candidate.patternParts.length === route.patternParts.length + 1 && candidate.patternParts.at(-1)?.endsWith("*") && patternsStructurallyEquivalent(candidate.patternParts.slice(0, -1), route.patternParts))) {
394
+ ghostParentRoutes.push(route);
395
+ continue;
396
+ }
369
397
  if (routePatterns.has(route.pattern)) {
370
398
  ghostParentRoutes.push(route);
371
399
  continue;
@@ -412,9 +440,9 @@ function validatePageRouteConflicts(routes, appDir) {
412
440
  }
413
441
  }
414
442
  function formatAppFilePath(filePath, appDir) {
415
- const relativePath = path.relative(appDir, filePath).replace(/\\/g, "/");
443
+ const relativePath = normalizePathSeparators(path.relative(appDir, filePath));
416
444
  const parsedPath = path.parse(relativePath);
417
- const withoutExtension = path.join(parsedPath.dir, parsedPath.name).replace(/\\/g, "/");
445
+ const withoutExtension = normalizePathSeparators(path.join(parsedPath.dir, parsedPath.name));
418
446
  return withoutExtension.startsWith("/") ? withoutExtension : `/${withoutExtension}`;
419
447
  }
420
448
  /**
@@ -482,8 +510,29 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
482
510
  }
483
511
  }
484
512
  if (subPathMap.size === 0) continue;
513
+ const childrenOwnerTreePath = parentRoute.parallelSlots.find((slot) => path.dirname(slot.ownerDir) === parentPageDir)?.ownerTreePath;
514
+ if (!childrenOwnerTreePath) throw new Error(`[vinext] App route graph invariant violated: missing children slot owner for ${parentRoute.pattern}`);
485
515
  const childrenDefault = findFile(parentPageDir, "default", matcher);
486
516
  if (parentRoute.pagePath && !childrenDefault) continue;
517
+ const childrenSlotId = createAppRouteGraphSlotId("children", childrenOwnerTreePath);
518
+ if (parentRoute.pagePath) parentRoute.childrenSlot = {
519
+ id: childrenSlotId,
520
+ ownerTreePath: childrenOwnerTreePath,
521
+ state: "active"
522
+ };
523
+ for (const route of routes) {
524
+ if (!route.pagePath || route === parentRoute) continue;
525
+ const relativePageDir = path.relative(parentPageDir, path.dirname(route.pagePath));
526
+ if (relativePageDir === "" || relativePageDir === ".." || relativePageDir.startsWith(`..${path.sep}`) || path.isAbsolute(relativePageDir)) continue;
527
+ const existingOwnerDepth = route.childrenSlot?.ownerTreePath.split("/").filter(Boolean).length;
528
+ const candidateOwnerDepth = childrenOwnerTreePath.split("/").filter(Boolean).length;
529
+ if (existingOwnerDepth !== void 0 && existingOwnerDepth >= candidateOwnerDepth) continue;
530
+ route.childrenSlot = {
531
+ id: childrenSlotId,
532
+ ownerTreePath: childrenOwnerTreePath,
533
+ state: "active"
534
+ };
535
+ }
487
536
  const childrenCatchAll = childrenDefault ? null : findCatchAllPage(parentPageDir, matcher);
488
537
  const childrenFallback = childrenDefault ?? childrenCatchAll;
489
538
  for (const { rawSegments, converted: convertedSubRoute, slotPages } of subPathMap.values()) {
@@ -525,6 +574,11 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
525
574
  layouts: parentRoute.layouts,
526
575
  templates: parentRoute.templates,
527
576
  parallelSlots: subSlots,
577
+ childrenSlot: {
578
+ id: childrenSlotId,
579
+ ownerTreePath: childrenOwnerTreePath,
580
+ state: childrenDefault ? "default" : childrenCatchAll ? "active" : "unmatched"
581
+ },
528
582
  loadingPath: parentRoute.loadingPath,
529
583
  errorPath: parentRoute.errorPath,
530
584
  layoutErrorPaths: parentRoute.layoutErrorPaths,
@@ -535,6 +589,7 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
535
589
  unauthorizedPath: parentRoute.unauthorizedPath,
536
590
  unauthorizedPaths: parentRoute.unauthorizedPaths,
537
591
  routeSegments: [...parentRoute.routeSegments, ...rawSegments],
592
+ childrenRouteSegments: childrenDefault ? parentRoute.routeSegments : void 0,
538
593
  templateTreePositions: parentRoute.templateTreePositions,
539
594
  layoutTreePositions: parentRoute.layoutTreePositions,
540
595
  isDynamic: parentRoute.isDynamic || subIsDynamic,
@@ -549,6 +604,26 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
549
604
  }
550
605
  return syntheticRoutes;
551
606
  }
607
+ const dirEntriesCache = /* @__PURE__ */ new WeakMap();
608
+ function readDirEntriesCached(dir, matcher) {
609
+ let perMatcher = dirEntriesCache.get(matcher);
610
+ if (!perMatcher) {
611
+ perMatcher = /* @__PURE__ */ new Map();
612
+ dirEntriesCache.set(matcher, perMatcher);
613
+ }
614
+ let entries = perMatcher.get(dir);
615
+ if (entries === void 0) {
616
+ try {
617
+ entries = fs.readdirSync(dir, { withFileTypes: true });
618
+ } catch (error) {
619
+ const code = error.code;
620
+ if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
621
+ entries = [];
622
+ }
623
+ perMatcher.set(dir, entries);
624
+ }
625
+ return entries;
626
+ }
552
627
  const findSlotSubPagesCache = /* @__PURE__ */ new WeakMap();
553
628
  function findSlotSubPages(slotDir, matcher) {
554
629
  let perMatcher = findSlotSubPagesCache.get(matcher);
@@ -629,23 +704,29 @@ function findCatchAllPage(dir, matcher) {
629
704
  }
630
705
  /**
631
706
  * Convert a file path relative to app/ into an AppRoute.
707
+ *
708
+ * `file` and `appDir` must be forward-slash. `file` comes from
709
+ * `scanWithExtensions` (already forward-slash) and is joined onto `appDir` with
710
+ * `path.posix.join` to form the page/route path, so a native input would
711
+ * produce a mixed separator on Windows.
632
712
  */
633
713
  function fileToAppRoute(file, appDir, type, matcher) {
634
- let dir = path.dirname(file);
635
- if (type === "page" && dir !== "." && path.basename(dir) === "@children") {
636
- const parent = path.dirname(dir);
714
+ let dir = path.posix.dirname(file);
715
+ if (type === "page" && dir !== "." && path.posix.basename(dir) === "@children") {
716
+ const parent = path.posix.dirname(dir);
637
717
  dir = parent === "" || parent === "." ? "." : parent;
638
718
  }
639
- return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.join(appDir, file) : null, type === "route" ? path.join(appDir, file) : null);
719
+ return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.posix.join(appDir, file) : null, type === "route" ? path.posix.join(appDir, file) : null);
640
720
  }
641
721
  /**
642
- * `dir` and `appDir` must both be forward-slash. `dir` is split on
643
- * `path.posix.sep` and joined onto `appDir` with `path.posix.join`, and `appDir`
644
- * is threaded to the layout/slot/boundary discovery below, which build paths the
645
- * same way.
722
+ * `dir`, `appDir`, `pagePath`, and `routePath` must all be forward-slash. `dir`
723
+ * is split on `path.posix.sep` and joined onto `appDir` with `path.posix.join`.
724
+ * `appDir` is threaded to the layout/slot/boundary discovery below, which builds
725
+ * paths the same way. `pagePath` and `routePath` are stored on the route node as
726
+ * canonical ids that get compared and re-joined downstream.
646
727
  */
647
- function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
648
- const segments = dir === "." ? [] : dir.split(path.posix.sep);
728
+ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath, includeNestedOnlySlots = false) {
729
+ const segments = dir === "." ? [] : dir.split("/");
649
730
  const params = [];
650
731
  let isDynamic = false;
651
732
  const convertedRoute = convertSegmentsToRouteParts(segments);
@@ -663,6 +744,7 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
663
744
  const errorPaths = errorEntries.map((entry) => entry.path);
664
745
  const errorTreePositions = errorEntries.map((entry) => entry.treePosition);
665
746
  const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
747
+ const effectivePagePath = pagePath ?? (routePath ? null : findFile(routeDir, "default", matcher));
666
748
  const loadingPath = findFile(routeDir, "loading", matcher);
667
749
  const errorPath = findFile(routeDir, "error", matcher);
668
750
  const notFoundPath = discoverBoundaryFile(segments, appDir, "not-found", matcher);
@@ -671,11 +753,11 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
671
753
  const notFoundPaths = discoverBoundaryFilePerLayout(layouts, "not-found", matcher);
672
754
  const forbiddenPaths = discoverBoundaryFilePerLayout(layouts, "forbidden", matcher);
673
755
  const unauthorizedPaths = discoverBoundaryFilePerLayout(layouts, "unauthorized", matcher);
674
- const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher);
756
+ const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher, includeNestedOnlySlots);
675
757
  return {
676
758
  ids: createAppRouteSemanticIds({
677
759
  pattern: pattern === "/" ? "/" : pattern,
678
- pagePath,
760
+ pagePath: effectivePagePath,
679
761
  routePath,
680
762
  routeSegments: segments,
681
763
  layoutTreePositions,
@@ -683,7 +765,7 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
683
765
  slots: parallelSlots
684
766
  }),
685
767
  pattern: pattern === "/" ? "/" : pattern,
686
- pagePath,
768
+ pagePath: effectivePagePath,
687
769
  routePath,
688
770
  layouts,
689
771
  templates,
@@ -899,7 +981,7 @@ function discoverBoundaryFilePerLayout(layouts, fileName, matcher) {
899
981
  * `appDir` via `path.posix.join`, and the `dir === routeDir` active-level test
900
982
  * below only matches when both share the canonical separator.
901
983
  */
902
- function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
984
+ function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher, includeNestedOnlySlots = false) {
903
985
  const slotMap = /* @__PURE__ */ new Map();
904
986
  let currentDir = appDir;
905
987
  const dirsToCheck = [];
@@ -922,9 +1004,9 @@ function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
922
1004
  for (const { dir, layoutIdx: lvlLayoutIdx, segmentIndex } of dirsToCheck) {
923
1005
  if (lvlLayoutIdx < 0 && routeHasLayout) continue;
924
1006
  const slotLayoutIdx = Math.max(lvlLayoutIdx, 0);
925
- const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher);
926
1007
  const segmentsBelow = segments.slice(segmentIndex);
927
1008
  const isActiveUrlLevel = dir === routeDir || segmentsBelow.every(isInvisibleSegment);
1009
+ const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher, includeNestedOnlySlots && isActiveUrlLevel);
928
1010
  for (const slot of slotsAtLevel) if (isActiveUrlLevel) {
929
1011
  slot.layoutIndex = slotLayoutIdx;
930
1012
  slotMap.set(slot.key, slot);
@@ -1083,12 +1165,7 @@ function patternsStructurallyEquivalent(a, b) {
1083
1165
  function findSlotRootPage(slotDir, matcher) {
1084
1166
  const directPage = findFile(slotDir, "page", matcher);
1085
1167
  if (directPage) return directPage;
1086
- let entries;
1087
- try {
1088
- entries = fs.readdirSync(slotDir, { withFileTypes: true });
1089
- } catch {
1090
- return null;
1091
- }
1168
+ const entries = readDirEntriesCached(slotDir, matcher);
1092
1169
  for (const entry of entries) {
1093
1170
  if (!entry.isDirectory()) continue;
1094
1171
  if (!entry.name.startsWith("(") || !entry.name.endsWith(")")) continue;
@@ -1099,11 +1176,14 @@ function findSlotRootPage(slotDir, matcher) {
1099
1176
  }
1100
1177
  /**
1101
1178
  * Discover parallel route slots (@team, @analytics, etc.) in a directory.
1102
- * Returns a ParallelSlot for each @-prefixed subdirectory that has a page or default component.
1179
+ * Returns a ParallelSlot for each @-prefixed subdirectory that has a page,
1180
+ * default component, intercepting route, or nested page-backed sub-route.
1181
+ *
1182
+ * `dir` and `appDir` must be forward-slash. The slot directory is built from
1183
+ * `dir` with `path.posix.join`.
1103
1184
  */
1104
- function discoverParallelSlots(dir, appDir, matcher) {
1105
- if (!fs.existsSync(dir)) return [];
1106
- const entries = fs.readdirSync(dir, { withFileTypes: true });
1185
+ function discoverParallelSlots(dir, appDir, matcher, includeNestedOnlySlots = false) {
1186
+ const entries = readDirEntriesCached(dir, matcher);
1107
1187
  const slots = [];
1108
1188
  for (const entry of entries) {
1109
1189
  if (!entry.isDirectory() || !entry.name.startsWith("@")) continue;
@@ -1113,13 +1193,14 @@ function discoverParallelSlots(dir, appDir, matcher) {
1113
1193
  const pagePath = findSlotRootPage(slotDir, matcher);
1114
1194
  const defaultPath = findFile(slotDir, "default", matcher);
1115
1195
  const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);
1116
- if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;
1196
+ const hasNestedPages = includeNestedOnlySlots && findSlotSubPages(slotDir, matcher).length > 0;
1197
+ if (!pagePath && !defaultPath && interceptingRoutes.length === 0 && !hasNestedPages) continue;
1117
1198
  const ownerSegments = path.relative(appDir, dir).split(path.sep).filter((segment) => segment.length > 0);
1118
1199
  const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);
1119
1200
  const configLayoutPaths = findSlotConfigLayoutPaths(slotDir, pagePath, matcher);
1120
1201
  slots.push({
1121
1202
  id: createAppRouteGraphSlotId(slotName, ownerTreePath),
1122
- key: `${slotName}@${path.relative(appDir, slotDir).replace(/\\/g, "/")}`,
1203
+ key: `${slotName}@${normalizePathSeparators(path.relative(appDir, slotDir))}`,
1123
1204
  name: slotName,
1124
1205
  ownerDir: slotDir,
1125
1206
  ownerTreePath,
@@ -1178,6 +1259,9 @@ function isInterceptionMarkerDir(name) {
1178
1259
  * Intercepting routes use conventions like (.)photo, (..)feed, (...), etc.
1179
1260
  * They intercept navigation to another route and render within the slot instead.
1180
1261
  *
1262
+ * `slotDir`, `routeDir`, and `appDir` must be forward-slash. They are passed
1263
+ * down to `path.posix.join` when building the intercept page paths.
1264
+ *
1181
1265
  * @param slotDir - The parallel slot directory (e.g. app/feed/@modal)
1182
1266
  * @param routeDir - The directory of the route that owns this slot (e.g. app/feed)
1183
1267
  * @param appDir - The root app directory
@@ -1196,13 +1280,17 @@ function discoverInterceptingRoutes(slotDir, routeDir, appDir, matcher) {
1196
1280
  * Sibling intercepts use the same conventions and target-computation logic as
1197
1281
  * slot intercepts, but their intercepting page replaces the full page response
1198
1282
  * (not a slot) during soft navigation.
1283
+ *
1284
+ * `appDir` and each route's `pagePath` / `routePath` must be forward-slash. The
1285
+ * owner directories are derived from `pagePath` / `routePath` and matched
1286
+ * against `appDir`-relative paths built with `path.posix.*`.
1199
1287
  */
1200
1288
  function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
1201
1289
  const routesByDir = /* @__PURE__ */ new Map();
1202
1290
  for (const route of routes) {
1203
1291
  const filePath = route.pagePath ?? route.routePath;
1204
1292
  if (!filePath) continue;
1205
- const routeDir = normalizePathSeparators(path.dirname(filePath));
1293
+ const routeDir = path.posix.dirname(filePath);
1206
1294
  if (!routesByDir.has(routeDir)) routesByDir.set(routeDir, route);
1207
1295
  }
1208
1296
  function walk(dir) {
@@ -1216,7 +1304,7 @@ function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
1216
1304
  if (!entry.isDirectory()) continue;
1217
1305
  if (entry.name.startsWith("_")) continue;
1218
1306
  if (entry.name.startsWith("@")) continue;
1219
- const childDir = path.join(dir, entry.name);
1307
+ const childDir = path.posix.join(dir, entry.name);
1220
1308
  const marker = matchInterceptConvention(entry.name);
1221
1309
  if (marker) {
1222
1310
  const restOfName = entry.name.slice(marker.prefix.length);
@@ -1281,6 +1369,9 @@ function findOwnerRouteForDir(dir, appDir, routes, routesByDir) {
1281
1369
  /**
1282
1370
  * Recursively scan a directory tree for page.tsx files that are inside
1283
1371
  * intercepting route directories.
1372
+ *
1373
+ * `currentDir`, `routeDir`, and `appDir` must be forward-slash. `currentDir`
1374
+ * descends with `path.posix.join` when building the intercept page paths.
1284
1375
  */
1285
1376
  function scanForInterceptingPages(currentDir, routeDir, appDir, results, matcher) {
1286
1377
  if (!fs.existsSync(currentDir)) return;
@@ -1289,11 +1380,11 @@ function scanForInterceptingPages(currentDir, routeDir, appDir, results, matcher
1289
1380
  if (!entry.isDirectory()) continue;
1290
1381
  if (entry.name.startsWith("_")) continue;
1291
1382
  const interceptMatch = matchInterceptConvention(entry.name);
1383
+ const interceptDir = path.posix.join(currentDir, entry.name);
1292
1384
  if (interceptMatch) {
1293
1385
  const restOfName = entry.name.slice(interceptMatch.prefix.length);
1294
- const interceptDir = path.join(currentDir, entry.name);
1295
1386
  collectInterceptingPages(interceptDir, interceptDir, interceptMatch.convention, restOfName, routeDir, appDir, currentDir, results, matcher);
1296
- } else scanForInterceptingPages(path.join(currentDir, entry.name), routeDir, appDir, results, matcher);
1387
+ } else scanForInterceptingPages(interceptDir, routeDir, appDir, results, matcher);
1297
1388
  }
1298
1389
  }
1299
1390
  /**
@@ -1306,6 +1397,12 @@ function matchInterceptConvention(name) {
1306
1397
  /**
1307
1398
  * Collect page.tsx files inside an intercepting route directory tree
1308
1399
  * and compute their target URL patterns.
1400
+ *
1401
+ * `currentDir`, `interceptRoot`, `routeDir`, `appDir`, and `interceptParentDir`
1402
+ * must all be forward-slash. `currentDir` descends with `path.posix.join` and
1403
+ * its `findFile` results become the stored layout/page paths. The others are
1404
+ * relativized against `appDir` (and each other) to derive the intercept page
1405
+ * segments and URL patterns.
1309
1406
  */
1310
1407
  function collectInterceptingPages(currentDir, interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, parentLayoutPaths = []) {
1311
1408
  const currentLayoutPath = findFile(currentDir, "layout", matcher);
@@ -1316,7 +1413,7 @@ function collectInterceptingPages(currentDir, interceptRoot, convention, interce
1316
1413
  if (targetPattern) {
1317
1414
  const sourceMatchPattern = computeInterceptSourceMatchPattern(interceptParentDir, appDir);
1318
1415
  results.push({
1319
- branchSegments: [interceptSegment, ...normalizePathSeparators(path.relative(interceptRoot, path.dirname(page))).split("/").filter(Boolean)],
1416
+ branchSegments: [interceptSegment, ...path.relative(interceptRoot, path.dirname(page)).split(path.sep).filter(Boolean)],
1320
1417
  convention,
1321
1418
  layoutPaths: [...layoutPaths],
1322
1419
  layoutSegments: layoutPaths.map((layoutPath) => {
@@ -1335,7 +1432,7 @@ function collectInterceptingPages(currentDir, interceptRoot, convention, interce
1335
1432
  for (const entry of entries) {
1336
1433
  if (!entry.isDirectory()) continue;
1337
1434
  if (entry.name.startsWith("_")) continue;
1338
- collectInterceptingPages(path.join(currentDir, entry.name), interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, layoutPaths);
1435
+ collectInterceptingPages(path.posix.join(currentDir, entry.name), interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, layoutPaths);
1339
1436
  }
1340
1437
  }
1341
1438
  /**
@@ -1455,6 +1552,9 @@ const findFileProbeCache = /* @__PURE__ */ new WeakMap();
1455
1552
  * registered per-scan cache; otherwise falls back to a direct probe (identical
1456
1553
  * result). The `null` "not found" outcome is cached too, so repeated misses on
1457
1554
  * shared ancestors cost a single set of `existsSync` calls per scan.
1555
+ *
1556
+ * `dir` must be forward-slash. The returned path comes from `findFileWithExts`,
1557
+ * so it is forward-slash too.
1458
1558
  */
1459
1559
  function findFile(dir, name, matcher) {
1460
1560
  const cache = findFileProbeCache.get(matcher);
@@ -21,6 +21,9 @@ 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.
24
27
  */
25
28
  declare function findFileWithExts(dir: string, name: string, matcher: ValidFileMatcher): string | null;
26
29
  /**
@@ -36,11 +39,18 @@ declare function findFileWithExts(dir: string, name: string, matcher: ValidFileM
36
39
  * 1. User-configured pageExtensions go first (each prefixed with `.`) so
37
40
  * the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
38
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'".
39
48
  *
40
49
  * The user's pageExtensions retain their relative order, which is what
41
50
  * Next.js / Turbopack do via the `resolveExtensions` config option.
42
51
  *
43
- * See: cloudflare/vinext#1502
52
+ * See: cloudflare/vinext#1502 for page-extension ordering, and
53
+ * cloudflare/vinext#2435 for extensionless `.cjs` config imports.
44
54
  */
45
55
  declare function buildViteResolveExtensions(pageExtensions?: readonly string[] | null, viteDefaults?: readonly string[]): string[];
46
56
  /**
@@ -1,5 +1,5 @@
1
- import { escapeRegExp } from "../utils/regex.js";
2
1
  import { normalizePathSeparators } from "../utils/path.js";
2
+ import { escapeRegExp } from "../utils/regex.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { glob } from "node:fs/promises";
@@ -67,6 +67,9 @@ function findFileWithExtensions(basePath, matcher) {
67
67
  /**
68
68
  * Find a file by basename and configured page extension in a directory.
69
69
  * 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.
70
73
  */
71
74
  function findFileWithExts(dir, name, matcher) {
72
75
  for (const ext of matcher.dottedExtensions) {
@@ -88,11 +91,18 @@ function findFileWithExts(dir, name, matcher) {
88
91
  * 1. User-configured pageExtensions go first (each prefixed with `.`) so
89
92
  * the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
90
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'".
91
100
  *
92
101
  * The user's pageExtensions retain their relative order, which is what
93
102
  * Next.js / Turbopack do via the `resolveExtensions` config option.
94
103
  *
95
- * See: cloudflare/vinext#1502
104
+ * See: cloudflare/vinext#1502 for page-extension ordering, and
105
+ * cloudflare/vinext#2435 for extensionless `.cjs` config imports.
96
106
  */
97
107
  function buildViteResolveExtensions(pageExtensions, viteDefaults = [
98
108
  ".mjs",
@@ -106,7 +116,12 @@ function buildViteResolveExtensions(pageExtensions, viteDefaults = [
106
116
  const dotted = normalizePageExtensions(pageExtensions).map((ext) => `.${ext}`);
107
117
  const seen = /* @__PURE__ */ new Set();
108
118
  const result = [];
109
- for (const ext of [...dotted, ...viteDefaults]) {
119
+ for (const ext of [
120
+ ...dotted,
121
+ ...viteDefaults,
122
+ ".cjs",
123
+ ".cts"
124
+ ]) {
110
125
  if (seen.has(ext)) continue;
111
126
  seen.add(ext);
112
127
  result.push(ext);
@@ -63,7 +63,7 @@ async function scanPageRoutes(pagesDir, matcher) {
63
63
  function fileToRoute(file, pagesDir, matcher) {
64
64
  const withoutExt = matcher.stripExtension(file);
65
65
  if (withoutExt === file) return null;
66
- const segments = withoutExt.split(path.sep);
66
+ const segments = withoutExt.split("/");
67
67
  if (segments[segments.length - 1] === "index") segments.pop();
68
68
  const params = [];
69
69
  let isDynamic = false;
@@ -152,7 +152,7 @@ async function scanApiRoutes(pagesDir, matcher) {
152
152
  }
153
153
  const routes = [];
154
154
  for (const file of files) {
155
- const route = fileToRoute(path.join("api", file), pagesDir, matcher);
155
+ const route = fileToRoute(path.posix.join("api", file), pagesDir, matcher);
156
156
  if (route) routes.push(route);
157
157
  }
158
158
  validateRoutePatterns(routes.map((route) => route.pattern));
@@ -1,15 +1,15 @@
1
1
  import { hasBasePath } from "../utils/base-path.js";
2
2
  import { matchRoute } from "../routing/pages-router.js";
3
3
  import "./server-globals.js";
4
- import { parseCookieHeader } from "../utils/parse-cookie.js";
5
4
  import { NextRequest } from "../shims/server.js";
6
5
  import { importModule, reportRequestError } from "./instrumentation.js";
7
6
  import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
8
- import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
9
- import { isEdgeApiRuntime } from "./edge-api-runtime.js";
10
7
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT, resolveBodyParserConfig } from "./pages-body-parser-config.js";
8
+ import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
11
9
  import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
12
10
  import { performOnDemandRevalidate } from "./pages-revalidate.js";
11
+ import { attachPagesRequestCookies } from "./pages-node-compat.js";
12
+ import { isEdgeApiRuntime } from "./edge-api-runtime.js";
13
13
  import { decode } from "node:querystring";
14
14
  import { Buffer } from "node:buffer";
15
15
  //#region src/server/api-handler.ts
@@ -69,12 +69,6 @@ async function parseBody(req, sizeLimit = MAX_BODY_SIZE) {
69
69
  });
70
70
  });
71
71
  }
72
- /**
73
- * Parse cookies from the Cookie header.
74
- */
75
- function parseCookies(req) {
76
- return parseCookieHeader(req.headers.cookie);
77
- }
78
72
  function isEdgeApiRouteModule(module) {
79
73
  if (typeof module.default !== "function") return false;
80
74
  const bare = module.runtime;
@@ -167,12 +161,13 @@ async function writeEdgeApiResponseBody(res, body) {
167
161
  * Enhance a Node.js req/res pair with Next.js API route helpers.
168
162
  */
169
163
  function enhanceApiObjects(req, res, query, body) {
164
+ const apiReq = Object.assign(req, {
165
+ body,
166
+ query
167
+ });
168
+ attachPagesRequestCookies(apiReq);
170
169
  return {
171
- apiReq: Object.assign(req, {
172
- body,
173
- cookies: parseCookies(req),
174
- query
175
- }),
170
+ apiReq,
176
171
  apiRes: Object.assign(res, {
177
172
  status(code) {
178
173
  this.statusCode = code;
@@ -1,3 +1,4 @@
1
+ import { OperationLane } from "./operation-token.js";
1
2
  import { ServerActionResultFacts } from "./navigation-planner.js";
2
3
 
3
4
  //#region src/server/app-browser-action-result.d.ts
@@ -24,7 +25,9 @@ type ServerActionInitiationSnapshot<TRouterState> = {
24
25
  declare function isServerActionResult<TRoot>(value: unknown): value is AppBrowserServerActionResult<TRoot>;
25
26
  declare function shouldClearClientNavigationCachesForServerActionResult<TRoot>(result: AppBrowserServerActionResult<TRoot> | TRoot, revalidation?: ServerActionRevalidationKind): boolean;
26
27
  declare function parseServerActionRevalidationHeader(headers: Pick<Headers, "get">): ServerActionRevalidationKind;
28
+ declare function resolveServerActionOperationLane(revalidation: ServerActionRevalidationKind): Extract<OperationLane, "refresh" | "server-action">;
27
29
  declare function normalizeServerActionThrownValue(data: unknown, responseStatus: number): unknown;
30
+ declare function shouldSyncServerActionHttpFallbackHead<TRoot>(result: AppBrowserServerActionResult<TRoot> | TRoot): boolean;
28
31
  declare function readInvalidServerActionResponseError(response: Pick<Response, "headers" | "status" | "text">, hasRedirectLocation: boolean): Promise<Error | null>;
29
32
  type ServerActionResultResponseFactsInput = {
30
33
  actionRedirectHref: string | null;
@@ -61,4 +64,4 @@ type DiscardedServerActionRefreshSchedulerOptions = {
61
64
  };
62
65
  declare function createDiscardedServerActionRefreshScheduler(options: DiscardedServerActionRefreshSchedulerOptions): DiscardedServerActionRefreshScheduler;
63
66
  //#endregion
64
- export { AppBrowserServerActionResult, ServerActionResultResponseFactsInput, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
67
+ export { AppBrowserServerActionResult, ServerActionResultResponseFactsInput, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionOperationLane, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction, shouldSyncServerActionHttpFallbackHead };
@@ -32,6 +32,9 @@ function parseServerActionRevalidationHeader(headers) {
32
32
  default: return "none";
33
33
  }
34
34
  }
35
+ function resolveServerActionOperationLane(revalidation) {
36
+ return revalidation === "none" ? "server-action" : "refresh";
37
+ }
35
38
  function createServerActionHttpFallbackError(status) {
36
39
  if (status !== 401 && status !== 403 && status !== 404) return null;
37
40
  const digest = status === 404 ? "NEXT_HTTP_ERROR_FALLBACK;404" : `NEXT_HTTP_ERROR_FALLBACK;${status}`;
@@ -41,6 +44,10 @@ function createServerActionHttpFallbackError(status) {
41
44
  function normalizeServerActionThrownValue(data, responseStatus) {
42
45
  return createServerActionHttpFallbackError(responseStatus) ?? data;
43
46
  }
47
+ function shouldSyncServerActionHttpFallbackHead(result) {
48
+ if (!isServerActionResult(result) || result.root !== void 0) return false;
49
+ return result.returnValue?.ok !== false;
50
+ }
44
51
  async function readInvalidServerActionResponseError(response, hasRedirectLocation) {
45
52
  const contentType = response.headers.get("content-type") ?? "";
46
53
  if (contentType.startsWith("text/x-component") || hasRedirectLocation) return null;
@@ -108,4 +115,4 @@ function createDiscardedServerActionRefreshScheduler(options) {
108
115
  };
109
116
  }
110
117
  //#endregion
111
- export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
118
+ export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionOperationLane, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction, shouldSyncServerActionHttpFallbackHead };