vinext 0.0.52 → 0.0.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +1 -1
  2. package/dist/build/clean-output.d.ts +14 -0
  3. package/dist/build/clean-output.js +36 -0
  4. package/dist/build/clean-output.js.map +1 -0
  5. package/dist/build/prerender.d.ts +6 -2
  6. package/dist/build/prerender.js +49 -11
  7. package/dist/build/prerender.js.map +1 -1
  8. package/dist/build/run-prerender.js +10 -1
  9. package/dist/build/run-prerender.js.map +1 -1
  10. package/dist/build/static-export.d.ts +5 -0
  11. package/dist/build/static-export.js +8 -3
  12. package/dist/build/static-export.js.map +1 -1
  13. package/dist/cli.js +19 -4
  14. package/dist/cli.js.map +1 -1
  15. package/dist/client/instrumentation-client-inject.d.ts +34 -0
  16. package/dist/client/instrumentation-client-inject.js +57 -0
  17. package/dist/client/instrumentation-client-inject.js.map +1 -0
  18. package/dist/client/navigation-runtime.d.ts +14 -1
  19. package/dist/client/navigation-runtime.js +16 -1
  20. package/dist/client/navigation-runtime.js.map +1 -1
  21. package/dist/client/vinext-next-data.d.ts +2 -1
  22. package/dist/client/vinext-next-data.js.map +1 -1
  23. package/dist/client/window-next.d.ts +10 -2
  24. package/dist/client/window-next.js.map +1 -1
  25. package/dist/cloudflare/tpr.js +1 -1
  26. package/dist/cloudflare/tpr.js.map +1 -1
  27. package/dist/config/config-matchers.js +2 -1
  28. package/dist/config/config-matchers.js.map +1 -1
  29. package/dist/config/next-config.d.ts +12 -3
  30. package/dist/config/next-config.js +44 -14
  31. package/dist/config/next-config.js.map +1 -1
  32. package/dist/deploy.js +29 -7
  33. package/dist/deploy.js.map +1 -1
  34. package/dist/entries/app-rsc-entry.d.ts +4 -2
  35. package/dist/entries/app-rsc-entry.js +23 -3
  36. package/dist/entries/app-rsc-entry.js.map +1 -1
  37. package/dist/entries/pages-client-entry.js +22 -1
  38. package/dist/entries/pages-client-entry.js.map +1 -1
  39. package/dist/entries/pages-server-entry.js +211 -31
  40. package/dist/entries/pages-server-entry.js.map +1 -1
  41. package/dist/index.js +29 -6
  42. package/dist/index.js.map +1 -1
  43. package/dist/plugins/fonts.js +25 -2
  44. package/dist/plugins/fonts.js.map +1 -1
  45. package/dist/routing/route-trie.js +13 -18
  46. package/dist/routing/route-trie.js.map +1 -1
  47. package/dist/routing/utils.d.ts +11 -1
  48. package/dist/routing/utils.js +15 -1
  49. package/dist/routing/utils.js.map +1 -1
  50. package/dist/server/api-handler.js +18 -9
  51. package/dist/server/api-handler.js.map +1 -1
  52. package/dist/server/app-browser-action-result.d.ts +16 -1
  53. package/dist/server/app-browser-action-result.js +15 -1
  54. package/dist/server/app-browser-action-result.js.map +1 -1
  55. package/dist/server/app-browser-entry.js +22 -12
  56. package/dist/server/app-browser-entry.js.map +1 -1
  57. package/dist/server/app-elements.js +1 -1
  58. package/dist/server/app-fallback-renderer.d.ts +12 -3
  59. package/dist/server/app-fallback-renderer.js +10 -5
  60. package/dist/server/app-fallback-renderer.js.map +1 -1
  61. package/dist/server/app-history-state.js +6 -2
  62. package/dist/server/app-history-state.js.map +1 -1
  63. package/dist/server/app-interception-context-header.d.ts +33 -0
  64. package/dist/server/app-interception-context-header.js +44 -0
  65. package/dist/server/app-interception-context-header.js.map +1 -0
  66. package/dist/server/app-mounted-slots-header.d.ts +19 -0
  67. package/dist/server/app-mounted-slots-header.js +40 -1
  68. package/dist/server/app-mounted-slots-header.js.map +1 -1
  69. package/dist/server/app-optimistic-routing.js +26 -18
  70. package/dist/server/app-optimistic-routing.js.map +1 -1
  71. package/dist/server/app-page-boundary-render.d.ts +1 -0
  72. package/dist/server/app-page-boundary-render.js +2 -0
  73. package/dist/server/app-page-boundary-render.js.map +1 -1
  74. package/dist/server/app-page-boundary.d.ts +1 -0
  75. package/dist/server/app-page-boundary.js +2 -0
  76. package/dist/server/app-page-boundary.js.map +1 -1
  77. package/dist/server/app-page-cache.d.ts +2 -0
  78. package/dist/server/app-page-cache.js +7 -1
  79. package/dist/server/app-page-cache.js.map +1 -1
  80. package/dist/server/app-page-dispatch.d.ts +3 -0
  81. package/dist/server/app-page-dispatch.js +11 -4
  82. package/dist/server/app-page-dispatch.js.map +1 -1
  83. package/dist/server/app-page-element-builder.d.ts +2 -1
  84. package/dist/server/app-page-element-builder.js +5 -2
  85. package/dist/server/app-page-element-builder.js.map +1 -1
  86. package/dist/server/app-page-execution.d.ts +1 -0
  87. package/dist/server/app-page-execution.js +2 -0
  88. package/dist/server/app-page-execution.js.map +1 -1
  89. package/dist/server/app-page-head.d.ts +1 -0
  90. package/dist/server/app-page-head.js +8 -0
  91. package/dist/server/app-page-head.js.map +1 -1
  92. package/dist/server/app-page-render-observation.js +1 -1
  93. package/dist/server/app-page-render.d.ts +1 -0
  94. package/dist/server/app-page-render.js +5 -2
  95. package/dist/server/app-page-render.js.map +1 -1
  96. package/dist/server/app-page-response.d.ts +11 -1
  97. package/dist/server/app-page-response.js +14 -2
  98. package/dist/server/app-page-response.js.map +1 -1
  99. package/dist/server/app-page-route-wiring.d.ts +1 -0
  100. package/dist/server/app-page-route-wiring.js +19 -6
  101. package/dist/server/app-page-route-wiring.js.map +1 -1
  102. package/dist/server/app-page-stream.d.ts +1 -0
  103. package/dist/server/app-page-stream.js +2 -0
  104. package/dist/server/app-page-stream.js.map +1 -1
  105. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  106. package/dist/server/app-route-handler-dispatch.js +3 -0
  107. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  108. package/dist/server/app-route-handler-execution.d.ts +1 -0
  109. package/dist/server/app-route-handler-execution.js +1 -0
  110. package/dist/server/app-route-handler-execution.js.map +1 -1
  111. package/dist/server/app-route-handler-response.js +1 -1
  112. package/dist/server/app-rsc-handler.d.ts +2 -0
  113. package/dist/server/app-rsc-handler.js +18 -9
  114. package/dist/server/app-rsc-handler.js.map +1 -1
  115. package/dist/server/app-rsc-request-normalization.js +3 -2
  116. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  117. package/dist/server/app-segment-config.d.ts +4 -1
  118. package/dist/server/app-segment-config.js +6 -1
  119. package/dist/server/app-segment-config.js.map +1 -1
  120. package/dist/server/app-server-action-execution.d.ts +1 -0
  121. package/dist/server/app-server-action-execution.js +4 -0
  122. package/dist/server/app-server-action-execution.js.map +1 -1
  123. package/dist/server/app-ssr-entry.js +39 -3
  124. package/dist/server/app-ssr-entry.js.map +1 -1
  125. package/dist/server/app-ssr-stream.d.ts +24 -1
  126. package/dist/server/app-ssr-stream.js +78 -5
  127. package/dist/server/app-ssr-stream.js.map +1 -1
  128. package/dist/server/app-static-generation.d.ts +1 -0
  129. package/dist/server/app-static-generation.js +2 -1
  130. package/dist/server/app-static-generation.js.map +1 -1
  131. package/dist/server/default-not-found-module.d.ts +20 -0
  132. package/dist/server/default-not-found-module.js +20 -0
  133. package/dist/server/default-not-found-module.js.map +1 -0
  134. package/dist/server/dev-server.d.ts +1 -1
  135. package/dist/server/dev-server.js +23 -7
  136. package/dist/server/dev-server.js.map +1 -1
  137. package/dist/server/headers.d.ts +5 -1
  138. package/dist/server/headers.js +5 -1
  139. package/dist/server/headers.js.map +1 -1
  140. package/dist/server/image-optimization.d.ts +13 -4
  141. package/dist/server/image-optimization.js +15 -4
  142. package/dist/server/image-optimization.js.map +1 -1
  143. package/dist/server/middleware.js +1 -1
  144. package/dist/server/middleware.js.map +1 -1
  145. package/dist/server/pages-api-route.d.ts +18 -0
  146. package/dist/server/pages-api-route.js +3 -1
  147. package/dist/server/pages-api-route.js.map +1 -1
  148. package/dist/server/pages-body-parser-config.d.ts +60 -0
  149. package/dist/server/pages-body-parser-config.js +79 -0
  150. package/dist/server/pages-body-parser-config.js.map +1 -0
  151. package/dist/server/pages-data-route.js +1 -0
  152. package/dist/server/pages-data-route.js.map +1 -1
  153. package/dist/server/pages-default-404.d.ts +31 -0
  154. package/dist/server/pages-default-404.js +40 -0
  155. package/dist/server/pages-default-404.js.map +1 -0
  156. package/dist/server/pages-node-compat.d.ts +10 -0
  157. package/dist/server/pages-node-compat.js +12 -1
  158. package/dist/server/pages-node-compat.js.map +1 -1
  159. package/dist/server/pages-page-data.d.ts +40 -0
  160. package/dist/server/pages-page-data.js +16 -14
  161. package/dist/server/pages-page-data.js.map +1 -1
  162. package/dist/server/pages-page-response.d.ts +2 -0
  163. package/dist/server/pages-page-response.js +11 -8
  164. package/dist/server/pages-page-response.js.map +1 -1
  165. package/dist/server/prerender-route-params.d.ts +14 -0
  166. package/dist/server/prerender-route-params.js +94 -0
  167. package/dist/server/prerender-route-params.js.map +1 -0
  168. package/dist/server/prod-server.d.ts +3 -23
  169. package/dist/server/prod-server.js +40 -57
  170. package/dist/server/prod-server.js.map +1 -1
  171. package/dist/server/proxy-trust.d.ts +41 -0
  172. package/dist/server/proxy-trust.js +70 -0
  173. package/dist/server/proxy-trust.js.map +1 -0
  174. package/dist/server/request-pipeline.d.ts +3 -3
  175. package/dist/server/request-pipeline.js +5 -4
  176. package/dist/server/request-pipeline.js.map +1 -1
  177. package/dist/server/seed-cache.js +12 -6
  178. package/dist/server/seed-cache.js.map +1 -1
  179. package/dist/server/static-file-cache.js +1 -1
  180. package/dist/server/static-file-cache.js.map +1 -1
  181. package/dist/server/streaming-metadata.d.ts +5 -0
  182. package/dist/server/streaming-metadata.js +10 -0
  183. package/dist/server/streaming-metadata.js.map +1 -0
  184. package/dist/shims/app-router-scroll-state.d.ts +12 -0
  185. package/dist/shims/app-router-scroll-state.js +38 -0
  186. package/dist/shims/app-router-scroll-state.js.map +1 -0
  187. package/dist/shims/app-router-scroll.d.ts +14 -0
  188. package/dist/shims/app-router-scroll.js +100 -0
  189. package/dist/shims/app-router-scroll.js.map +1 -0
  190. package/dist/shims/before-interactive-context.d.ts +30 -0
  191. package/dist/shims/before-interactive-context.js +10 -0
  192. package/dist/shims/before-interactive-context.js.map +1 -0
  193. package/dist/shims/cache-runtime.d.ts +1 -1
  194. package/dist/shims/cache-runtime.js +14 -1
  195. package/dist/shims/cache-runtime.js.map +1 -1
  196. package/dist/shims/default-not-found.d.ts +12 -0
  197. package/dist/shims/default-not-found.js +61 -0
  198. package/dist/shims/default-not-found.js.map +1 -0
  199. package/dist/shims/font-local.d.ts +5 -0
  200. package/dist/shims/font-local.js +6 -2
  201. package/dist/shims/font-local.js.map +1 -1
  202. package/dist/shims/head.js +4 -4
  203. package/dist/shims/head.js.map +1 -1
  204. package/dist/shims/headers.d.ts +6 -2
  205. package/dist/shims/headers.js +64 -21
  206. package/dist/shims/headers.js.map +1 -1
  207. package/dist/shims/image.d.ts +1 -1
  208. package/dist/shims/image.js +4 -4
  209. package/dist/shims/image.js.map +1 -1
  210. package/dist/shims/internal/pages-data-target.d.ts +58 -0
  211. package/dist/shims/internal/pages-data-target.js +91 -0
  212. package/dist/shims/internal/pages-data-target.js.map +1 -0
  213. package/dist/shims/internal/pages-data-url.d.ts +42 -0
  214. package/dist/shims/internal/pages-data-url.js +73 -0
  215. package/dist/shims/internal/pages-data-url.js.map +1 -0
  216. package/dist/shims/link.js +59 -9
  217. package/dist/shims/link.js.map +1 -1
  218. package/dist/shims/metadata.d.ts +2 -1
  219. package/dist/shims/metadata.js +61 -2
  220. package/dist/shims/metadata.js.map +1 -1
  221. package/dist/shims/navigation.js +32 -9
  222. package/dist/shims/navigation.js.map +1 -1
  223. package/dist/shims/router.js +376 -77
  224. package/dist/shims/router.js.map +1 -1
  225. package/dist/shims/script.js +86 -12
  226. package/dist/shims/script.js.map +1 -1
  227. package/dist/shims/server.js +1 -0
  228. package/dist/shims/server.js.map +1 -1
  229. package/dist/shims/url-utils.d.ts +2 -1
  230. package/dist/shims/url-utils.js +15 -4
  231. package/dist/shims/url-utils.js.map +1 -1
  232. package/dist/utils/html-limited-bots.d.ts +5 -0
  233. package/dist/utils/html-limited-bots.js +15 -0
  234. package/dist/utils/html-limited-bots.js.map +1 -0
  235. package/dist/utils/query.d.ts +6 -0
  236. package/dist/utils/query.js +10 -1
  237. package/dist/utils/query.js.map +1 -1
  238. package/package.json +1 -1
