vinext 0.0.26 → 0.0.28

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 (227) hide show
  1. package/README.md +89 -85
  2. package/dist/build/static-export.d.ts +1 -1
  3. package/dist/build/static-export.d.ts.map +1 -1
  4. package/dist/build/static-export.js +5 -9
  5. package/dist/build/static-export.js.map +1 -1
  6. package/dist/check.d.ts.map +1 -1
  7. package/dist/check.js +152 -48
  8. package/dist/check.js.map +1 -1
  9. package/dist/cli.js +10 -11
  10. package/dist/cli.js.map +1 -1
  11. package/dist/cloudflare/kv-cache-handler.d.ts +43 -1
  12. package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
  13. package/dist/cloudflare/kv-cache-handler.js +135 -44
  14. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  15. package/dist/cloudflare/tpr.d.ts.map +1 -1
  16. package/dist/cloudflare/tpr.js +15 -4
  17. package/dist/cloudflare/tpr.js.map +1 -1
  18. package/dist/config/config-matchers.d.ts +28 -0
  19. package/dist/config/config-matchers.d.ts.map +1 -1
  20. package/dist/config/config-matchers.js +353 -79
  21. package/dist/config/config-matchers.js.map +1 -1
  22. package/dist/config/dotenv.d.ts.map +1 -1
  23. package/dist/config/dotenv.js +1 -6
  24. package/dist/config/dotenv.js.map +1 -1
  25. package/dist/config/next-config.d.ts +7 -0
  26. package/dist/config/next-config.d.ts.map +1 -1
  27. package/dist/config/next-config.js +44 -19
  28. package/dist/config/next-config.js.map +1 -1
  29. package/dist/deploy.d.ts +1 -1
  30. package/dist/deploy.d.ts.map +1 -1
  31. package/dist/deploy.js +81 -48
  32. package/dist/deploy.js.map +1 -1
  33. package/dist/entries/app-rsc-entry.d.ts +3 -1
  34. package/dist/entries/app-rsc-entry.d.ts.map +1 -1
  35. package/dist/entries/app-rsc-entry.js +584 -113
  36. package/dist/entries/app-rsc-entry.js.map +1 -1
  37. package/dist/entries/pages-client-entry.d.ts.map +1 -1
  38. package/dist/entries/pages-client-entry.js +5 -3
  39. package/dist/entries/pages-client-entry.js.map +1 -1
  40. package/dist/entries/pages-server-entry.d.ts.map +1 -1
  41. package/dist/entries/pages-server-entry.js +100 -32
  42. package/dist/entries/pages-server-entry.js.map +1 -1
  43. package/dist/index.d.ts +24 -8
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +327 -154
  46. package/dist/index.js.map +1 -1
  47. package/dist/init.d.ts.map +1 -1
  48. package/dist/init.js +6 -5
  49. package/dist/init.js.map +1 -1
  50. package/dist/plugins/client-reference-dedup.d.ts +19 -0
  51. package/dist/plugins/client-reference-dedup.d.ts.map +1 -0
  52. package/dist/plugins/client-reference-dedup.js +96 -0
  53. package/dist/plugins/client-reference-dedup.js.map +1 -0
  54. package/dist/routing/app-router.d.ts +2 -0
  55. package/dist/routing/app-router.d.ts.map +1 -1
  56. package/dist/routing/app-router.js +70 -107
  57. package/dist/routing/app-router.js.map +1 -1
  58. package/dist/routing/file-matcher.d.ts.map +1 -1
  59. package/dist/routing/file-matcher.js.map +1 -1
  60. package/dist/routing/pages-router.d.ts +3 -1
  61. package/dist/routing/pages-router.d.ts.map +1 -1
  62. package/dist/routing/pages-router.js +33 -18
  63. package/dist/routing/pages-router.js.map +1 -1
  64. package/dist/routing/route-validation.d.ts +8 -0
  65. package/dist/routing/route-validation.d.ts.map +1 -0
  66. package/dist/routing/route-validation.js +124 -0
  67. package/dist/routing/route-validation.js.map +1 -0
  68. package/dist/routing/utils.d.ts.map +1 -1
  69. package/dist/routing/utils.js.map +1 -1
  70. package/dist/server/api-handler.d.ts.map +1 -1
  71. package/dist/server/api-handler.js +31 -9
  72. package/dist/server/api-handler.js.map +1 -1
  73. package/dist/server/app-router-entry.d.ts +3 -2
  74. package/dist/server/app-router-entry.d.ts.map +1 -1
  75. package/dist/server/app-router-entry.js +8 -4
  76. package/dist/server/app-router-entry.js.map +1 -1
  77. package/dist/server/dev-module-runner.d.ts.map +1 -1
  78. package/dist/server/dev-module-runner.js +1 -1
  79. package/dist/server/dev-module-runner.js.map +1 -1
  80. package/dist/server/dev-origin-check.d.ts.map +1 -1
  81. package/dist/server/dev-origin-check.js.map +1 -1
  82. package/dist/server/dev-server.d.ts.map +1 -1
  83. package/dist/server/dev-server.js +39 -21
  84. package/dist/server/dev-server.js.map +1 -1
  85. package/dist/server/image-optimization.d.ts.map +1 -1
  86. package/dist/server/image-optimization.js.map +1 -1
  87. package/dist/server/instrumentation.js +1 -1
  88. package/dist/server/instrumentation.js.map +1 -1
  89. package/dist/server/isr-cache.d.ts +5 -1
  90. package/dist/server/isr-cache.d.ts.map +1 -1
  91. package/dist/server/isr-cache.js +13 -3
  92. package/dist/server/isr-cache.js.map +1 -1
  93. package/dist/server/metadata-routes.d.ts +8 -2
  94. package/dist/server/metadata-routes.d.ts.map +1 -1
  95. package/dist/server/metadata-routes.js +78 -45
  96. package/dist/server/metadata-routes.js.map +1 -1
  97. package/dist/server/middleware-codegen.d.ts +1 -1
  98. package/dist/server/middleware-codegen.d.ts.map +1 -1
  99. package/dist/server/middleware-codegen.js +177 -22
  100. package/dist/server/middleware-codegen.js.map +1 -1
  101. package/dist/server/middleware-request-headers.d.ts +9 -0
  102. package/dist/server/middleware-request-headers.d.ts.map +1 -0
  103. package/dist/server/middleware-request-headers.js +77 -0
  104. package/dist/server/middleware-request-headers.js.map +1 -0
  105. package/dist/server/middleware.d.ts +9 -8
  106. package/dist/server/middleware.d.ts.map +1 -1
  107. package/dist/server/middleware.js +112 -32
  108. package/dist/server/middleware.js.map +1 -1
  109. package/dist/server/normalize-path.js.map +1 -1
  110. package/dist/server/prod-server.d.ts +1 -1
  111. package/dist/server/prod-server.d.ts.map +1 -1
  112. package/dist/server/prod-server.js +127 -82
  113. package/dist/server/prod-server.js.map +1 -1
  114. package/dist/server/request-pipeline.d.ts +2 -1
  115. package/dist/server/request-pipeline.d.ts.map +1 -1
  116. package/dist/server/request-pipeline.js +5 -7
  117. package/dist/server/request-pipeline.js.map +1 -1
  118. package/dist/shims/cache-runtime.d.ts.map +1 -1
  119. package/dist/shims/cache-runtime.js +21 -16
  120. package/dist/shims/cache-runtime.js.map +1 -1
  121. package/dist/shims/cache.d.ts +2 -0
  122. package/dist/shims/cache.d.ts.map +1 -1
  123. package/dist/shims/cache.js +38 -25
  124. package/dist/shims/cache.js.map +1 -1
  125. package/dist/shims/constants.d.ts.map +1 -1
  126. package/dist/shims/constants.js +1 -6
  127. package/dist/shims/constants.js.map +1 -1
  128. package/dist/shims/dynamic.d.ts.map +1 -1
  129. package/dist/shims/dynamic.js +1 -1
  130. package/dist/shims/dynamic.js.map +1 -1
  131. package/dist/shims/error-boundary.d.ts.map +1 -1
  132. package/dist/shims/error-boundary.js +2 -3
  133. package/dist/shims/error-boundary.js.map +1 -1
  134. package/dist/shims/error.d.ts.map +1 -1
  135. package/dist/shims/error.js +1 -3
  136. package/dist/shims/error.js.map +1 -1
  137. package/dist/shims/fetch-cache.d.ts.map +1 -1
  138. package/dist/shims/fetch-cache.js +57 -30
  139. package/dist/shims/fetch-cache.js.map +1 -1
  140. package/dist/shims/font-google-base.d.ts.map +1 -1
  141. package/dist/shims/font-google-base.js +16 -4
  142. package/dist/shims/font-google-base.js.map +1 -1
  143. package/dist/shims/font-google.d.ts +1 -1
  144. package/dist/shims/font-google.d.ts.map +1 -1
  145. package/dist/shims/font-google.generated.d.ts.map +1 -1
  146. package/dist/shims/font-google.generated.js +412 -206
  147. package/dist/shims/font-google.generated.js.map +1 -1
  148. package/dist/shims/font-google.js +1 -1
  149. package/dist/shims/font-google.js.map +1 -1
  150. package/dist/shims/font-local.d.ts.map +1 -1
  151. package/dist/shims/font-local.js +13 -3
  152. package/dist/shims/font-local.js.map +1 -1
  153. package/dist/shims/form.d.ts.map +1 -1
  154. package/dist/shims/form.js +105 -10
  155. package/dist/shims/form.js.map +1 -1
  156. package/dist/shims/head.d.ts.map +1 -1
  157. package/dist/shims/head.js +10 -8
  158. package/dist/shims/head.js.map +1 -1
  159. package/dist/shims/headers.d.ts +34 -8
  160. package/dist/shims/headers.d.ts.map +1 -1
  161. package/dist/shims/headers.js +268 -53
  162. package/dist/shims/headers.js.map +1 -1
  163. package/dist/shims/image.d.ts.map +1 -1
  164. package/dist/shims/image.js +35 -8
  165. package/dist/shims/image.js.map +1 -1
  166. package/dist/shims/internal/parse-cookie-header.d.ts +12 -0
  167. package/dist/shims/internal/parse-cookie-header.d.ts.map +1 -0
  168. package/dist/shims/internal/parse-cookie-header.js +32 -0
  169. package/dist/shims/internal/parse-cookie-header.js.map +1 -0
  170. package/dist/shims/legacy-image.d.ts.map +1 -1
  171. package/dist/shims/legacy-image.js +1 -1
  172. package/dist/shims/legacy-image.js.map +1 -1
  173. package/dist/shims/link.d.ts +2 -1
  174. package/dist/shims/link.d.ts.map +1 -1
  175. package/dist/shims/link.js +37 -17
  176. package/dist/shims/link.js.map +1 -1
  177. package/dist/shims/metadata.d.ts +12 -2
  178. package/dist/shims/metadata.d.ts.map +1 -1
  179. package/dist/shims/metadata.js +10 -8
  180. package/dist/shims/metadata.js.map +1 -1
  181. package/dist/shims/navigation-state.d.ts.map +1 -1
  182. package/dist/shims/navigation-state.js +3 -2
  183. package/dist/shims/navigation-state.js.map +1 -1
  184. package/dist/shims/navigation.d.ts +3 -7
  185. package/dist/shims/navigation.d.ts.map +1 -1
  186. package/dist/shims/navigation.js +46 -29
  187. package/dist/shims/navigation.js.map +1 -1
  188. package/dist/shims/readonly-url-search-params.d.ts +11 -0
  189. package/dist/shims/readonly-url-search-params.d.ts.map +1 -0
  190. package/dist/shims/readonly-url-search-params.js +24 -0
  191. package/dist/shims/readonly-url-search-params.js.map +1 -0
  192. package/dist/shims/request-context.d.ts +50 -0
  193. package/dist/shims/request-context.d.ts.map +1 -0
  194. package/dist/shims/request-context.js +59 -0
  195. package/dist/shims/request-context.js.map +1 -0
  196. package/dist/shims/router-state.d.ts.map +1 -1
  197. package/dist/shims/router-state.js +2 -1
  198. package/dist/shims/router-state.js.map +1 -1
  199. package/dist/shims/router.d.ts +4 -3
  200. package/dist/shims/router.d.ts.map +1 -1
  201. package/dist/shims/router.js +59 -53
  202. package/dist/shims/router.js.map +1 -1
  203. package/dist/shims/script.d.ts.map +1 -1
  204. package/dist/shims/script.js.map +1 -1
  205. package/dist/shims/server.d.ts +14 -1
  206. package/dist/shims/server.d.ts.map +1 -1
  207. package/dist/shims/server.js +107 -47
  208. package/dist/shims/server.js.map +1 -1
  209. package/dist/shims/url-utils.d.ts.map +1 -1
  210. package/dist/shims/url-utils.js +1 -3
  211. package/dist/shims/url-utils.js.map +1 -1
  212. package/dist/utils/base-path.d.ts +17 -0
  213. package/dist/utils/base-path.d.ts.map +1 -0
  214. package/dist/utils/base-path.js +25 -0
  215. package/dist/utils/base-path.js.map +1 -0
  216. package/dist/utils/manifest-paths.d.ts +4 -0
  217. package/dist/utils/manifest-paths.d.ts.map +1 -0
  218. package/dist/utils/manifest-paths.js +20 -0
  219. package/dist/utils/manifest-paths.js.map +1 -0
  220. package/dist/utils/project.d.ts.map +1 -1
  221. package/dist/utils/project.js +2 -4
  222. package/dist/utils/project.js.map +1 -1
  223. package/dist/utils/query.d.ts +9 -0
  224. package/dist/utils/query.d.ts.map +1 -1
  225. package/dist/utils/query.js +59 -7
  226. package/dist/utils/query.js.map +1 -1
  227. package/package.json +47 -33
