vinext 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/README.md +2 -5
  2. package/dist/build/assets-ignore.d.ts +32 -0
  3. package/dist/build/assets-ignore.js +48 -0
  4. package/dist/build/client-build-config.d.ts +33 -1
  5. package/dist/build/client-build-config.js +66 -1
  6. package/dist/check.js +4 -3
  7. package/dist/cli.js +2 -0
  8. package/dist/client/navigation-runtime.d.ts +11 -2
  9. package/dist/client/navigation-runtime.js +1 -1
  10. package/dist/client/vinext-next-data.d.ts +2 -1
  11. package/dist/client/window-next.d.ts +6 -4
  12. package/dist/config/config-matchers.d.ts +31 -5
  13. package/dist/config/config-matchers.js +50 -3
  14. package/dist/config/next-config.d.ts +29 -3
  15. package/dist/config/next-config.js +32 -2
  16. package/dist/deploy.js +47 -304
  17. package/dist/entries/app-rsc-entry.d.ts +8 -2
  18. package/dist/entries/app-rsc-entry.js +61 -5
  19. package/dist/entries/app-rsc-manifest.js +20 -2
  20. package/dist/entries/pages-client-entry.js +1 -1
  21. package/dist/entries/pages-server-entry.js +16 -7
  22. package/dist/index.d.ts +0 -2
  23. package/dist/index.js +233 -280
  24. package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
  25. package/dist/plugins/dynamic-preload-metadata.js +415 -0
  26. package/dist/plugins/og-assets.js +2 -2
  27. package/dist/plugins/optimize-imports.d.ts +8 -4
  28. package/dist/plugins/optimize-imports.js +16 -12
  29. package/dist/plugins/postcss.js +18 -14
  30. package/dist/plugins/require-context.d.ts +6 -0
  31. package/dist/plugins/require-context.js +184 -0
  32. package/dist/plugins/sass.d.ts +53 -24
  33. package/dist/plugins/sass.js +249 -1
  34. package/dist/plugins/wasm-module-import.d.ts +15 -0
  35. package/dist/plugins/wasm-module-import.js +50 -0
  36. package/dist/routing/app-route-graph.d.ts +35 -2
  37. package/dist/routing/app-route-graph.js +179 -8
  38. package/dist/routing/file-matcher.js +1 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +16 -1
  41. package/dist/server/api-handler.js +4 -0
  42. package/dist/server/app-browser-entry.js +155 -215
  43. package/dist/server/app-browser-error.d.ts +4 -1
  44. package/dist/server/app-browser-error.js +7 -1
  45. package/dist/server/app-browser-history-controller.d.ts +104 -0
  46. package/dist/server/app-browser-history-controller.js +210 -0
  47. package/dist/server/app-browser-interception-context.d.ts +2 -1
  48. package/dist/server/app-browser-interception-context.js +15 -2
  49. package/dist/server/app-browser-navigation-controller.d.ts +13 -2
  50. package/dist/server/app-browser-navigation-controller.js +83 -4
  51. package/dist/server/app-browser-popstate.d.ts +12 -3
  52. package/dist/server/app-browser-popstate.js +19 -4
  53. package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
  54. package/dist/server/app-browser-rsc-redirect.js +30 -8
  55. package/dist/server/app-browser-state.d.ts +3 -0
  56. package/dist/server/app-browser-state.js +10 -10
  57. package/dist/server/app-browser-visible-commit.js +10 -8
  58. package/dist/server/app-fallback-renderer.d.ts +2 -1
  59. package/dist/server/app-fallback-renderer.js +3 -1
  60. package/dist/server/app-history-state.d.ts +45 -1
  61. package/dist/server/app-history-state.js +109 -1
  62. package/dist/server/app-middleware.js +1 -0
  63. package/dist/server/app-optimistic-routing.js +22 -1
  64. package/dist/server/app-page-boundary-render.d.ts +2 -1
  65. package/dist/server/app-page-boundary-render.js +45 -21
  66. package/dist/server/app-page-cache.js +9 -7
  67. package/dist/server/app-page-dispatch.d.ts +14 -0
  68. package/dist/server/app-page-dispatch.js +21 -6
  69. package/dist/server/app-page-element-builder.d.ts +23 -2
  70. package/dist/server/app-page-element-builder.js +58 -17
  71. package/dist/server/app-page-execution.d.ts +1 -1
  72. package/dist/server/app-page-execution.js +32 -17
  73. package/dist/server/app-page-render.d.ts +7 -1
  74. package/dist/server/app-page-render.js +11 -16
  75. package/dist/server/app-page-request.d.ts +9 -6
  76. package/dist/server/app-page-request.js +14 -10
  77. package/dist/server/app-page-response.d.ts +2 -2
  78. package/dist/server/app-page-response.js +2 -2
  79. package/dist/server/app-page-route-wiring.d.ts +3 -1
  80. package/dist/server/app-page-route-wiring.js +10 -8
  81. package/dist/server/app-page-stream.d.ts +37 -7
  82. package/dist/server/app-page-stream.js +36 -6
  83. package/dist/server/app-pages-bridge.d.ts +16 -0
  84. package/dist/server/app-pages-bridge.js +23 -3
  85. package/dist/server/app-route-handler-cache.d.ts +1 -0
  86. package/dist/server/app-route-handler-cache.js +1 -0
  87. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  88. package/dist/server/app-route-handler-dispatch.js +2 -0
  89. package/dist/server/app-route-handler-execution.d.ts +1 -0
  90. package/dist/server/app-route-handler-execution.js +1 -0
  91. package/dist/server/app-route-handler-response.js +11 -10
  92. package/dist/server/app-route-handler-runtime.d.ts +1 -0
  93. package/dist/server/app-route-handler-runtime.js +15 -3
  94. package/dist/server/app-rsc-handler.d.ts +1 -0
  95. package/dist/server/app-rsc-handler.js +5 -4
  96. package/dist/server/app-rsc-response-finalizer.js +1 -1
  97. package/dist/server/app-rsc-route-matching.d.ts +20 -1
  98. package/dist/server/app-rsc-route-matching.js +29 -4
  99. package/dist/server/app-server-action-execution.d.ts +22 -1
  100. package/dist/server/app-server-action-execution.js +73 -12
  101. package/dist/server/app-ssr-entry.d.ts +6 -0
  102. package/dist/server/app-ssr-entry.js +19 -3
  103. package/dist/server/app-ssr-stream.js +9 -1
  104. package/dist/server/dev-lockfile.js +2 -1
  105. package/dist/server/dev-server.d.ts +1 -1
  106. package/dist/server/dev-server.js +97 -43
  107. package/dist/server/headers.d.ts +8 -1
  108. package/dist/server/headers.js +8 -1
  109. package/dist/server/instrumentation-runtime.d.ts +6 -0
  110. package/dist/server/instrumentation-runtime.js +8 -0
  111. package/dist/server/isr-cache.d.ts +37 -1
  112. package/dist/server/isr-cache.js +85 -1
  113. package/dist/server/isr-decision.d.ts +79 -0
  114. package/dist/server/isr-decision.js +70 -0
  115. package/dist/server/metadata-route-response.js +5 -3
  116. package/dist/server/middleware-runtime.d.ts +13 -0
  117. package/dist/server/middleware-runtime.js +11 -7
  118. package/dist/server/middleware.js +1 -0
  119. package/dist/server/navigation-planner.d.ts +62 -1
  120. package/dist/server/navigation-planner.js +193 -3
  121. package/dist/server/navigation-trace.d.ts +12 -2
  122. package/dist/server/navigation-trace.js +11 -1
  123. package/dist/server/normalize-path.d.ts +0 -8
  124. package/dist/server/normalize-path.js +3 -1
  125. package/dist/server/otel-tracer-extension.d.ts +45 -0
  126. package/dist/server/otel-tracer-extension.js +89 -0
  127. package/dist/server/pages-api-route.d.ts +14 -3
  128. package/dist/server/pages-api-route.js +6 -1
  129. package/dist/server/pages-asset-tags.d.ts +15 -4
  130. package/dist/server/pages-asset-tags.js +18 -12
  131. package/dist/server/pages-data-route.js +5 -1
  132. package/dist/server/pages-node-compat.d.ts +5 -11
  133. package/dist/server/pages-node-compat.js +175 -118
  134. package/dist/server/pages-page-data.d.ts +38 -7
  135. package/dist/server/pages-page-data.js +64 -18
  136. package/dist/server/pages-page-handler.d.ts +10 -2
  137. package/dist/server/pages-page-handler.js +49 -20
  138. package/dist/server/pages-page-response.d.ts +55 -2
  139. package/dist/server/pages-page-response.js +74 -6
  140. package/dist/server/pages-readiness.d.ts +36 -0
  141. package/dist/server/pages-readiness.js +21 -0
  142. package/dist/server/pages-request-pipeline.d.ts +113 -0
  143. package/dist/server/pages-request-pipeline.js +230 -0
  144. package/dist/server/pages-revalidate.d.ts +15 -0
  145. package/dist/server/pages-revalidate.js +19 -0
  146. package/dist/server/prod-server.d.ts +45 -3
  147. package/dist/server/prod-server.js +182 -234
  148. package/dist/server/socket-error-backstop.d.ts +19 -1
  149. package/dist/server/socket-error-backstop.js +77 -4
  150. package/dist/shims/app-router-scroll.js +22 -4
  151. package/dist/shims/cache-runtime.js +39 -2
  152. package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
  153. package/dist/shims/dynamic-preload-chunks.js +77 -0
  154. package/dist/shims/dynamic.d.ts +4 -0
  155. package/dist/shims/dynamic.js +4 -2
  156. package/dist/shims/error-boundary.d.ts +17 -7
  157. package/dist/shims/error-boundary.js +8 -1
  158. package/dist/shims/error.js +37 -11
  159. package/dist/shims/fetch-cache.d.ts +22 -1
  160. package/dist/shims/fetch-cache.js +28 -1
  161. package/dist/shims/hash-scroll.d.ts +1 -0
  162. package/dist/shims/hash-scroll.js +3 -1
  163. package/dist/shims/head.js +6 -1
  164. package/dist/shims/headers.d.ts +16 -2
  165. package/dist/shims/headers.js +37 -1
  166. package/dist/shims/image-config.js +7 -1
  167. package/dist/shims/internal/app-route-detection.d.ts +6 -3
  168. package/dist/shims/internal/app-route-detection.js +10 -6
  169. package/dist/shims/internal/app-router-context.d.ts +5 -0
  170. package/dist/shims/internal/link-status-registry.d.ts +43 -0
  171. package/dist/shims/internal/link-status-registry.js +42 -0
  172. package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
  173. package/dist/shims/internal/route-pattern-for-warning.js +40 -0
  174. package/dist/shims/internal/utils.d.ts +1 -0
  175. package/dist/shims/link.js +20 -6
  176. package/dist/shims/metadata.d.ts +6 -2
  177. package/dist/shims/metadata.js +32 -14
  178. package/dist/shims/navigation.d.ts +9 -18
  179. package/dist/shims/navigation.js +96 -23
  180. package/dist/shims/router-state.d.ts +1 -0
  181. package/dist/shims/router-state.js +2 -0
  182. package/dist/shims/router.d.ts +6 -3
  183. package/dist/shims/router.js +156 -22
  184. package/dist/shims/script-nonce-context.d.ts +1 -1
  185. package/dist/shims/script-nonce-context.js +11 -3
  186. package/dist/shims/server.d.ts +17 -1
  187. package/dist/shims/server.js +31 -6
  188. package/dist/shims/slot.js +1 -1
  189. package/dist/shims/unified-request-context.js +1 -0
  190. package/dist/typegen.js +1 -0
  191. package/dist/utils/client-build-manifest.d.ts +8 -1
  192. package/dist/utils/client-build-manifest.js +41 -6
  193. package/dist/utils/client-entry-manifest.d.ts +11 -0
  194. package/dist/utils/client-entry-manifest.js +29 -0
  195. package/dist/utils/client-runtime-metadata.d.ts +45 -0
  196. package/dist/utils/client-runtime-metadata.js +63 -0
  197. package/dist/utils/hash.d.ts +17 -1
  198. package/dist/utils/hash.js +36 -1
  199. package/dist/utils/lazy-chunks.d.ts +27 -1
  200. package/dist/utils/lazy-chunks.js +65 -1
  201. package/dist/utils/manifest-paths.d.ts +20 -2
  202. package/dist/utils/manifest-paths.js +38 -3
  203. package/dist/utils/path.d.ts +2 -1
  204. package/dist/utils/path.js +5 -1
  205. package/package.json +6 -2