package/README.md CHANGED
@@ -558,7 +558,7 @@ These are intentional exclusions. For things that are missing today but on the r
558
558
 
559
559
  These are gaps we'd like to close — distinct from the [intentional exclusions](#whats-not-supported-and-wont-be) above.
560
560
 
561
- - **Image optimization doesn't happen at build time.** Remote images work via `@unpic/react` (auto-detects 28 CDN providers). Local images are routed through a `/_vinext/image` endpoint that can resize and transcode on Cloudflare Workers (via the Images binding) in production, but no build-time optimization or static resizing occurs.
561
+ - **Image optimization doesn't happen at build time.** Remote images work via `@unpic/react` (auto-detects 28 CDN providers). Local images are routed through a `/_next/image` endpoint that can resize and transcode on Cloudflare Workers (via the Images binding) in production, but no build-time optimization or static resizing occurs.
562
562
  - **Google Fonts are loaded from the CDN, not self-hosted.** No `size-adjust` fallback font metrics. Local fonts work but `@font-face` CSS is injected at runtime, not extracted at build time.
563
563
  - **Route segment config** — `runtime` and `preferredRegion` are ignored (everything runs in the same environment).
564
564
  - **Node.js production server (`vinext start`)** works for testing but is less complete than Workers deployment. Cloudflare Workers is the primary target.