@@ -23,10 +23,12 @@ import { pathToFileURL } from "node:url";
23
23
  import fs from "node:fs";
24
24
  import path from "node:path";
25
25
  import zlib from "node:zlib";
26
- import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
27
- import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES } from "./image-optimization.js";
26
+ import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination, } from "../config/config-matchers.js";
27
+ import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, } from "./image-optimization.js";
28
28
  import { normalizePath } from "./normalize-path.js";
29
+ import { hasBasePath, stripBasePath } from "../utils/base-path.js";
29
30
  import { computeLazyChunks } from "../index.js";
31
+ import { manifestFileWithBase } from "../utils/manifest-paths.js";
30
32
  /** Convert a Node.js IncomingMessage into a ReadableStream for Web Request body. */
31
33
  function readNodeStream(req) {
32
34
  return new ReadableStream({
@@ -108,9 +110,7 @@ function mergeResponseHeaders(middlewareHeaders, response) {
108
110
  const responseCookies = response.headers.getSetCookie?.() ?? [];
109
111
  if (responseCookies.length > 0) {
110
112
  const existing = merged["set-cookie"];
111
- const mwCookies = existing
112
- ? (Array.isArray(existing) ? existing : [existing])
113
- : [];
113
+ const mwCookies = existing ? (Array.isArray(existing) ? existing : [existing]) : [];
114
114
  merged["set-cookie"] = [...mwCookies, ...responseCookies];
115
115
  }
116
116
  return merged;
@@ -133,7 +133,9 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
133
133
  let varyValue;
134
134
  if (existingVary) {
135
135
  const existing = existingVary.toLowerCase();
136
- varyValue = existing.includes("accept-encoding") ? existingVary : existingVary + ", Accept-Encoding";
136
+ varyValue = existing.includes("accept-encoding")
137
+ ? existingVary
138
+ : existingVary + ", Accept-Encoding";
137
139
  }
138
140
  else {
139
141
  varyValue = "Accept-Encoding";
@@ -145,11 +147,16 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
145
147
  Vary: varyValue,
146
148
  });
147
149
  compressor.end(buf);
148
- pipeline(compressor, res, () => { });
150
+ pipeline(compressor, res, () => {
151
+ /* ignore pipeline errors on closed connections */
152
+ });
149
153
  }
150
154
  else {
155
+ // Strip any pre-existing content-length (from the Web Response constructor)
156
+ // before setting our own — avoids duplicate Content-Length headers.
157
+ const { "content-length": _cl, "Content-Length": _CL, ...headersWithoutLength } = extraHeaders;
151
158
  res.writeHead(statusCode, {
152
- ...extraHeaders,
159
+ ...headersWithoutLength,
153
160
  "Content-Type": contentType,
154
161
  "Content-Length": String(buf.length),
155
162
  });
@@ -202,17 +209,13 @@ function tryServeStatic(req, res, clientDir, pathname, compress, extraHeaders) {
202
209
  if (!staticFile.startsWith(resolvedClient + path.sep) && staticFile !== resolvedClient) {
203
210
  return false;
204
211
  }
205
- if (pathname === "/" ||
206
- !fs.existsSync(staticFile) ||
207
- !fs.statSync(staticFile).isFile()) {
212
+ if (pathname === "/" || !fs.existsSync(staticFile) || !fs.statSync(staticFile).isFile()) {
208
213
  return false;
209
214
  }
210
215
  const ext = path.extname(staticFile);
211
216
  const ct = CONTENT_TYPES[ext] ?? "application/octet-stream";
212
217
  const isHashed = pathname.startsWith("/assets/");
213
- const cacheControl = isHashed
214
- ? "public, max-age=31536000, immutable"
215
- : "public, max-age=3600";
218
+ const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
216
219
  const baseHeaders = {
217
220
  "Content-Type": ct,
218
221
  "Cache-Control": cacheControl,
@@ -229,7 +232,9 @@ function tryServeStatic(req, res, clientDir, pathname, compress, extraHeaders) {
229
232
  "Content-Encoding": encoding,
230
233
  Vary: "Accept-Encoding",
231
234
  });
232
- pipeline(fileStream, compressor, res, () => { });
235
+ pipeline(fileStream, compressor, res, () => {
236
+ /* ignore */
237
+ });
233
238
  return true;
234
239
  }
235
240
  }
@@ -321,9 +326,7 @@ async function sendWebResponse(webResponse, req, res, compress) {
321
326
  webResponse.headers.forEach((value, key) => {
322
327
  const existing = nodeHeaders[key];
323
328
  if (existing !== undefined) {
324
- nodeHeaders[key] = Array.isArray(existing)
325
- ? [...existing, value]
326
- : [existing, value];
329
+ nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
327
330
  }
328
331
  else {
329
332
  nodeHeaders[key] = value;
@@ -339,7 +342,7 @@ async function sendWebResponse(webResponse, req, res, compress) {
339
342
  const alreadyEncoded = webResponse.headers.has("content-encoding");
340
343
  const contentType = webResponse.headers.get("content-type") ?? "";
341
344
  const baseType = contentType.split(";")[0].trim();
342
- const encoding = (compress && !alreadyEncoded) ? negotiateEncoding(req) : null;
345
+ const encoding = compress && !alreadyEncoded ? negotiateEncoding(req) : null;
343
346
  const shouldCompress = !!(encoding && COMPRESSIBLE_TYPES.has(baseType));
344
347
  if (shouldCompress) {
345
348
  delete nodeHeaders["content-length"];
@@ -370,10 +373,14 @@ async function sendWebResponse(webResponse, req, res, compress) {
370
373
  const nodeStream = Readable.fromWeb(webResponse.body);
371
374
  if (shouldCompress) {
372
375
  const compressor = createCompressor(encoding);
373
- pipeline(nodeStream, compressor, res, () => { });
376
+ pipeline(nodeStream, compressor, res, () => {
377
+ /* ignore pipeline errors on closed connections */
378
+ });
374
379
  }
375
380
  else {
376
- pipeline(nodeStream, res, () => { });
381
+ pipeline(nodeStream, res, () => {
382
+ /* ignore pipeline errors on closed connections */
383
+ });
377
384
  }
378
385
  }
379
386
  /**
@@ -402,11 +409,36 @@ export async function startProdServer(options = {}) {
402
409
  }
403
410
  return startPagesRouterServer({ port, host, clientDir, serverEntryPath, compress });
404
411
  }
412
+ function createNodeExecutionContext() {
413
+ return {
414
+ waitUntil(promise) {
415
+ // Node doesn't provide a Workers lifecycle, but we still attach a
416
+ // rejection handler so background waitUntil work doesn't surface as an
417
+ // unhandled rejection when a Worker-style entry is used with vinext start.
418
+ void Promise.resolve(promise).catch(() => { });
419
+ },
420
+ passThroughOnException() { },
421
+ };
422
+ }
423
+ function resolveAppRouterHandler(entry) {
424
+ if (typeof entry === "function") {
425
+ return (request) => Promise.resolve(entry(request));
426
+ }
427
+ if (entry && typeof entry === "object" && "fetch" in entry) {
428
+ const workerEntry = entry;
429
+ if (typeof workerEntry.fetch === "function") {
430
+ return (request) => Promise.resolve(workerEntry.fetch(request, undefined, createNodeExecutionContext()));
431
+ }
432
+ }
433
+ console.error("[vinext] App Router entry must export either a default handler function or a Worker-style default export with fetch()");
434
+ process.exit(1);
435
+ }
405
436
  /**
406
437
  * Start the App Router production server.
407
438
  *
408
- * The RSC entry (dist/server/index.js) exports a default handler function:
409
- * handler(request: Request) → Promise<Response>
439
+ * The App Router entry (dist/server/index.js) can export either:
440
+ * - a default handler function: handler(request: Request) → Promise<Response>
441
+ * - a Worker-style object: { fetch(request, env, ctx) → Promise<Response> }
410
442
  *
411
443
  * This handler already does everything: route matching, RSC rendering,
412
444
  * SSR HTML generation (via import("./ssr/index.js")), route handlers,
@@ -428,15 +460,13 @@ async function startAppRouterServer(options) {
428
460
  try {
429
461
  imageConfig = JSON.parse(fs.readFileSync(imageConfigPath, "utf-8"));
430
462
  }
431
- catch { /* ignore parse errors */ }
463
+ catch {
464
+ /* ignore parse errors */
465
+ }
432
466
  }
433
467
  // Import the RSC handler (use file:// URL for reliable dynamic import)
434
468
  const rscModule = await import(pathToFileURL(rscEntryPath).href);
435
- const rscHandler = rscModule.default;
436
- if (typeof rscHandler !== "function") {
437
- console.error("[vinext] RSC entry does not export a default handler function");
438
- process.exit(1);
439
- }
469
+ const rscHandler = resolveAppRouterHandler(rscModule.default);
440
470
  const server = createServer(async (req, res) => {
441
471
  const url = req.url ?? "/";
442
472
  // Normalize backslashes (browsers treat /\ as //), then decode and normalize path.
@@ -531,6 +561,33 @@ async function startAppRouterServer(options) {
531
561
  */
532
562
  async function startPagesRouterServer(options) {
533
563
  const { port, host, clientDir, serverEntryPath, compress } = options;
564
+ // Import the server entry module (use file:// URL for reliable dynamic import)
565
+ const serverEntry = await import(pathToFileURL(serverEntryPath).href);
566
+ const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig } = serverEntry;
567
+ // Extract config values (embedded at build time in the server entry)
568
+ const basePath = vinextConfig?.basePath ?? "";
569
+ const assetBase = basePath ? `${basePath}/` : "/";
570
+ const trailingSlash = vinextConfig?.trailingSlash ?? false;
571
+ const configRedirects = vinextConfig?.redirects ?? [];
572
+ const configRewrites = vinextConfig?.rewrites ?? {
573
+ beforeFiles: [],
574
+ afterFiles: [],
575
+ fallback: [],
576
+ };
577
+ const configHeaders = vinextConfig?.headers ?? [];
578
+ // Compute allowed image widths from config (union of deviceSizes + imageSizes)
579
+ const allowedImageWidths = [
580
+ ...(vinextConfig?.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES),
581
+ ...(vinextConfig?.images?.imageSizes ?? DEFAULT_IMAGE_SIZES),
582
+ ];
583
+ // Extract image security config for SVG handling and security headers
584
+ const pagesImageConfig = vinextConfig?.images
585
+ ? {
586
+ dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
587
+ contentDispositionType: vinextConfig.images.contentDispositionType,
588
+ contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
589
+ }
590
+ : undefined;
534
591
  // Load the SSR manifest (maps module URLs to client asset URLs)
535
592
  let ssrManifest = {};
536
593
  const manifestPath = path.join(clientDir, ".vite", "ssr-manifest.json");
@@ -544,33 +601,15 @@ async function startPagesRouterServer(options) {
544
601
  if (fs.existsSync(buildManifestPath)) {
545
602
  try {
546
603
  const buildManifest = JSON.parse(fs.readFileSync(buildManifestPath, "utf-8"));
547
- const lazyChunks = computeLazyChunks(buildManifest);
604
+ const lazyChunks = computeLazyChunks(buildManifest).map((file) => manifestFileWithBase(file, assetBase));
548
605
  if (lazyChunks.length > 0) {
549
606
  globalThis.__VINEXT_LAZY_CHUNKS__ = lazyChunks;
550
607
  }
551
608
  }
552
- catch { /* ignore parse errors */ }
609
+ catch {
610
+ /* ignore parse errors */
611
+ }
553
612
  }
554
- // Import the server entry module (use file:// URL for reliable dynamic import)
555
- const serverEntry = await import(pathToFileURL(serverEntryPath).href);
556
- const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig } = serverEntry;
557
- // Extract config values (embedded at build time in the server entry)
558
- const basePath = vinextConfig?.basePath ?? "";
559
- const trailingSlash = vinextConfig?.trailingSlash ?? false;
560
- const configRedirects = vinextConfig?.redirects ?? [];
561
- const configRewrites = vinextConfig?.rewrites ?? { beforeFiles: [], afterFiles: [], fallback: [] };
562
- const configHeaders = vinextConfig?.headers ?? [];
563
- // Compute allowed image widths from config (union of deviceSizes + imageSizes)
564
- const allowedImageWidths = [
565
- ...(vinextConfig?.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES),
566
- ...(vinextConfig?.images?.imageSizes ?? DEFAULT_IMAGE_SIZES),
567
- ];
568
- // Extract image security config for SVG handling and security headers
569
- const pagesImageConfig = vinextConfig?.images ? {
570
- dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
571
- contentDispositionType: vinextConfig.images.contentDispositionType,
572
- contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
573
- } : undefined;
574
613
  const server = createServer(async (req, res) => {
575
614
  const rawUrl = req.url ?? "/";
576
615
  // Normalize backslashes (browsers treat /\ as //), then decode and normalize path.
@@ -601,9 +640,7 @@ async function startPagesRouterServer(options) {
601
640
  // Serve static files from client build. When basePath is configured,
602
641
  // Vite's `base` config ensures assets are under basePath/assets/.
603
642
  // We check both with and without basePath.
604
- const staticLookupPath = basePath && pathname.startsWith(basePath)
605
- ? pathname.slice(basePath.length) || "/"
606
- : pathname;
643
+ const staticLookupPath = stripBasePath(pathname, basePath);
607
644
  if (staticLookupPath !== "/" &&
608
645
  !staticLookupPath.startsWith("/api/") &&
609
646
  tryServeStatic(req, res, clientDir, staticLookupPath, compress)) {
@@ -641,11 +678,13 @@ async function startPagesRouterServer(options) {
641
678
  }
642
679
  try {
643
680
  // ── 2. Strip basePath ─────────────────────────────────────────
644
- if (basePath && pathname.startsWith(basePath)) {
645
- const stripped = pathname.slice(basePath.length) || "/";
646
- const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
647
- url = stripped + qs;
648
- pathname = stripped;
681
+ {
682
+ const stripped = stripBasePath(pathname, basePath);
683
+ if (stripped !== pathname) {
684
+ const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
685
+ url = stripped + qs;
686
+ pathname = stripped;
687
+ }
649
688
  }
650
689
  // ── 3. Trailing slash normalization ───────────────────────────
651
690
  if (pathname !== "/" && pathname !== "/api" && !pathname.startsWith("/api/")) {
@@ -683,12 +722,31 @@ async function startPagesRouterServer(options) {
683
722
  // @ts-expect-error — duplex needed for streaming request bodies
684
723
  duplex: hasBody ? "half" : undefined,
685
724
  });
686
- // Build request context for has/missing condition matching.
687
- // headers and redirects run before middleware and use this pre-middleware
688
- // snapshot. beforeFiles, afterFiles, and fallback all run after middleware
689
- // per the Next.js execution order, so they use postMwReqCtx below.
725
+ // Build request context for pre-middleware config matching. Redirects
726
+ // run before middleware in Next.js. Header match conditions also use the
727
+ // original request snapshot even though header merging happens later so
728
+ // middleware response headers can still take precedence.
729
+ // beforeFiles, afterFiles, and fallback all run after middleware per the
730
+ // Next.js execution order, so they use postMwReqCtx below.
690
731
  const reqCtx = requestContextFromRequest(webRequest);
691
- // ── 4. Run middleware ─────────────────────────────────────────
732
+ // ── 4. Apply redirects from next.config.js ────────────────────
733
+ if (configRedirects.length) {
734
+ const redirect = matchRedirect(pathname, configRedirects, reqCtx);
735
+ if (redirect) {
736
+ // Guard against double-prefixing: only add basePath if destination
737
+ // doesn't already start with it.
738
+ // Sanitize the final destination to prevent protocol-relative URL open redirects.
739
+ const dest = sanitizeDestination(basePath &&
740
+ !isExternalUrl(redirect.destination) &&
741
+ !hasBasePath(redirect.destination, basePath)
742
+ ? basePath + redirect.destination
743
+ : redirect.destination);
744
+ res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
745
+ res.end();
746
+ return;
747
+ }
748
+ }
749
+ // ── 5. Run middleware ─────────────────────────────────────────
692
750
  let resolvedUrl = url;
693
751
  const middlewareHeaders = {};
694
752
  let middlewareRewriteStatus;
@@ -771,15 +829,17 @@ async function startPagesRouterServer(options) {
771
829
  // middleware per the Next.js execution order).
772
830
  const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, webRequest);
773
831
  webRequest = postMwReq;
832
+ // Config header matching must keep using the original normalized pathname
833
+ // even if middleware rewrites the downstream route/render target.
774
834
  let resolvedPathname = resolvedUrl.split("?")[0];
775
- // ── 5. Apply custom headers from next.config.js ───────────────
835
+ // ── 6. Apply custom headers from next.config.js ───────────────
776
836
  // Config headers are additive for multi-value headers (Vary,
777
837
  // Set-Cookie) and override for everything else. Set-Cookie values
778
838
  // are stored as arrays (RFC 6265 forbids comma-joining cookies).
779
839
  // Middleware headers take precedence: skip config keys already set
780
840
  // by middleware so middleware always wins for the same key.
781
841
  if (configHeaders.length) {
782
- const matched = matchHeaders(resolvedPathname, configHeaders, reqCtx);
842
+ const matched = matchHeaders(pathname, configHeaders, reqCtx);
783
843
  for (const h of matched) {
784
844
  const lk = h.key.toLowerCase();
785
845
  if (lk === "set-cookie") {
@@ -804,21 +864,6 @@ async function startPagesRouterServer(options) {
804
864
  }
805
865
  }
806
866
  }
807
- // ── 6. Apply redirects from next.config.js ────────────────────
808
- if (configRedirects.length) {
809
- const redirect = matchRedirect(resolvedPathname, configRedirects, reqCtx);
810
- if (redirect) {
811
- // Guard against double-prefixing: only add basePath if destination
812
- // doesn't already start with it.
813
- // Sanitize the final destination to prevent protocol-relative URL open redirects.
814
- const dest = sanitizeDestination(basePath && !redirect.destination.startsWith(basePath)
815
- ? basePath + redirect.destination
816
- : redirect.destination);
817
- res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
818
- res.end();
819
- return;
820
- }
821
- }
822
867
  // ── 7. Apply beforeFiles rewrites from next.config.js ─────────
823
868
  if (configRewrites.beforeFiles?.length) {
824
869
  const rewritten = matchRewrite(resolvedPathname, configRewrites.beforeFiles, postMwReqCtx);
@@ -909,5 +954,5 @@ async function startPagesRouterServer(options) {
909
954
  return server;
910
955
  }
911
956
  // Export helpers for testing
912
- export { sendCompressed, negotiateEncoding, COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, resolveHost, trustedHosts, trustProxy, nodeToWebRequest, mergeResponseHeaders };
957
+ export { sendCompressed, negotiateEncoding, COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, resolveHost, trustedHosts, trustProxy, nodeToWebRequest, mergeResponseHeaders, };
913
958
  //# sourceMappingURL=prod-server.js.map