@@ -72,6 +72,12 @@ const CONFIG_FILES = [
72
72
  ];
73
73
  const DEFAULT_EXPIRE_TIME = 31536e3;
74
74
  /**
75
+ * Default cap for the App Router preload `Link` header length, matching the
76
+ * Next.js `defaultConfig.reactMaxHeadersLength`.
77
+ * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/reactMaxHeadersLength
78
+ */
79
+ const DEFAULT_REACT_MAX_HEADERS_LENGTH = 6e3;
80
+ /**
75
81
  * Check whether an error indicates a CJS module was loaded in an ESM context
76
82
  * (i.e. the file uses `require()` which is not available in ESM).
77
83
  */
@@ -506,6 +512,7 @@ async function resolveNextConfig(config, root = process.cwd()) {
506
512
  output: "",
507
513
  pageExtensions: normalizePageExtensions(),
508
514
  cacheComponents: false,
515
+ gestureTransition: false,
509
516
  prefetchInlining: false,
510
517
  redirects: [],
511
518
  rewrites: {
@@ -523,7 +530,9 @@ async function resolveNextConfig(config, root = process.cwd()) {
523
530
  optimizePackageImports: [],
524
531
  inlineCss: false,
525
532
  serverActionsBodySizeLimit: 1 * 1024 * 1024,
533
+ serverActionsBodySizeLimitLabel: "1 MB",
526
534
  expireTime: DEFAULT_EXPIRE_TIME,
535
+ reactMaxHeadersLength: DEFAULT_REACT_MAX_HEADERS_LENGTH,
527
536
  htmlLimitedBots: void 0,
528
537
  serverExternalPackages: [],
529
538
  cacheHandler: void 0,
@@ -588,7 +597,9 @@ async function resolveNextConfig(config, root = process.cwd()) {
588
597
  const experimental = readOptionalRecord(config.experimental);
589
598
  const serverActionsConfig = readOptionalRecord(experimental?.serverActions);
590
599
  const serverActionsAllowedOrigins = readStringArray(serverActionsConfig?.allowedOrigins);
591
- const serverActionsBodySizeLimit = parseBodySizeLimit(readOptionalBodySizeLimit(serverActionsConfig?.bodySizeLimit));
600
+ const serverActionsBodySizeLimitConfig = readOptionalBodySizeLimit(serverActionsConfig?.bodySizeLimit);
601
+ const serverActionsBodySizeLimit = parseBodySizeLimit(serverActionsBodySizeLimitConfig);
602
+ const serverActionsBodySizeLimitLabel = serverActionsBodySizeLimitConfig === void 0 ? "1 MB" : String(serverActionsBodySizeLimitConfig);
592
603
  const hashSalt = (readOptionalString(experimental?.outputHashSalt) ?? "") + (process.env.NEXT_HASH_SALT ?? "");
593
604
  const htmlLimitedBots = resolveHtmlLimitedBots(config.htmlLimitedBots);
594
605
  const rawOptimize = experimental?.optimizePackageImports;
@@ -645,6 +656,7 @@ async function resolveNextConfig(config, root = process.cwd()) {
645
656
  pageExtensions,
646
657
  instrumentationClientInject: Array.isArray(config.instrumentationClientInject) ? config.instrumentationClientInject.filter((x) => typeof x === "string") : [],
647
658
  cacheComponents: config.cacheComponents ?? false,
659
+ gestureTransition: experimental?.gestureTransition === true,
648
660
  prefetchInlining,
649
661
  redirects,
650
662
  rewrites,
@@ -658,7 +670,9 @@ async function resolveNextConfig(config, root = process.cwd()) {
658
670
  optimizePackageImports,
659
671
  inlineCss,
660
672
  serverActionsBodySizeLimit,
673
+ serverActionsBodySizeLimitLabel,
661
674
  expireTime: typeof config.expireTime === "number" ? config.expireTime : DEFAULT_EXPIRE_TIME,
675
+ reactMaxHeadersLength: typeof config.reactMaxHeadersLength === "number" ? config.reactMaxHeadersLength : DEFAULT_REACT_MAX_HEADERS_LENGTH,
662
676
  htmlLimitedBots,
663
677
  serverExternalPackages,
664
678
  cacheHandler,
@@ -680,12 +694,28 @@ async function resolveNextConfig(config, root = process.cwd()) {
680
694
  if (resolved.basePath !== "" && resolved.basePath !== "/" && resolved.assetPrefix === "") resolved.assetPrefix = resolved.basePath;
681
695
  return resolved;
682
696
  }
697
+ /**
698
+ * Whether an alias target is a relative filesystem path (`./foo`, `../foo`,
699
+ * or a bare `.`/`..`) that should be resolved against the project root.
700
+ *
701
+ * Both Next.js Turbopack `resolveAlias` and webpack `resolve.alias` accept two
702
+ * kinds of values: relative/absolute file paths AND bare package specifiers
703
+ * (e.g. `react`, `preact/compat`, `@scope/pkg`). Bare specifiers must be left
704
+ * verbatim so Vite/Rolldown re-resolves them through node_modules — resolving
705
+ * them against `root` mangles them into bogus `<root>/react` paths and breaks
706
+ * the build with "No such file or directory". See cloudflare/vinext#1507.
707
+ */
708
+ function isRelativeAliasTarget(value) {
709
+ return value === "." || value === ".." || value.startsWith("./") || value.startsWith("../");
710
+ }
683
711
  function normalizeAliasEntries(aliases, root) {
684
712
  if (!aliases) return {};
685
713
  const normalized = {};
686
714
  for (const [key, value] of Object.entries(aliases)) {
687
715
  if (typeof value !== "string") continue;
688
- normalized[key] = path.isAbsolute(value) ? value : path.resolve(root, value);
716
+ if (path.isAbsolute(value)) normalized[key] = value;
717
+ else if (isRelativeAliasTarget(value)) normalized[key] = path.resolve(root, value);
718
+ else normalized[key] = value;
689
719
  }
690
720
  return normalized;
691
721
  }
package/dist/deploy.js CHANGED
@@ -334,30 +334,14 @@ function generatePagesRouterWorkerEntry() {
334
334
  * Cloudflare Worker entry point -- auto-generated by vinext deploy.
335
335
  * Edit freely or delete to regenerate on next deploy.
336
336
  */
337
+ import { runPagesRequest, wrapMiddlewareWithBasePath } from "vinext/server/pages-request-pipeline";
338
+ import type { PagesPipelineDeps } from "vinext/server/pages-request-pipeline";
337
339
  import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath } from "vinext/server/image-optimization";
338
340
  import type { ImageConfig } from "vinext/server/image-optimization";
339
- import {
340
- matchRedirect,
341
- matchRewrite,
342
- requestContextFromRequest,
343
- applyMiddlewareRequestHeaders,
344
- isExternalUrl,
345
- proxyExternalRequest,
346
- sanitizeDestination,
347
- } from "vinext/config/config-matchers";
348
- import {
349
- applyConfigHeadersToHeaderRecord,
350
- cloneRequestWithHeaders,
351
- filterInternalHeaders,
352
- isOpenRedirectShaped,
353
- normalizeTrailingSlash,
354
- } from "vinext/server/request-pipeline";
355
- import { mergeHeaders } from "vinext/server/worker-utils";
341
+ import { cloneRequestWithHeaders, filterInternalHeaders, isOpenRedirectShaped } from "vinext/server/request-pipeline";
356
342
  import { notFoundStaticAssetResponse } from "vinext/server/http-error-responses";
357
343
  import { assetPrefixPathname, isNextStaticPath } from "vinext/utils/asset-prefix";
358
344
  import { hasBasePath, stripBasePath } from "vinext/utils/base-path";
359
- import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "vinext/server/pages-i18n";
360
- import { mergeRewriteQuery } from "vinext/utils/query";
361
345
 
362
346
  // @ts-expect-error -- virtual module resolved by vinext at build time
363
347
  import { renderPage, handleApiRoute, runMiddleware, vinextConfig, matchPageRoute } from "virtual:vinext-server-entry";
@@ -402,7 +386,6 @@ export default {
402
386
  try {
403
387
  const url = new URL(request.url);
404
388
  let pathname = url.pathname;
405
- let urlWithQuery = pathname + url.search;
406
389
 
407
390
  // Block protocol-relative URL open redirects in all shapes:
408
391
  // literal //evil.com, /\\\\evil.com
@@ -445,11 +428,12 @@ export default {
445
428
  {
446
429
  const stripped = stripBasePath(pathname, basePath);
447
430
  if (stripped !== pathname) {
448
- urlWithQuery = stripped + url.search;
431
+ const strippedUrl = new URL(request.url);
432
+ strippedUrl.pathname = stripped;
433
+ request = new Request(strippedUrl, request);
449
434
  pathname = stripped;
450
435
  }
451
436
  }
452
- const basePathState = { basePath, hadBasePath };
453
437
 
454
438
  // ── Image optimization via Cloudflare Images binding ──────────
455
439
  // Checked after basePath stripping so /<basePath>/_next/image works.
@@ -464,291 +448,50 @@ export default {
464
448
  }, allowedWidths, imageConfig);
465
449
  }
466
450
 
467
- // ── 2. Trailing slash normalization ────────────────────────────
468
- {
469
- const trailingSlashRedirect = normalizeTrailingSlash(
470
- pathname,
471
- basePath,
472
- trailingSlash,
473
- url.search,
474
- );
475
- if (trailingSlashRedirect) {
476
- return trailingSlashRedirect;
477
- }
478
- }
479
-
480
- // Build a request with the basePath-stripped URL for middleware and
481
- // downstream handlers. In Workers the incoming request URL still
482
- // contains basePath; prod-server constructs its webRequest from
483
- // the already-stripped URL, so we replicate that here.
484
- if (basePath) {
485
- const strippedUrl = new URL(request.url);
486
- strippedUrl.pathname = pathname;
487
- request = new Request(strippedUrl, request);
488
- }
489
-
490
- // Build request context for pre-middleware config matching. Redirects
491
- // run before middleware in Next.js. Header match conditions also use the
492
- // original request snapshot even though header merging happens later so
493
- // middleware response headers can still take precedence.
494
- // beforeFiles, afterFiles, and fallback rewrites run after middleware
495
- // (App Router order), so they use postMwReqCtx created after
496
- // x-middleware-request-* headers are unpacked into request.
497
- const reqCtx = requestContextFromRequest(request);
498
-
499
- // Default-locale path normalisation (issue #1336, item 4). Mirrors
500
- // Next.js's resolve-routes.ts: every request without a locale prefix
501
- // gets the (domain-aware) default locale prepended before config rule
502
- // matching so that locale-aware rules with :locale placeholders or
503
- // locale: false overrides still match default-locale URLs.
504
- const matchPathname = i18nConfig
505
- ? normalizeDefaultLocalePathname(pathname, i18nConfig, {
506
- hostname: url.hostname,
507
- })
508
- : pathname;
509
-
510
- // ── 3. Apply redirects from next.config.js ────────────────────
511
- if (configRedirects.length) {
512
- const redirect = matchRedirect(matchPathname, configRedirects, reqCtx, basePathState);
513
- if (redirect) {
514
- // Only prepend basePath when the request was actually under basePath.
515
- // Opt-out rules running on out-of-basepath requests must not receive
516
- // a basePath prefix.
517
- const dest = sanitizeDestination(
518
- basePath &&
519
- hadBasePath &&
520
- !isExternalUrl(redirect.destination) &&
521
- !hasBasePath(redirect.destination, basePath)
522
- ? basePath + redirect.destination
523
- : redirect.destination,
524
- );
525
- return new Response(null, {
526
- status: redirect.permanent ? 308 : 307,
527
- headers: { Location: dest },
528
- });
529
- }
530
- }
531
-
532
- // ── 4. Run middleware ──────────────────────────────────────────
533
- let resolvedUrl = urlWithQuery;
534
- const middlewareHeaders: Record<string, string | string[]> = {};
535
- let middlewareRewriteStatus: number | undefined;
536
- if (typeof runMiddleware === "function") {
537
- const result = await runMiddleware(request, ctx, { isDataRequest });
538
-
539
- // Bubble up waitUntil promises (e.g. Clerk telemetry/session sync)
540
- if (result.waitUntilPromises?.length) {
541
- for (const p of result.waitUntilPromises) {
542
- ctx.waitUntil(p);
543
- }
544
- }
545
-
546
- if (!result.continue) {
547
- if (result.redirectUrl) {
548
- const redirectHeaders = new Headers({ Location: result.redirectUrl });
549
- if (result.responseHeaders) {
550
- for (const [key, value] of result.responseHeaders) {
551
- redirectHeaders.append(key, value);
552
- }
553
- }
554
- return new Response(null, {
555
- status: result.redirectStatus ?? 307,
556
- headers: redirectHeaders,
557
- });
558
- }
559
- if (result.response) {
560
- return result.response;
561
- }
562
- }
563
-
564
- // Collect middleware response headers to merge into final response.
565
- // Use an array for Set-Cookie to preserve multiple values.
566
- if (result.responseHeaders) {
567
- for (const [key, value] of result.responseHeaders) {
568
- if (key === "set-cookie") {
569
- const existing = middlewareHeaders[key];
570
- if (Array.isArray(existing)) {
571
- existing.push(value);
572
- } else if (existing) {
573
- middlewareHeaders[key] = [existing as string, value];
574
- } else {
575
- middlewareHeaders[key] = [value];
576
- }
577
- } else {
578
- middlewareHeaders[key] = value;
579
- }
580
- }
581
- }
582
-
583
- // Apply middleware rewrite
584
- if (result.rewriteUrl) {
585
- resolvedUrl = result.rewriteUrl;
586
- }
587
-
588
- // Apply custom status code from middleware rewrite
589
- middlewareRewriteStatus = result.rewriteStatus;
590
- }
591
-
592
- // Unpack x-middleware-request-* headers into the actual request and strip
593
- // all x-middleware-* internal signals. Rebuilds postMwReqCtx for use by
594
- // beforeFiles, afterFiles, and fallback config rules (which run after
595
- // middleware per the Next.js execution order).
596
- const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, request);
597
- request = postMwReq;
598
-
599
- // Config header matching must keep using the original normalized pathname
600
- // even if middleware rewrites the downstream route/render target.
601
- let resolvedPathname = resolvedUrl.split("?")[0];
602
-
603
- // ── 5. Apply custom headers from next.config.js ───────────────
604
- // Config headers are additive for multi-value headers (Vary,
605
- // Set-Cookie) and override for everything else. Vary values are
606
- // comma-joined per HTTP spec. Set-Cookie values are accumulated
607
- // as arrays (RFC 6265 forbids comma-joining cookies).
608
- // Middleware headers take precedence: skip config keys already set
609
- // by middleware so middleware always wins for the same key.
610
- if (configHeaders.length) {
611
- applyConfigHeadersToHeaderRecord(middlewareHeaders, {
612
- configHeaders,
613
- pathname: matchPathname,
614
- requestContext: reqCtx,
615
- basePathState,
616
- });
617
- }
618
-
619
- if (isExternalUrl(resolvedUrl)) {
620
- const proxyResponse = await proxyExternalRequest(request, resolvedUrl);
621
- return mergeHeaders(proxyResponse, middlewareHeaders, undefined);
622
- }
623
-
624
- // Default-locale-normalised form of resolvedPathname for matching
625
- // against next.config.js rewrites (beforeFiles, afterFiles, fallback).
626
- const matchResolvedPathname = (p: string): string =>
627
- i18nConfig
628
- ? normalizeDefaultLocalePathname(p, i18nConfig, { hostname: url.hostname })
629
- : p;
630
-
631
- // ── 6. Apply beforeFiles rewrites from next.config.js ─────────
632
- let configRewriteFired = false;
633
- if (configRewrites.beforeFiles?.length) {
634
- const rewritten = matchRewrite(
635
- matchResolvedPathname(resolvedPathname),
636
- configRewrites.beforeFiles,
637
- postMwReqCtx,
638
- basePathState,
639
- );
640
- if (rewritten) {
641
- if (isExternalUrl(rewritten)) {
642
- return proxyExternalRequest(request, rewritten);
643
- }
644
- // Preserve original query params across rewrites (Next.js parity).
645
- resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
646
- resolvedPathname = resolvedUrl.split("?")[0];
647
- configRewriteFired = true;
648
- }
649
- }
650
-
651
- // Reject out-of-basePath requests that no rule rewrote. See the
652
- // matching comment in prod-server.ts step 7b.
653
- if (basePath && !hadBasePath && !configRewriteFired) {
654
- return new Response("This page could not be found", {
655
- status: 404,
656
- headers: { "Content-Type": "text/html; charset=utf-8" },
657
- });
658
- }
659
-
660
- // ── 7. API routes ─────────────────────────────────────────────
661
- // Forward ctx so handlePagesApiRoute can wrap the user handler in
662
- // runWithExecutionContext, making ctx.waitUntil() reachable from
663
- // after() and other shims that schedule deferred work.
664
- //
665
- // Strip the i18n locale prefix before the /api/ check so
666
- // /fr/api/ok resolves to the pages/api/ok handler (Next.js
667
- // parity -- see base-server.ts's normalizeLocalePath call).
668
- const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, vinextConfig?.i18n ?? null);
669
- const apiLookupPathname = apiLookupUrl.split("?")[0];
670
- if (apiLookupPathname.startsWith("/api/") || apiLookupPathname === "/api") {
671
- const response = typeof handleApiRoute === "function"
672
- ? await handleApiRoute(request, apiLookupUrl, ctx)
673
- : new Response("404 - API route not found", { status: 404 });
674
- return mergeHeaders(response, middlewareHeaders, middlewareRewriteStatus);
675
- }
676
-
677
- const pageMatch =
678
- typeof matchPageRoute === "function" ? matchPageRoute(resolvedPathname, request) : null;
679
-
680
- // ── 8. Apply afterFiles rewrites from next.config.js ──────────
681
- // These run after non-dynamic page routes but before dynamic routes.
682
- if ((!pageMatch || pageMatch.route.isDynamic) && configRewrites.afterFiles?.length) {
683
- const rewritten = matchRewrite(
684
- matchResolvedPathname(resolvedPathname),
685
- configRewrites.afterFiles,
686
- postMwReqCtx,
687
- basePathState,
688
- );
689
- if (rewritten) {
690
- if (isExternalUrl(rewritten)) {
691
- return proxyExternalRequest(request, rewritten);
692
- }
693
- resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
694
- resolvedPathname = resolvedUrl.split("?")[0];
695
- }
696
- }
697
-
698
- // ── 9. Page routes ────────────────────────────────────────────
699
- let response: Response | undefined;
700
- if (typeof renderPage === "function") {
701
- const renderPageMatch =
702
- typeof matchPageRoute === "function" ? matchPageRoute(resolvedPathname, request) : null;
703
- const shouldDeferErrorPageOnMiss =
704
- !isDataRequest && typeof matchPageRoute === "function" && !renderPageMatch;
705
- const initialRenderOptions = shouldDeferErrorPageOnMiss
706
- ? { renderErrorPageOnMiss: false }
707
- : undefined;
708
- response = await renderPage(request, resolvedUrl, null, ctx, undefined, initialRenderOptions);
709
-
710
- // ── 10. Fallback rewrites (if SSR returned 404) ─────────────
711
- let matchedFallbackRewrite = false;
712
- if (
713
- response &&
714
- response.status === 404 &&
715
- shouldDeferErrorPageOnMiss &&
716
- configRewrites.fallback?.length
717
- ) {
718
- const fallbackRewrite = matchRewrite(
719
- matchResolvedPathname(resolvedPathname),
720
- configRewrites.fallback,
721
- postMwReqCtx,
722
- basePathState,
723
- );
724
- if (fallbackRewrite) {
725
- if (isExternalUrl(fallbackRewrite)) {
726
- return proxyExternalRequest(request, fallbackRewrite);
727
- }
728
- matchedFallbackRewrite = true;
729
- response = await renderPage(
730
- request,
731
- mergeRewriteQuery(resolvedUrl, fallbackRewrite),
732
- null,
733
- ctx,
734
- );
735
- }
736
- }
737
- if (
738
- response &&
739
- response.status === 404 &&
740
- shouldDeferErrorPageOnMiss &&
741
- !matchedFallbackRewrite
742
- ) {
743
- response = await renderPage(request, resolvedUrl, null, ctx);
744
- }
745
- }
451
+ // Delegate the canonical 9-step Next.js pipeline to the shared owner.
452
+ // The worker adapter is responsible for: open-redirect guard, _next/static
453
+ // 404 short-circuit, header filtering, basePath stripping, and image
454
+ // optimization. runPagesRequest receives a clean, basePath-stripped request.
455
+ const deps: PagesPipelineDeps = {
456
+ basePath,
457
+ trailingSlash,
458
+ i18nConfig,
459
+ configRedirects,
460
+ configRewrites,
461
+ configHeaders,
462
+ hadBasePath,
463
+ // The worker adapter does not do _next/data URL normalization (no
464
+ // buildId available at request time). isDataReq is used by the pipeline
465
+ // only for renderPage options and shouldDeferErrorPageOnMiss -- false
466
+ // is correct here.
467
+ isDataReq: false,
468
+ isDataRequest,
469
+ ctx,
470
+ matchPageRoute: typeof matchPageRoute === "function" ? matchPageRoute : null,
471
+ // Pass the original (pre-basePath-stripping) URL to middleware so that
472
+ // request.nextUrl.basePath reflects whether the URL actually had the
473
+ // basePath prefix. Matches Next.js behavior and the prod-server.ts
474
+ // equivalent (shared via wrapMiddlewareWithBasePath).
475
+ runMiddleware:
476
+ typeof runMiddleware === "function"
477
+ ? wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath)
478
+ : null,
479
+ renderPage: typeof renderPage === "function"
480
+ ? (req, resolvedUrl, options, stagedHeaders) =>
481
+ renderPage(req, resolvedUrl, null, ctx, stagedHeaders, options)
482
+ : null,
483
+ handleApi: typeof handleApiRoute === "function"
484
+ ? (req, apiUrl) => handleApiRoute(req, apiUrl, ctx)
485
+ : null,
486
+ };
746
487
 
747
- if (!response) {
748
- return new Response("This page could not be found", { status: 404 });
488
+ const result = await runPagesRequest(request, deps);
489
+ if (result.type === "response") {
490
+ return result.response;
749
491
  }
492
+ // Should not reach here for prod/worker (all callbacks supplied).
493
+ return new Response("This page could not be found", { status: 404 });
750
494
 
751
- return mergeHeaders(response, middlewareHeaders, middlewareRewriteStatus);
752
495
  } catch (error) {
753
496
  console.error("[vinext] Worker error:", error);
754
497
  return new Response("Internal Server Error", { status: 500 });
@@ -17,7 +17,8 @@ type AppRouterConfig = {
17
17
  headers?: NextHeader[]; /** Extra origins allowed for server action CSRF checks (from experimental.serverActions.allowedOrigins). */
18
18
  allowedOrigins?: string[]; /** Extra origins allowed for dev server access (from allowedDevOrigins). */
19
19
  allowedDevOrigins?: string[]; /** Body size limit for server actions in bytes (from experimental.serverActions.bodySizeLimit). */
20
- bodySizeLimit?: number; /** Serialized next.config htmlLimitedBots regexp source. */
20
+ bodySizeLimit?: number; /** Verbatim body size limit config value (e.g. "2mb") for the "Body exceeded {limit} limit" error. */
21
+ bodySizeLimitLabel?: string; /** Serialized next.config htmlLimitedBots regexp source. */
21
22
  htmlLimitedBots?: string;
22
23
  /**
23
24
  * Allow-list of keys (from `experimental.clientTraceMetadata`) to surface
@@ -34,7 +35,12 @@ type AppRouterConfig = {
34
35
  * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix
35
36
  */
36
37
  assetPrefix?: string; /** Route-level expire fallback in seconds for ISR entries with numeric revalidate. */
37
- expireTime?: number; /** Maximum in-memory cache size in bytes. 0 disables the default memory cache. */
38
+ expireTime?: number;
39
+ /**
40
+ * Maximum total length (in characters) of the preload `Link` header emitted
41
+ * during App Router SSR. `0` disables emission. Defaults to 6000.
42
+ */
43
+ reactMaxHeadersLength?: number; /** Maximum in-memory cache size in bytes. 0 disables the default memory cache. */
38
44
  cacheMaxMemorySize?: number; /** Inline app CSS into production HTML (from experimental.inlineCss). */
39
45
  inlineCss?: boolean; /** Enables Next.js Cache Components semantics for App Router document HTML. */
40
46
  cacheComponents?: boolean; /** Internationalization routing config for middleware matcher locale handling. */