@@ -0,0 +1,14 @@
1
+ //#region src/build/clean-output.d.ts
2
+ type CleanBuildOutputOptions = {
3
+ root: string;
4
+ outDir?: string;
5
+ emptyOutDir?: boolean;
6
+ };
7
+ type CleanBuildOutputResult = {
8
+ cleaned: boolean;
9
+ outDir: string;
10
+ };
11
+ declare function cleanBuildOutput(options: CleanBuildOutputOptions): CleanBuildOutputResult;
12
+ //#endregion
13
+ export { cleanBuildOutput };
14
+ //# sourceMappingURL=clean-output.d.ts.map
@@ -0,0 +1,36 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ //#region src/build/clean-output.ts
4
+ function resolveOutDir(root, outDir) {
5
+ const resolvedRoot = path.resolve(root);
6
+ if (!outDir) return path.join(resolvedRoot, "dist");
7
+ return path.isAbsolute(outDir) ? outDir : path.resolve(resolvedRoot, outDir);
8
+ }
9
+ function isPathInsideOrEqual(parent, child) {
10
+ const relative = path.relative(parent, child);
11
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
12
+ }
13
+ function shouldCleanBuildOutput(options) {
14
+ if (options.emptyOutDir === false) return false;
15
+ if (options.emptyOutDir === true) return true;
16
+ return isPathInsideOrEqual(path.resolve(options.root), resolveOutDir(options.root, options.outDir));
17
+ }
18
+ function cleanBuildOutput(options) {
19
+ const outDir = resolveOutDir(options.root, options.outDir);
20
+ if (!shouldCleanBuildOutput(options)) return {
21
+ cleaned: false,
22
+ outDir
23
+ };
24
+ fs.rmSync(outDir, {
25
+ recursive: true,
26
+ force: true
27
+ });
28
+ return {
29
+ cleaned: true,
30
+ outDir
31
+ };
32
+ }
33
+ //#endregion
34
+ export { cleanBuildOutput };
35
+
36
+ //# sourceMappingURL=clean-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean-output.js","names":[],"sources":["../../src/build/clean-output.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype CleanBuildOutputOptions = {\n root: string;\n outDir?: string;\n emptyOutDir?: boolean;\n};\n\ntype CleanBuildOutputResult = {\n cleaned: boolean;\n outDir: string;\n};\n\nfunction resolveOutDir(root: string, outDir: string | undefined): string {\n const resolvedRoot = path.resolve(root);\n if (!outDir) return path.join(resolvedRoot, \"dist\");\n return path.isAbsolute(outDir) ? outDir : path.resolve(resolvedRoot, outDir);\n}\n\nfunction isPathInsideOrEqual(parent: string, child: string): boolean {\n const relative = path.relative(parent, child);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction shouldCleanBuildOutput(options: CleanBuildOutputOptions): boolean {\n if (options.emptyOutDir === false) return false;\n if (options.emptyOutDir === true) return true;\n\n return isPathInsideOrEqual(\n path.resolve(options.root),\n resolveOutDir(options.root, options.outDir),\n );\n}\n\nexport function cleanBuildOutput(options: CleanBuildOutputOptions): CleanBuildOutputResult {\n const outDir = resolveOutDir(options.root, options.outDir);\n if (!shouldCleanBuildOutput(options)) return { cleaned: false, outDir };\n\n fs.rmSync(outDir, { recursive: true, force: true });\n return { cleaned: true, outDir };\n}\n"],"mappings":";;;AAcA,SAAS,cAAc,MAAc,QAAoC;CACvE,MAAM,eAAe,KAAK,QAAQ,KAAK;CACvC,IAAI,CAAC,QAAQ,OAAO,KAAK,KAAK,cAAc,OAAO;CACnD,OAAO,KAAK,WAAW,OAAO,GAAG,SAAS,KAAK,QAAQ,cAAc,OAAO;;AAG9E,SAAS,oBAAoB,QAAgB,OAAwB;CACnE,MAAM,WAAW,KAAK,SAAS,QAAQ,MAAM;CAC7C,OAAO,aAAa,MAAO,CAAC,SAAS,WAAW,KAAK,IAAI,CAAC,KAAK,WAAW,SAAS;;AAGrF,SAAS,uBAAuB,SAA2C;CACzE,IAAI,QAAQ,gBAAgB,OAAO,OAAO;CAC1C,IAAI,QAAQ,gBAAgB,MAAM,OAAO;CAEzC,OAAO,oBACL,KAAK,QAAQ,QAAQ,KAAK,EAC1B,cAAc,QAAQ,MAAM,QAAQ,OAAO,CAC5C;;AAGH,SAAgB,iBAAiB,SAA0D;CACzF,MAAM,SAAS,cAAc,QAAQ,MAAM,QAAQ,OAAO;CAC1D,IAAI,CAAC,uBAAuB,QAAQ,EAAE,OAAO;EAAE,SAAS;EAAO;EAAQ;CAEvE,GAAG,OAAO,QAAQ;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;CACnD,OAAO;EAAE,SAAS;EAAM;EAAQ"}
@@ -1,12 +1,14 @@
1
1
  import { Route } from "../routing/pages-router.js";
2
2
  import { AppRoute } from "../routing/app-route-graph.js";
3
3
  import { ResolvedNextConfig } from "../config/next-config.js";
4
+ import { MetadataFileRoute } from "../server/metadata-routes.js";
4
5
  import { readPrerenderSecret } from "./server-manifest.js";
5
6
  import { Server } from "node:http";
6
7
 
7
8
  //#region src/build/prerender.d.ts
8
9
  type PrerenderResult = {
9
- /** One entry per route (including skipped/error routes). */routes: PrerenderRouteResult[];
10
+ /** One entry per route (including skipped/error routes). */routes: PrerenderRouteResult[]; /** Additional generated files that are not represented as route entries. */
11
+ outputFiles?: string[];
10
12
  };
11
13
  type PrerenderRouteResult = {
12
14
  /** The route's file-system pattern, e.g. `/blog/:slug`. */route: string;
@@ -83,7 +85,8 @@ type PrerenderPagesOptions = {
83
85
  pagesBundlePath?: string;
84
86
  } & PrerenderOptions;
85
87
  type PrerenderAppOptions = {
86
- /** Discovered app routes. */routes: AppRoute[];
88
+ /** Discovered app routes. */routes: AppRoute[]; /** Discovered file-based metadata routes. Used by static export. */
89
+ metadataRoutes?: readonly MetadataFileRoute[];
87
90
  /**
88
91
  * Absolute path to the pre-built RSC handler bundle (e.g. `dist/server/index.js`).
89
92
  */
@@ -176,6 +179,7 @@ declare function prerenderPages({
176
179
  */
177
180
  declare function prerenderApp({
178
181
  routes,
182
+ metadataRoutes,
179
183
  outDir,
180
184
  config,
181
185
  mode,
@@ -1,11 +1,12 @@
1
1
  import { createValidFileMatcher, findFileWithExtensions } from "../routing/file-matcher.js";
2
- import { VINEXT_PRERENDER_SECRET_HEADER } from "../server/headers.js";
2
+ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../server/headers.js";
3
3
  import { normalizeStaticPathsEntry } from "../routing/route-pattern.js";
4
4
  import { headersContextFromRequest, runWithHeadersContext } from "../shims/headers.js";
5
5
  import { NoOpCacheHandler, _consumeRequestScopedCacheLife, getCacheHandler, setCacheHandler } from "../shims/cache.js";
6
6
  import { classifyAppRoute, classifyPagesRoute, getAppRouteRenderEntryPath } from "./report.js";
7
7
  import { concatUint8Arrays, decodeRscEmbeddedChunk } from "../server/app-rsc-embedded-chunks.js";
8
8
  import { navigationRuntimeRscBootstrapExpression } from "../server/app-ssr-stream.js";
9
+ import { encodePrerenderRouteParams, serializePrerenderRouteParamsHeader } from "../server/prerender-route-params.js";
9
10
  import { readPrerenderSecret } from "./server-manifest.js";
10
11
  import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
11
12
  import { startProdServer } from "../server/prod-server.js";
@@ -143,6 +144,26 @@ function buildUrlFromParams(pattern, params) {
143
144
  } else result.push(part);
144
145
  return "/" + result.join("/");
145
146
  }
147
+ function metadataOutputPath(servedUrl) {
148
+ const pathname = servedUrl.split("?", 1)[0];
149
+ if (!pathname || !pathname.startsWith("/")) return null;
150
+ const segments = pathname.split("/").filter(Boolean);
151
+ if (segments.length === 0 || segments.some((segment) => segment === "." || segment === "..")) return null;
152
+ return segments.join("/");
153
+ }
154
+ function emitStaticMetadataFiles(metadataRoutes, outDir) {
155
+ const outputFiles = [];
156
+ for (const route of metadataRoutes) {
157
+ if (route.isDynamic) continue;
158
+ const outputPath = metadataOutputPath(route.servedUrl);
159
+ if (!outputPath) continue;
160
+ const fullPath = path.join(outDir, ...outputPath.split("/"));
161
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
162
+ fs.copyFileSync(route.filePath, fullPath);
163
+ outputFiles.push(outputPath);
164
+ }
165
+ return outputFiles;
166
+ }
146
167
  /**
147
168
  * Resolve parent dynamic segment params for a route.
148
169
  * Handles top-down generateStaticParams resolution for nested dynamic routes.
@@ -268,6 +289,7 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
268
289
  const pagesToRender = [];
269
290
  for (const route of bundlePageRoutes) {
270
291
  if (path.basename(route.filePath, path.extname(route.filePath)).startsWith("_")) continue;
292
+ if (route.pattern === "/404") continue;
271
293
  if (!routes.find((r) => r.filePath === route.filePath || r.pattern === route.pattern)) continue;
272
294
  const { type, revalidate: classifiedRevalidate } = classifyPagesRoute(route.filePath);
273
295
  if (type === "ssr") {
@@ -394,9 +416,12 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
394
416
  return result;
395
417
  });
396
418
  results.push(...pageResults);
397
- if (findFileWithExtensions(path.join(pagesDir, "404"), fileMatcher) || findFileWithExtensions(path.join(pagesDir, "_error"), fileMatcher)) try {
398
- const notFoundRes = await renderPage(NOT_FOUND_SENTINEL_PATH);
399
- if ((notFoundRes.headers.get("content-type") ?? "").includes("text/html")) {
419
+ const hasCustom404 = findFileWithExtensions(path.join(pagesDir, "404"), fileMatcher);
420
+ const hasErrorPage = findFileWithExtensions(path.join(pagesDir, "_error"), fileMatcher);
421
+ if (hasCustom404 || hasErrorPage) try {
422
+ const notFoundRes = await renderPage(hasCustom404 ? "/404" : NOT_FOUND_SENTINEL_PATH);
423
+ const contentType = notFoundRes.headers.get("content-type") ?? "";
424
+ if (notFoundRes.status === 404 && contentType.includes("text/html")) {
400
425
  const html404 = await notFoundRes.text();
401
426
  const fullPath = path.join(outDir, "404.html");
402
427
  fs.writeFileSync(fullPath, html404, "utf-8");
@@ -438,7 +463,7 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
438
463
  * If they succeed, they are marked as rendered. If they throw a DynamicUsageError
439
464
  * or fail, they are marked as skipped with reason 'dynamic'.
440
465
  */
441
- async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...options }) {
466
+ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode, rscBundlePath, ...options }) {
442
467
  const manifestDir = options.manifestDir ?? outDir;
443
468
  const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
444
469
  const onProgress = options.onProgress;
@@ -477,7 +502,8 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
477
502
  ...secretHeaders,
478
503
  ...Object.fromEntries(req.headers.entries())
479
504
  },
480
- body: req.method !== "GET" && req.method !== "HEAD" ? req.body : void 0
505
+ body: req.method !== "GET" && req.method !== "HEAD" ? req.body : void 0,
506
+ redirect: "manual"
481
507
  });
482
508
  };
483
509
  const staticParamsCache = /* @__PURE__ */ new Map();
@@ -608,6 +634,7 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
608
634
  urlsToRender.push({
609
635
  urlPath,
610
636
  routePattern: route.pattern,
637
+ prerenderRouteParams: encodePrerenderRouteParams(route.pattern, params),
611
638
  revalidate,
612
639
  isSpeculative: false
613
640
  });
@@ -624,12 +651,14 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
624
651
  else if (type === "unknown") urlsToRender.push({
625
652
  urlPath: route.pattern,
626
653
  routePattern: route.pattern,
654
+ prerenderRouteParams: null,
627
655
  revalidate: false,
628
656
  isSpeculative: true
629
657
  });
630
658
  else urlsToRender.push({
631
659
  urlPath: route.pattern,
632
660
  routePattern: route.pattern,
661
+ prerenderRouteParams: null,
633
662
  revalidate,
634
663
  isSpeculative: false
635
664
  });
@@ -640,9 +669,12 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
640
669
  * exactly once per URL after this function returns, keeping the callback
641
670
  * at a single, predictable call site.
642
671
  */
643
- async function renderUrl({ urlPath, routePattern, revalidate, isSpeculative }) {
672
+ async function renderUrl({ urlPath, routePattern, prerenderRouteParams, revalidate, isSpeculative }) {
644
673
  try {
645
- const htmlRequest = new Request(`http://localhost${urlPath}`);
674
+ const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParams);
675
+ const htmlHeaders = new Headers();
676
+ if (prerenderRouteParamsHeader !== null) htmlHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
677
+ const htmlRequest = new Request(`http://localhost${urlPath}`, { headers: htmlHeaders });
646
678
  const htmlRender = await runWithHeadersContext(headersContextFromRequest(htmlRequest), async () => {
647
679
  const response = await rscHandler(htmlRequest);
648
680
  const cacheControl = response.headers.get("cache-control") ?? "";
@@ -692,10 +724,12 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
692
724
  const html = htmlRender.html;
693
725
  let rscData = extractRscPayloadFromPrerenderedHtml(html);
694
726
  if (rscData === null) {
695
- const rscRequest = new Request(`http://localhost${urlPath}`, { headers: {
727
+ const rscHeaders = new Headers({
696
728
  Accept: "text/x-component",
697
729
  RSC: "1"
698
- } });
730
+ });
731
+ if (prerenderRouteParamsHeader !== null) rscHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
732
+ const rscRequest = new Request(`http://localhost${urlPath}`, { headers: rscHeaders });
699
733
  const rscRes = await runWithHeadersContext(headersContextFromRequest(rscRequest), () => rscHandler(rscRequest));
700
734
  if (!rscRes.ok) {
701
735
  await rscRes.body?.cancel();
@@ -752,6 +786,7 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
752
786
  return result;
753
787
  });
754
788
  results.push(...appResults);
789
+ const outputFiles = mode === "export" && metadataRoutes.length > 0 ? emitStaticMetadataFiles(metadataRoutes, outDir) : [];
755
790
  try {
756
791
  const notFoundRequest = new Request(`http://localhost${NOT_FOUND_SENTINEL_PATH}`);
757
792
  const notFoundRes = await runWithHeadersContext(headersContextFromRequest(notFoundRequest), () => rscHandler(notFoundRequest));
@@ -773,7 +808,10 @@ async function prerenderApp({ routes, outDir, config, mode, rscBundlePath, ...op
773
808
  buildId: config.buildId,
774
809
  trailingSlash: config.trailingSlash
775
810
  });
776
- return { routes: results };
811
+ return {
812
+ routes: results,
813
+ ...outputFiles.length > 0 ? { outputFiles } : {}
814
+ };
777
815
  } finally {
778
816
  setCacheHandler(previousHandler);
779
817
  if (previousPrerenderFlag === void 0) delete process.env.VINEXT_PRERENDER;