vinext 1.1.0 → 1.2.0

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 (234) hide show
  1. package/README.md +21 -9
  2. package/dist/build/client-build-config.d.ts +10 -0
  3. package/dist/build/client-build-config.js +18 -2
  4. package/dist/build/pages-client-assets-module.d.ts +8 -0
  5. package/dist/build/pages-client-assets-module.js +21 -1
  6. package/dist/build/prerender-paths.js +5 -3
  7. package/dist/build/run-prerender.js +1 -1
  8. package/dist/build/ssr-manifest.d.ts +2 -0
  9. package/dist/build/ssr-manifest.js +6 -2
  10. package/dist/check.js +7 -6
  11. package/dist/cli.js +2 -1
  12. package/dist/client/client-redirect-matcher.d.ts +14 -0
  13. package/dist/client/client-redirect-matcher.js +37 -0
  14. package/dist/client/client-redirects.d.ts +27 -0
  15. package/dist/client/client-redirects.js +28 -0
  16. package/dist/client/client-rewrites.d.ts +2 -1
  17. package/dist/client/client-rewrites.js +1 -1
  18. package/dist/config/config-matchers.d.ts +26 -11
  19. package/dist/config/config-matchers.js +78 -81
  20. package/dist/config/destination-params.d.ts +47 -0
  21. package/dist/config/destination-params.js +116 -0
  22. package/dist/config/next-config.d.ts +7 -0
  23. package/dist/config/next-config.js +3 -0
  24. package/dist/entries/app-rsc-entry.d.ts +4 -0
  25. package/dist/entries/app-rsc-entry.js +20 -6
  26. package/dist/entries/pages-client-entry.js +3 -1
  27. package/dist/entries/pages-server-entry.js +13 -37
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.js +134 -43
  30. package/dist/init-cloudflare.d.ts +9 -0
  31. package/dist/init-cloudflare.js +107 -31
  32. package/dist/init-platform.d.ts +4 -0
  33. package/dist/init-platform.js +27 -2
  34. package/dist/init.d.ts +1 -0
  35. package/dist/init.js +67 -3
  36. package/dist/plugins/ast-scope.d.ts +7 -0
  37. package/dist/plugins/ast-scope.js +59 -3
  38. package/dist/plugins/cache-flight-codec.d.ts +1 -1
  39. package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
  40. package/dist/plugins/dynamic-preload-metadata.js +9 -8
  41. package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
  42. package/dist/plugins/ignore-dynamic-requests.js +3 -4
  43. package/dist/plugins/middleware-server-only.d.ts +5 -4
  44. package/dist/plugins/middleware-server-only.js +8 -5
  45. package/dist/plugins/pages-node-externals.js +1 -1
  46. package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
  47. package/dist/plugins/rsc-scan-glob-imports.js +50 -0
  48. package/dist/plugins/strip-server-exports.js +262 -98
  49. package/dist/plugins/transform-result.d.ts +9 -5
  50. package/dist/plugins/transitive-externals.js +1 -1
  51. package/dist/plugins/typeof-window.d.ts +2 -2
  52. package/dist/plugins/use-cache-callable.js +8 -2
  53. package/dist/plugins/worker-server-only-imports.d.ts +20 -0
  54. package/dist/plugins/worker-server-only-imports.js +31 -0
  55. package/dist/plugins/worker-use-server.d.ts +25 -0
  56. package/dist/plugins/worker-use-server.js +129 -0
  57. package/dist/server/api-handler.d.ts +1 -0
  58. package/dist/server/api-handler.js +2 -1
  59. package/dist/server/app-browser-action-result.d.ts +1 -1
  60. package/dist/server/app-browser-action-result.js +9 -2
  61. package/dist/server/app-browser-navigation-controller.js +1 -1
  62. package/dist/server/app-browser-server-action-client.js +1 -1
  63. package/dist/server/app-middleware.d.ts +11 -0
  64. package/dist/server/app-middleware.js +17 -2
  65. package/dist/server/app-page-cache.d.ts +1 -1
  66. package/dist/server/app-page-cache.js +1 -1
  67. package/dist/server/app-page-dispatch.d.ts +3 -1
  68. package/dist/server/app-page-dispatch.js +4 -3
  69. package/dist/server/app-page-ppr-runtime.js +1 -1
  70. package/dist/server/app-page-render-observation.js +1 -1
  71. package/dist/server/app-page-request.js +53 -15
  72. package/dist/server/app-page-route-wiring.js +2 -2
  73. package/dist/server/app-pages-bridge.d.ts +1 -1
  74. package/dist/server/app-pages-bridge.js +2 -3
  75. package/dist/server/app-prerender-endpoints.js +9 -6
  76. package/dist/server/app-request-stage-dispatch.js +6 -2
  77. package/dist/server/app-request-stage-independent-entry.js +25 -5
  78. package/dist/server/app-response-stage-entry.js +10 -2
  79. package/dist/server/app-route-handler-cache.d.ts +1 -0
  80. package/dist/server/app-route-handler-cache.js +1 -0
  81. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  82. package/dist/server/app-route-handler-dispatch.js +5 -2
  83. package/dist/server/app-route-handler-execution.d.ts +1 -0
  84. package/dist/server/app-route-handler-execution.js +1 -0
  85. package/dist/server/app-route-handler-runtime.d.ts +4 -1
  86. package/dist/server/app-route-handler-runtime.js +45 -24
  87. package/dist/server/app-router-entry.js +24 -5
  88. package/dist/server/app-rsc-cache-busting.js +1 -1
  89. package/dist/server/app-rsc-errors.js +20 -16
  90. package/dist/server/app-rsc-handler.d.ts +7 -0
  91. package/dist/server/app-rsc-handler.js +85 -35
  92. package/dist/server/app-rsc-response-stage.js +4 -2
  93. package/dist/server/app-segment-config.d.ts +2 -1
  94. package/dist/server/app-server-action-execution.d.ts +2 -1
  95. package/dist/server/app-server-action-execution.js +61 -22
  96. package/dist/server/app-ssr-entry.js +2 -1
  97. package/dist/server/app-worker-stages.d.ts +5 -0
  98. package/dist/server/app-worker-stages.js +1 -1
  99. package/dist/server/cacheability-request.js +2 -2
  100. package/dist/server/client-build-files.d.ts +16 -0
  101. package/dist/server/client-build-files.js +36 -0
  102. package/dist/server/client-reuse-manifest.js +1 -1
  103. package/dist/server/dev-server.js +38 -27
  104. package/dist/server/dev-stack-sourcemap.js +18 -23
  105. package/dist/server/document-initial-head.d.ts +0 -11
  106. package/dist/server/document-initial-head.js +1 -1
  107. package/dist/server/forwarded-middleware-context.d.ts +5 -0
  108. package/dist/server/forwarded-middleware-context.js +22 -0
  109. package/dist/server/headers.d.ts +4 -1
  110. package/dist/server/headers.js +4 -1
  111. package/dist/server/http-conditional.d.ts +11 -0
  112. package/dist/server/http-conditional.js +10 -1
  113. package/dist/server/http-error-responses.d.ts +1 -1
  114. package/dist/server/image-optimization.d.ts +38 -0
  115. package/dist/server/image-optimization.js +93 -4
  116. package/dist/server/isr-cache.d.ts +10 -0
  117. package/dist/server/isr-cache.js +41 -6
  118. package/dist/server/metadata-route-response.js +9 -8
  119. package/dist/server/middleware-matcher.d.ts +2 -0
  120. package/dist/server/middleware-matcher.js +23 -2
  121. package/dist/server/middleware-runtime.d.ts +13 -0
  122. package/dist/server/middleware-runtime.js +33 -20
  123. package/dist/server/middleware.d.ts +1 -1
  124. package/dist/server/middleware.js +3 -1
  125. package/dist/server/multi-stage.d.ts +11 -0
  126. package/dist/server/normalize-path.d.ts +0 -13
  127. package/dist/server/normalize-path.js +1 -34
  128. package/dist/server/pages-api-route.d.ts +3 -2
  129. package/dist/server/pages-api-route.js +4 -3
  130. package/dist/server/pages-cache-tag.d.ts +12 -0
  131. package/dist/server/pages-cache-tag.js +19 -0
  132. package/dist/server/pages-client-assets.d.ts +2 -0
  133. package/dist/server/pages-data-route.d.ts +10 -0
  134. package/dist/server/pages-data-route.js +19 -2
  135. package/dist/server/pages-document-asset-props.d.ts +5 -1
  136. package/dist/server/pages-document-asset-props.js +13 -5
  137. package/dist/server/pages-document-splice.d.ts +19 -0
  138. package/dist/server/pages-document-splice.js +55 -0
  139. package/dist/server/pages-i18n.d.ts +12 -1
  140. package/dist/server/pages-i18n.js +18 -4
  141. package/dist/server/pages-node-compat.d.ts +16 -5
  142. package/dist/server/pages-node-compat.js +20 -12
  143. package/dist/server/pages-page-data.d.ts +32 -24
  144. package/dist/server/pages-page-data.js +50 -120
  145. package/dist/server/pages-page-handler.d.ts +0 -6
  146. package/dist/server/pages-page-handler.js +188 -126
  147. package/dist/server/pages-page-response.d.ts +12 -6
  148. package/dist/server/pages-page-response.js +41 -34
  149. package/dist/server/pages-request-pipeline.d.ts +10 -2
  150. package/dist/server/pages-request-pipeline.js +37 -18
  151. package/dist/server/pages-request-stage-entry.d.ts +6 -0
  152. package/dist/server/pages-request-stage-entry.js +71 -12
  153. package/dist/server/pages-response-stage-entry.js +4 -0
  154. package/dist/server/pages-revalidate.js +1 -1
  155. package/dist/server/pages-router-entry.js +4 -3
  156. package/dist/server/prerender-manifest.d.ts +3 -3
  157. package/dist/server/prerender-manifest.js +4 -3
  158. package/dist/server/prerender-work-unit-setup.js +4 -0
  159. package/dist/server/prod-server.d.ts +12 -0
  160. package/dist/server/prod-server.js +199 -69
  161. package/dist/server/proper-error.d.ts +4 -0
  162. package/dist/server/proper-error.js +31 -0
  163. package/dist/server/request-pipeline.d.ts +4 -1
  164. package/dist/server/request-pipeline.js +3 -2
  165. package/dist/server/revalidation-request.d.ts +1 -0
  166. package/dist/server/revalidation-request.js +1 -1
  167. package/dist/server/rsc-stream-hints.js +31 -2
  168. package/dist/server/seed-cache.d.ts +1 -0
  169. package/dist/server/seed-cache.js +5 -4
  170. package/dist/server/server-reference-loader.d.ts +4 -0
  171. package/dist/server/server-reference-loader.js +29 -0
  172. package/dist/server/socket-error-backstop.d.ts +9 -1
  173. package/dist/server/socket-error-backstop.js +46 -17
  174. package/dist/server/static-file-signal.d.ts +15 -4
  175. package/dist/server/static-file-signal.js +46 -12
  176. package/dist/server/worker-image-optimization.d.ts +34 -0
  177. package/dist/server/worker-image-optimization.js +86 -0
  178. package/dist/server/worker-stages.d.ts +1 -1
  179. package/dist/server/worker-stages.js +2 -2
  180. package/dist/server/worker-utils.d.ts +8 -3
  181. package/dist/server/worker-utils.js +12 -7
  182. package/dist/shims/app-router-scroll.js +4 -1
  183. package/dist/shims/app-router-tree-context.d.ts +5 -0
  184. package/dist/shims/app-router-tree-context.js +27 -0
  185. package/dist/shims/cache-callable-runtime.d.ts +4 -2
  186. package/dist/shims/cache-callable-runtime.js +21 -12
  187. package/dist/shims/cache-handler.js +1 -9
  188. package/dist/shims/cache-runtime.d.ts +6 -1
  189. package/dist/shims/cache-runtime.js +2 -1
  190. package/dist/shims/cache.d.ts +2 -2
  191. package/dist/shims/cache.js +40 -13
  192. package/dist/shims/cdn-cache.d.ts +8 -0
  193. package/dist/shims/cdn-cache.js +17 -1
  194. package/dist/shims/disable-smooth-scroll.d.ts +3 -0
  195. package/dist/shims/disable-smooth-scroll.js +36 -0
  196. package/dist/shims/document-placeholders.d.ts +19 -0
  197. package/dist/shims/document-placeholders.js +45 -0
  198. package/dist/shims/document.js +21 -5
  199. package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
  200. package/dist/shims/dynamic-preload-chunks.js +13 -9
  201. package/dist/shims/dynamic.d.ts +1 -1
  202. package/dist/shims/dynamic.js +60 -8
  203. package/dist/shims/fetch-cache-state.d.ts +66 -0
  204. package/dist/shims/fetch-cache-state.js +92 -0
  205. package/dist/shims/fetch-cache.d.ts +3 -67
  206. package/dist/shims/fetch-cache.js +160 -125
  207. package/dist/shims/head.d.ts +10 -6
  208. package/dist/shims/head.js +15 -13
  209. package/dist/shims/image.js +2 -1
  210. package/dist/shims/internal/work-store-scope.d.ts +5 -0
  211. package/dist/shims/internal/work-store-scope.js +24 -0
  212. package/dist/shims/navigation.js +31 -5
  213. package/dist/shims/request-context.d.ts +2 -0
  214. package/dist/shims/request-state-types.d.ts +2 -1
  215. package/dist/shims/router.js +12 -20
  216. package/dist/shims/server.d.ts +16 -0
  217. package/dist/shims/server.js +24 -4
  218. package/dist/shims/unified-request-context.d.ts +1 -1
  219. package/dist/shims/url-utils.d.ts +2 -0
  220. package/dist/shims/url-utils.js +3 -1
  221. package/dist/utils/client-runtime-metadata.js +1 -1
  222. package/dist/utils/hash.d.ts +7 -0
  223. package/dist/utils/hash.js +11 -1
  224. package/dist/utils/package-name.d.ts +6 -0
  225. package/dist/utils/package-name.js +12 -1
  226. package/dist/utils/plugin-rsc-version.d.ts +4 -0
  227. package/dist/utils/plugin-rsc-version.js +15 -0
  228. package/dist/utils/prerender-output-paths.js +15 -4
  229. package/dist/utils/public-file-path.d.ts +10 -2
  230. package/dist/utils/public-file-path.js +13 -9
  231. package/dist/utils/public-routes.js +2 -2
  232. package/dist/utils/react-version.d.ts +3 -0
  233. package/dist/utils/react-version.js +1 -1
  234. package/package.json +7 -3
@@ -3,6 +3,7 @@ import { buildRequestHeadersFromMiddlewareResponse, getUnconsumedMiddlewareReque
3
3
  import { analyzeRegexSafety } from "../utils/regex-safety.js";
4
4
  import { normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
5
5
  import { isExternalUrl } from "../utils/external-url.js";
6
+ import { substituteDestinationParams, substituteRedirectDestinationQuery } from "./destination-params.js";
6
7
  //#region src/config/config-matchers.ts
7
8
  /**
8
9
  * Cache for compiled regex patterns in matchConfigPattern.
@@ -44,14 +45,6 @@ const _compiledHeaderSourceCache = /* @__PURE__ */ new Map();
44
45
  */
45
46
  const _compiledConditionCache = /* @__PURE__ */ new Map();
46
47
  /**
47
- * Cache for destination substitution regexes in substituteDestinationParams.
48
- *
49
- * The regex depends only on the set of param keys captured from the matched
50
- * source pattern. Caching by sorted key list avoids recompiling a new RegExp
51
- * for repeated redirect/rewrite calls that use the same param shape.
52
- */
53
- const _compiledDestinationParamCache = /* @__PURE__ */ new Map();
54
- /**
55
48
  * Generic helper for the regex compilation caches above.
56
49
  *
57
50
  * Each cache stores the compiled artifact (or `null` when safeRegExp rejected
@@ -561,13 +554,10 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
561
554
  onRuleSourceMatch?.(redirect);
562
555
  const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
563
556
  if (!conditionParams) continue;
564
- localeMatch = {
565
- destination: substituteAndSanitizeDestination(redirect.destination, {
566
- [entry.paramName]: "",
567
- ...conditionParams
568
- }),
569
- permanent: redirect.permanent
570
- };
557
+ localeMatch = resolveRedirectMatch(redirect, {
558
+ [entry.paramName]: "",
559
+ ...conditionParams
560
+ });
571
561
  localeMatchIndex = entry.originalIndex;
572
562
  break;
573
563
  }
@@ -584,13 +574,10 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
584
574
  onRuleSourceMatch?.(redirect);
585
575
  const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
586
576
  if (!conditionParams) continue;
587
- localeMatch = {
588
- destination: substituteAndSanitizeDestination(redirect.destination, {
589
- [entry.paramName]: localePart,
590
- ...conditionParams
591
- }),
592
- permanent: redirect.permanent
593
- };
577
+ localeMatch = resolveRedirectMatch(redirect, {
578
+ [entry.paramName]: localePart,
579
+ ...conditionParams
580
+ });
594
581
  localeMatchIndex = entry.originalIndex;
595
582
  break;
596
583
  }
@@ -604,13 +591,10 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
604
591
  onRuleSourceMatch?.(redirect);
605
592
  const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
606
593
  if (!conditionParams) continue;
607
- return {
608
- destination: substituteAndSanitizeDestination(redirect.destination, {
609
- ...params,
610
- ...conditionParams
611
- }),
612
- permanent: redirect.permanent
613
- };
594
+ return resolveRedirectMatch(redirect, {
595
+ ...params,
596
+ ...conditionParams
597
+ });
614
598
  }
615
599
  }
616
600
  return localeMatch;
@@ -636,12 +620,24 @@ function matchRewrite(pathname, rewrites, ctx, basePathState = _BASEPATH_DEFAULT
636
620
  ...params,
637
621
  ...conditionParams
638
622
  };
639
- return substituteAndSanitizeRewriteDestination(rewrite.destination, rewriteParams);
623
+ return substituteAndSanitizeRewriteDestination(serializeRewriteDestinationTemplate(rewrite.destination), rewriteParams);
640
624
  }
641
625
  }
642
626
  return null;
643
627
  }
644
628
  /**
629
+ * Next.js prepareDestination URL-parses the destination template before it
630
+ * substitutes params, so a literal `é` routes as `%C3%A9` while substituted
631
+ * values stay verbatim: a captured `../admin` is never resolved to `/admin`.
632
+ *
633
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
634
+ */
635
+ function serializeRewriteDestinationTemplate(destination) {
636
+ if (!destination.startsWith("/") || destination.startsWith("//")) return destination;
637
+ const parsed = new URL(destination, "http://n");
638
+ return parsed.pathname + parsed.search + parsed.hash;
639
+ }
640
+ /**
645
641
  * Check whether a rewrite source can match a pathname without evaluating its
646
642
  * request-dependent `has` / `missing` conditions.
647
643
  *
@@ -654,47 +650,20 @@ function matchesRewriteSource(pathname, rewrite, basePathState = _BASEPATH_DEFAU
654
650
  return shouldEvaluateRule(rewrite.basePath, basePathState) && matchConfigPattern(pathname, rewrite.source) !== null;
655
651
  }
656
652
  /**
657
- * Substitute all matched route params into a redirect/rewrite destination.
658
- *
659
- * Handles repeated params (e.g. `/api/:id/:id`) and catch-all suffix forms
660
- * (`:path*`, `:path+`) in a single pass. Unknown params are left intact.
661
- */
662
- function substituteDestinationParams(destination, params) {
663
- const keys = Object.keys(params);
664
- if (keys.length === 0) return destination;
665
- const sortedKeys = [...keys].sort((a, b) => b.length - a.length);
666
- const cacheKey = sortedKeys.join("\0");
667
- let paramRe = _compiledDestinationParamCache.get(cacheKey);
668
- if (!paramRe) {
669
- const paramAlternation = sortedKeys.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
670
- paramRe = new RegExp(`:(${paramAlternation})([+*])?(?![A-Za-z0-9_])`, "g");
671
- _compiledDestinationParamCache.set(cacheKey, paramRe);
672
- }
673
- const replaceParams = (value, encodeParam) => value.replace(paramRe, (_token, key) => encodeParam(params[key]));
674
- const hashIndex = destination.indexOf("#");
675
- const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
676
- const hash = hashIndex === -1 ? "" : destination.slice(hashIndex);
677
- const queryIndex = beforeHash.indexOf("?");
678
- if (queryIndex !== -1) {
679
- const beforeQuery = beforeHash.slice(0, queryIndex);
680
- const query = beforeHash.slice(queryIndex + 1);
681
- return `${replaceParams(beforeQuery, (value) => value)}?${replaceParams(query, encodeDestinationQueryParamValue)}${replaceParams(hash, (value) => value)}`;
682
- }
683
- return replaceParams(destination, (value) => value);
684
- }
685
- function encodeDestinationQueryParamValue(value) {
686
- const params = new URLSearchParams();
687
- params.set("", value);
688
- return params.toString().slice(1);
689
- }
690
- /**
691
653
  * Substitute params into a redirect/rewrite destination and sanitize the
692
654
  * result. Used by every redirect/rewrite branch — the substitution can
693
655
  * introduce protocol-relative URLs (e.g. `//evil.com` from a decoded `%2F`
694
656
  * in a catch-all param), which sanitizeDestination collapses.
695
657
  */
696
- function substituteAndSanitizeDestination(destination, params) {
697
- return sanitizeDestination(substituteDestinationParams(destination, params));
658
+ function substituteAndSanitizeDestination(destination, params, kind) {
659
+ return sanitizeDestination(substituteDestinationParams(destination, params, kind));
660
+ }
661
+ function resolveRedirectMatch(redirect, params) {
662
+ return {
663
+ destination: substituteAndSanitizeDestination(redirect.destination, params, "redirect"),
664
+ permanent: redirect.permanent,
665
+ destinationQuery: substituteRedirectDestinationQuery(redirect.destination, params)
666
+ };
698
667
  }
699
668
  /**
700
669
  * Match Next.js's rewrite-specific prepareDestination behavior: source params
@@ -704,7 +673,7 @@ function substituteAndSanitizeDestination(destination, params) {
704
673
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
705
674
  */
706
675
  function substituteAndSanitizeRewriteDestination(destination, params) {
707
- const rewritten = substituteAndSanitizeDestination(destination, params);
676
+ const rewritten = substituteAndSanitizeDestination(destination, params, "rewrite");
708
677
  if (!shouldAppendRewriteParamsToQuery(destination, params)) return rewritten;
709
678
  const existingQueryKeys = getDestinationQueryKeys(destination);
710
679
  const paramsToAppend = [];
@@ -771,11 +740,12 @@ function appendQueryParams(url, params) {
771
740
  * users off-site.
772
741
  *
773
742
  * This function collapses any leading double (or more) slashes to a single
774
- * slash for non-external (relative) destinations.
743
+ * slash for non-external (relative) destinations, including tab/newline and
744
+ * leading C0 control characters that browsers ignore while parsing.
775
745
  */
776
746
  function sanitizeDestination(dest) {
777
747
  if (dest.startsWith("http://") || dest.startsWith("https://")) return dest;
778
- dest = dest.replace(/^[\\/]+/, "/");
748
+ dest = dest.replace(/^[\u0000-\u0020]*(?:[\\/][\t\n\r]*)+/, "/");
779
749
  return dest;
780
750
  }
781
751
  /**
@@ -795,13 +765,20 @@ function sanitizeDestination(dest) {
795
765
  * still treated as an RSC fetch. Dropping it breaks RSC fetch semantics
796
766
  * (issue #1529).
797
767
  *
798
- * Destination query params win — a request param is only carried over when
799
- * the destination does not already specify that key. Mirrors the merge
800
- * semantics in `proxyExternalRequest`. External destinations are returned
801
- * untouched (a config redirect to another origin should not leak the
802
- * original request's query).
768
+ * Ported from Next.js's `{ ...requestQuery, ...destinationQuery }` merge and
769
+ * `stringifyQuery`: request keys keep their order (integer-like keys first, as
770
+ * in a JS object), a destination key overrides the request value in place,
771
+ * and destination-only keys follow. Request keys and values are re-encoded;
772
+ * destination query text is emitted verbatim, except that, like Next.js,
773
+ * destination strings equal to a request key or value are re-encoded too.
774
+ * Pass the match's
775
+ * `destinationQuery` so substituted params keep their value boundaries;
776
+ * without it the destination's own query is split. External destinations are returned untouched (a config redirect to another
777
+ * origin should not leak the original request's query).
778
+ *
779
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
803
780
  */
804
- function preserveRedirectDestinationQuery(destination, requestSearch) {
781
+ function preserveRedirectDestinationQuery(destination, requestSearch, destinationQuery) {
805
782
  if (requestSearch === "" || requestSearch === "?" || isExternalUrl(destination)) return destination;
806
783
  const requestParams = new URLSearchParams(requestSearch);
807
784
  if ([...requestParams.keys()].length === 0) return destination;
@@ -810,13 +787,29 @@ function preserveRedirectDestinationQuery(destination, requestSearch) {
810
787
  const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
811
788
  const queryIndex = beforeHash.indexOf("?");
812
789
  const pathPart = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);
813
- const destQuery = queryIndex === -1 ? "" : beforeHash.slice(queryIndex + 1);
814
- const merged = new URLSearchParams(destQuery);
815
- const destKeys = new Set(merged.keys());
816
- for (const [key, value] of requestParams) if (!destKeys.has(key)) merged.append(key, value);
817
- const mergedQuery = merged.toString();
790
+ const requestStrings = /* @__PURE__ */ new Set();
791
+ const requestParts = Object.create(null);
792
+ for (const [key, value] of requestParams) {
793
+ requestStrings.add(key);
794
+ requestStrings.add(value);
795
+ (requestParts[key] ??= []).push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
796
+ }
797
+ const encode = (text) => requestStrings.has(text) ? encodeURIComponent(text) : text;
798
+ const destinationParts = Object.create(null);
799
+ for (const [key, keyText, valueText] of destinationQuery ?? substituteRedirectDestinationQuery(destination, {})) (destinationParts[key] ??= []).push(valueText === null ? encode(keyText) : `${encode(keyText)}=${encode(valueText)}`);
800
+ const mergedQuery = Object.values({
801
+ ...requestParts,
802
+ ...destinationParts
803
+ }).flat().join("&");
818
804
  return mergedQuery === "" ? `${pathPart}${hash}` : `${pathPart}?${mergedQuery}${hash}`;
819
805
  }
806
+ function parseExternalRewriteUrl(externalUrl) {
807
+ try {
808
+ return new URL(externalUrl);
809
+ } catch {
810
+ return null;
811
+ }
812
+ }
820
813
  /**
821
814
  * Proxy an incoming request to an external URL and return the upstream response.
822
815
  *
@@ -828,7 +821,11 @@ function preserveRedirectDestinationQuery(destination, requestSearch) {
828
821
  */
829
822
  async function proxyExternalRequest(request, externalUrl) {
830
823
  const originalUrl = new URL(request.url);
831
- const targetUrl = new URL(externalUrl);
824
+ const targetUrl = parseExternalRewriteUrl(externalUrl);
825
+ if (!targetUrl) {
826
+ console.error("[vinext] Invalid external rewrite destination:", externalUrl);
827
+ return new Response("Internal Server Error", { status: 500 });
828
+ }
832
829
  const destinationKeys = new Set(targetUrl.searchParams.keys());
833
830
  for (const [key, value] of originalUrl.searchParams) if (!destinationKeys.has(key)) targetUrl.searchParams.append(key, value);
834
831
  const headers = new Headers(request.headers);
@@ -0,0 +1,47 @@
1
+ //#region src/config/destination-params.d.ts
2
+ /**
3
+ * Destination param substitution for next.config.js redirects and rewrites.
4
+ *
5
+ * Kept free of server-only imports so the Pages Router client can apply simple
6
+ * beforeFiles rewrites with exactly the same substitution as the server.
7
+ */
8
+ /**
9
+ * Substitute all matched route params into a redirect/rewrite destination.
10
+ *
11
+ * Handles repeated params (e.g. `/api/:id/:id`) and catch-all suffix forms
12
+ * (`:path*`, `:path+`) in a single pass. Unknown params are left intact.
13
+ *
14
+ * Query substitution follows how Next.js consumes each destination kind:
15
+ *
16
+ * - A rewrite's query is parsed into an object before substitution, so the
17
+ * target sees each param verbatim as one value. vinext encodes the whole
18
+ * value so it round-trips back to that verbatim string.
19
+ * - A redirect's query is emitted as Location text with params inserted
20
+ * verbatim, so an already percent-encoded capture is decoded once by the
21
+ * client. vinext inserts redirect params verbatim too.
22
+ *
23
+ * A rewrite's absolute destination is proxied server-side, so params in its
24
+ * authority (`https://:tenant.example.com/`) are percent-encoded, keeping the
25
+ * `%XX` escapes a raw path capture already carries. A decoded `has` capture
26
+ * carrying `#`, `/`, `?`, `@` or `:` then makes the host invalid instead of
27
+ * moving the proxy to another host. Next.js substitutes the hostname verbatim
28
+ * and can be retargeted this way; vinext is stricter.
29
+ *
30
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
31
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
32
+ */
33
+ export declare function substituteDestinationParams(destination: string, params: Record<string, string>, kind: "redirect" | "rewrite"): string;
34
+ /**
35
+ * Split a redirect destination's query into parts before substituting params,
36
+ * as Next.js's prepareDestination parses the template query first. Each part
37
+ * is `[key, keyText, valueText]`: the texts are the part's template text with
38
+ * params substituted verbatim (`valueText` is `null` without an `=`), and
39
+ * `key` is the decoded key, used only to match request params. Keeping these
40
+ * boundaries means a param containing `&` stays one value when the request
41
+ * query is merged in.
42
+ *
43
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
44
+ */
45
+ export declare function substituteRedirectDestinationQuery(destination: string, params: Record<string, string>): RedirectDestinationQueryPart[];
46
+ export type RedirectDestinationQueryPart = [key: string, keyText: string, valueText: string | null];
47
+ //#endregion
@@ -0,0 +1,116 @@
1
+ //#region src/config/destination-params.ts
2
+ /**
3
+ * Destination param substitution for next.config.js redirects and rewrites.
4
+ *
5
+ * Kept free of server-only imports so the Pages Router client can apply simple
6
+ * beforeFiles rewrites with exactly the same substitution as the server.
7
+ */
8
+ /**
9
+ * Cache for destination substitution regexes in substituteDestinationParams.
10
+ *
11
+ * The regex depends only on the set of param keys captured from the matched
12
+ * source pattern. Caching by sorted key list avoids recompiling a new RegExp
13
+ * for repeated redirect/rewrite calls that use the same param shape.
14
+ */
15
+ const _compiledDestinationParamCache = /* @__PURE__ */ new Map();
16
+ /**
17
+ * Substitute all matched route params into a redirect/rewrite destination.
18
+ *
19
+ * Handles repeated params (e.g. `/api/:id/:id`) and catch-all suffix forms
20
+ * (`:path*`, `:path+`) in a single pass. Unknown params are left intact.
21
+ *
22
+ * Query substitution follows how Next.js consumes each destination kind:
23
+ *
24
+ * - A rewrite's query is parsed into an object before substitution, so the
25
+ * target sees each param verbatim as one value. vinext encodes the whole
26
+ * value so it round-trips back to that verbatim string.
27
+ * - A redirect's query is emitted as Location text with params inserted
28
+ * verbatim, so an already percent-encoded capture is decoded once by the
29
+ * client. vinext inserts redirect params verbatim too.
30
+ *
31
+ * A rewrite's absolute destination is proxied server-side, so params in its
32
+ * authority (`https://:tenant.example.com/`) are percent-encoded, keeping the
33
+ * `%XX` escapes a raw path capture already carries. A decoded `has` capture
34
+ * carrying `#`, `/`, `?`, `@` or `:` then makes the host invalid instead of
35
+ * moving the proxy to another host. Next.js substitutes the hostname verbatim
36
+ * and can be retargeted this way; vinext is stricter.
37
+ *
38
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
39
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
40
+ */
41
+ function substituteDestinationParams(destination, params, kind) {
42
+ const paramRe = getDestinationParamRegex(params);
43
+ if (!paramRe) return destination;
44
+ const replaceParams = (value, encodeParam) => value.replace(paramRe, (_token, key) => encodeParam(params[key]));
45
+ if (kind === "redirect") return replaceParams(destination, (value) => value);
46
+ const hashIndex = destination.indexOf("#");
47
+ const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
48
+ const hash = hashIndex === -1 ? "" : destination.slice(hashIndex);
49
+ const queryIndex = beforeHash.indexOf("?");
50
+ const beforeQuery = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);
51
+ const authorityEnd = getAbsoluteUrlAuthorityEnd(beforeQuery.replace(paramRe, (token) => "x".repeat(token.length)));
52
+ return `${`${replaceParams(beforeQuery.slice(0, authorityEnd), encodeAuthorityParam)}${replaceParams(beforeQuery.slice(authorityEnd), (value) => value)}`}${queryIndex === -1 ? "" : `?${replaceParams(beforeHash.slice(queryIndex + 1), encodeRewriteQueryParamValue)}`}${replaceParams(hash, (value) => value)}`;
53
+ }
54
+ function getAbsoluteUrlAuthorityEnd(value) {
55
+ const scheme = /^[a-z][a-z0-9+.-]*:[/\\\t\n\r]*/i.exec(value);
56
+ if (!scheme && /^[/\\]/.test(value)) return 0;
57
+ const start = scheme ? scheme[0].length : 0;
58
+ const pathStart = value.slice(start).search(/[/\\]/);
59
+ return pathStart === -1 ? value.length : start + pathStart;
60
+ }
61
+ /**
62
+ * Split a redirect destination's query into parts before substituting params,
63
+ * as Next.js's prepareDestination parses the template query first. Each part
64
+ * is `[key, keyText, valueText]`: the texts are the part's template text with
65
+ * params substituted verbatim (`valueText` is `null` without an `=`), and
66
+ * `key` is the decoded key, used only to match request params. Keeping these
67
+ * boundaries means a param containing `&` stays one value when the request
68
+ * query is merged in.
69
+ *
70
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
71
+ */
72
+ function substituteRedirectDestinationQuery(destination, params) {
73
+ const hashIndex = destination.indexOf("#");
74
+ const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
75
+ const queryIndex = beforeHash.indexOf("?");
76
+ if (queryIndex === -1) return [];
77
+ const paramRe = getDestinationParamRegex(params);
78
+ const substitute = (value) => paramRe ? value.replace(paramRe, (_token, key) => params[key]) : value;
79
+ return beforeHash.slice(queryIndex + 1).split("&").filter(Boolean).map((part) => {
80
+ const equalsIndex = part.indexOf("=");
81
+ const keyText = substitute(equalsIndex === -1 ? part : part.slice(0, equalsIndex));
82
+ const valueText = equalsIndex === -1 ? null : substitute(part.slice(equalsIndex + 1));
83
+ return [
84
+ decodeQueryKey(keyText),
85
+ keyText,
86
+ valueText
87
+ ];
88
+ });
89
+ }
90
+ function decodeQueryKey(keyText) {
91
+ const [entry] = new URLSearchParams(keyText.replace(/[&=]/g, (char) => encodeURIComponent(char)));
92
+ return entry?.[0] ?? "";
93
+ }
94
+ function getDestinationParamRegex(params) {
95
+ const keys = Object.keys(params);
96
+ if (keys.length === 0) return null;
97
+ const sortedKeys = [...keys].sort((a, b) => b.length - a.length);
98
+ const cacheKey = sortedKeys.join("\0");
99
+ let paramRe = _compiledDestinationParamCache.get(cacheKey);
100
+ if (!paramRe) {
101
+ const paramAlternation = sortedKeys.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
102
+ paramRe = new RegExp(`:(${paramAlternation})([+*])?(?![A-Za-z0-9_])`, "g");
103
+ _compiledDestinationParamCache.set(cacheKey, paramRe);
104
+ }
105
+ return paramRe;
106
+ }
107
+ function encodeAuthorityParam(value) {
108
+ return value.replace(/%(?![0-9a-f]{2})|[^A-Za-z0-9._~%-]/giu, encodeURIComponent);
109
+ }
110
+ function encodeRewriteQueryParamValue(value) {
111
+ const params = new URLSearchParams();
112
+ params.set("", value);
113
+ return params.toString().slice(1);
114
+ }
115
+ //#endregion
116
+ export { substituteDestinationParams, substituteRedirectDestinationQuery };
@@ -111,6 +111,12 @@ export type NextConfig = {
111
111
  crossOrigin?: "anonymous" | "use-credentials";
112
112
  /** Whether to add trailing slashes */
113
113
  trailingSlash?: boolean;
114
+ /**
115
+ * Skip the automatic trailing-slash redirects and keep `<Link>`/router
116
+ * hrefs exactly as written.
117
+ * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/skipTrailingSlashRedirect
118
+ */
119
+ skipTrailingSlashRedirect?: boolean;
114
120
  /**
115
121
  * Compress responses from the Node production server. Defaults to true.
116
122
  * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/compress
@@ -317,6 +323,7 @@ export type ResolvedNextConfig = {
317
323
  */
318
324
  assetPrefix: string;
319
325
  trailingSlash: boolean;
326
+ skipTrailingSlashRedirect: boolean;
320
327
  /** Whether the Node production server compresses responses (`compress`, default true). */
321
328
  compress: boolean;
322
329
  skipProxyUrlNormalize: boolean;
@@ -373,6 +373,7 @@ function warnDeprecatedConfigOptions(config, root) {
373
373
  ["experimental.instrumentationHook", `\`experimental.instrumentationHook\` is no longer needed, because \`instrumentation.js\` is available by default. You can remove it from ${configFileName}.`]
374
374
  ];
375
375
  for (const [propertyPath, warning] of warnings) if (hasConfigProperty(config, propertyPath)) warnConfigOnce(warning);
376
+ if (readOptionalRecord(config.experimental)?.skipTrailingSlashRedirect != null) warnConfigOnce(`\`experimental.skipTrailingSlashRedirect\` has been moved to \`skipTrailingSlashRedirect\`. Please update your ${configFileName} file accordingly.`);
376
377
  }
377
378
  async function resolveNextConfigInput(config, phase = PHASE_DEVELOPMENT_SERVER) {
378
379
  return await resolveConfigValue(config, phase);
@@ -761,6 +762,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
761
762
  basePath: "",
762
763
  assetPrefix: "",
763
764
  trailingSlash: false,
765
+ skipTrailingSlashRedirect: false,
764
766
  compress: true,
765
767
  skipProxyUrlNormalize: false,
766
768
  typescript: {},
@@ -947,6 +949,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
947
949
  basePath: config.basePath ?? "",
948
950
  assetPrefix: normalizeAssetPrefix(config.assetPrefix),
949
951
  trailingSlash: config.trailingSlash ?? false,
952
+ skipTrailingSlashRedirect: (experimental?.skipTrailingSlashRedirect ?? config.skipTrailingSlashRedirect) === true,
950
953
  compress: config.compress !== false,
951
954
  skipProxyUrlNormalize: config.skipProxyUrlNormalize ?? config.skipMiddlewareUrlNormalize ?? false,
952
955
  typescript: typeof config.typescript?.tsconfigPath === "string" ? { tsconfigPath: config.typescript.tsconfigPath } : {},
@@ -93,6 +93,10 @@ type AppRouterConfig = {
93
93
  draftModeSecret?: string;
94
94
  /** Server-only token used to authorize build-time prerender endpoints. */
95
95
  prerenderSecret?: string;
96
+ /** next.config `skipTrailingSlashRedirect`. */
97
+ skipTrailingSlashRedirect?: boolean;
98
+ /** Dev-only key authenticating the hybrid Pages handler's forwarded middleware context. */
99
+ devForwardedMiddlewareContextKey?: string;
96
100
  };
97
101
  /** Generate the module-free App request stage used by multi-stage Worker outputs. */
98
102
  export declare function generateAppRequestRscEntry(appDir: string, routes: AppRoute[], middlewarePath?: string | null, metadataRoutes?: MetadataFileRoute[], _globalErrorPath?: string | null, basePath?: string, trailingSlash?: boolean, config?: AppRouterConfig, instrumentationPath?: string | null): string;
@@ -25,12 +25,12 @@ import { randomUUID } from "node:crypto";
25
25
  const DEFAULT_EXPIRE_TIME = 31536e3;
26
26
  const DEFAULT_REACT_MAX_HEADERS_LENGTH = 6e3;
27
27
  const middlewareRequestHeadersPath = resolveEntryPath("../utils/middleware-request-headers.js", import.meta.url);
28
- const normalizePathModulePath = resolveEntryPath("../server/normalize-path.js", import.meta.url);
29
28
  const appRouteHandlerDispatchPath = resolveEntryPath("../server/app-route-handler-dispatch.js", import.meta.url);
30
29
  const appRouteRequestBuiltInsPath = resolveEntryPath("../server/app-route-request-built-ins.js", import.meta.url);
31
30
  const appRouteHandlerResponsePath = resolveEntryPath("../server/app-route-handler-response.js", import.meta.url);
32
31
  const appRouteHandlerMiddlewareContextPath = resolveEntryPath("../server/app-route-handler-middleware-context.js", import.meta.url);
33
32
  const appServerActionExecutionPath = resolveEntryPath("../server/app-server-action-execution.js", import.meta.url);
33
+ const serverReferenceLoaderPath = resolveEntryPath("../server/server-reference-loader.js", import.meta.url);
34
34
  const appActionForwardingPath = resolveEntryPath("../server/app-action-forwarding.js", import.meta.url);
35
35
  const appMiddlewarePath = resolveEntryPath("../server/app-middleware.js", import.meta.url);
36
36
  const metadataRouteResponsePath = resolveEntryPath("../server/metadata-route-response.js", import.meta.url);
@@ -200,6 +200,7 @@ import { dispatchAppRequestStage as __dispatchAppRequestStage } from ${JSON.stri
200
200
  import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters } from "virtual:vinext-cdn-cache-adapter";
201
201
  import { clearAppRequestStageContext as __clearRequestContext, setAppRequestStageNavigationContext as setNavigationContext } from ${JSON.stringify(appRequestStageContextPath)};
202
202
  import { matchRoutePattern as __matchRoutePattern } from ${JSON.stringify(routePatternPath)};
203
+ import __pagesClientAssets from "virtual:vinext-pages-client-assets";
203
204
  ${middlewarePath ? `import { applyAppMiddleware as __applyAppMiddleware } from ${JSON.stringify(appMiddlewarePath)};` : ""}
204
205
  ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(toSlash(instrumentationPath))};
205
206
  import { ensureInstrumentationRegistered as __ensureInstrumentationRegistered } from ${JSON.stringify(instrumentationRuntimePath)};
@@ -216,7 +217,6 @@ ${hasPagesDir ? `import { getDraftModeCookieHeader } from "next/headers";
216
217
  import * as __pagesRequestEntry from "virtual:vinext-pages-request-entry";
217
218
  import { renderPagesFallback as __renderPagesFallback } from ${JSON.stringify(appPagesBridgePath)};
218
219
  import { buildRequestHeadersFromMiddlewareResponse as __buildRequestHeadersFromMiddlewareResponse } from ${JSON.stringify(middlewareRequestHeadersPath)};
219
- import { decodePathParams as __decodePathParams } from ${JSON.stringify(normalizePathModulePath)};
220
220
  import { applyRouteHandlerMiddlewareContext as __applyRouteHandlerMiddlewareContext } from ${JSON.stringify(appRouteHandlerMiddlewareContextPath)};` : ""}
221
221
 
222
222
  ${hasPagesDir ? `export function __ensureHybridPagesApplication() {
@@ -238,6 +238,7 @@ export const __imageConfig = ${JSON.stringify({
238
238
  contentDispositionType: config?.imageConfig?.contentDispositionType,
239
239
  contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy
240
240
  })};
241
+ export const __clientBuildFiles = __pagesClientAssets.clientBuildFiles ?? [];
241
242
  const __routes = ${JSON.stringify(requestRoutes)};
242
243
  const __routeMatcher = __createAppRscRouteMatcher(__routes, ${JSON.stringify(buildAppDecodedPathnamePatterns(routes, config))});
243
244
  const __metadataRouteMatchers = ${JSON.stringify(metadataRouteMatchers)};
@@ -291,6 +292,7 @@ const __requestHandler = createAppRscRequestHandler({
291
292
  fallback: []
292
293
  })},
293
294
  draftModeSecret: __draftModeSecret,
295
+ devForwardedMiddlewareContextKey: ${JSON.stringify(config?.devForwardedMiddlewareContextKey ?? null)},
294
296
  dispatchMatchedPage() { throw new Error("App request stage attempted to render a page inline"); },
295
297
  dispatchMatchedRouteHandler() { throw new Error("App request stage attempted to render a route handler inline"); },
296
298
  ${instrumentationPath ? "ensureInstrumentation() { return __ensureInstrumentation(); }," : ""}
@@ -333,6 +335,7 @@ const __requestHandler = createAppRscRequestHandler({
333
335
  middlewareRequest,
334
336
  module: middlewareModule,
335
337
  request,
338
+ skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
336
339
  trailingSlash: __trailingSlash,
337
340
  validateExternalRewriteRequest,
338
341
  });
@@ -358,7 +361,6 @@ const __requestHandler = createAppRscRequestHandler({
358
361
  };
359
362
  },
360
363
  buildRequestHeaders: __buildRequestHeadersFromMiddlewareResponse,
361
- decodePathParams: __decodePathParams,
362
364
  applyRouteHandlerMiddlewareContext: __applyRouteHandlerMiddlewareContext,
363
365
  getDraftModeCookieHeader,
364
366
  }
@@ -366,6 +368,7 @@ const __requestHandler = createAppRscRequestHandler({
366
368
  },` : ""}
367
369
  rootParamNamesByPattern: {},
368
370
  setNavigationContext,
371
+ skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
369
372
  staticParamsMap: {},
370
373
  trailingSlash: __trailingSlash,
371
374
  validateDevRequestOrigin: __validateDevRequestOrigin,
@@ -520,14 +523,15 @@ import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters }
520
523
  import __pagesClientAssets from "virtual:vinext-pages-client-assets";
521
524
  ${actionOwners === void 0 ? `import __vinextActionOwners from ${JSON.stringify(ACTION_OWNER_MANIFEST_ID)};` : ""}
522
525
  import { setPagesClientAssets as __setPagesClientAssets } from "vinext/server/pages-client-assets";
523
- import { decodePathParams as __decodePathParams } from ${JSON.stringify(normalizePathModulePath)};
524
526
  import { buildRequestHeadersFromMiddlewareResponse as __buildRequestHeadersFromMiddlewareResponse } from ${JSON.stringify(middlewareRequestHeadersPath)};
525
527
  ${hasPagesDir ? `import {
526
528
  applyRouteHandlerMiddlewareContext as __applyRouteHandlerMiddlewareContext,
527
529
  } from ${JSON.stringify(appRouteHandlerResponsePath)};` : ""}
528
530
  const __loadAppRouteHandlerDispatch = () => import(${JSON.stringify(appRouteHandlerDispatchPath)});
529
531
  ${hasServerActions ? `const __loadAppServerActionExecution = () => import(${JSON.stringify(appServerActionExecutionPath)});
530
- const __loadAppActionForwarding = () => import(${JSON.stringify(appActionForwardingPath)});` : ""}
532
+ const __loadAppActionForwarding = () => import(${JSON.stringify(appActionForwardingPath)});
533
+ import { isolateServerReferenceLoads as __isolateServerReferenceLoads } from ${JSON.stringify(serverReferenceLoaderPath)};
534
+ __isolateServerReferenceLoads();` : ""}
531
535
  ${(metadataRoutes?.length ?? 0) > 0 ? `const __loadMetadataRouteResponse = () => import(${JSON.stringify(metadataRouteResponsePath)});` : ""}
532
536
  ${(metadataRoutes?.length ?? 0) > 0 ? `const __loadFileBasedMetadata = () => import(${JSON.stringify(fileBasedMetadataPath)});
533
537
  async function __applyFileBasedMetadata(...args) {
@@ -578,6 +582,8 @@ import {
578
582
  SIBLING_PAGE_INTERCEPT_SLOT_KEY as __SIBLING_PAGE_INTERCEPT_SLOT_KEY,
579
583
  } from ${JSON.stringify(appRscRouteMatchingPath)};
580
584
  import {
585
+ appIsrFallbackShellHtmlKey as __isrFallbackShellHtmlKey,
586
+ appIsrFallbackShellKey as __isrFallbackShellKey,
581
587
  appIsrHtmlKey as __isrHtmlKey,
582
588
  appIsrRscKey as __isrRscKey,
583
589
  appIsrRouteKey as __isrRouteKey,
@@ -949,6 +955,9 @@ export async function seedMemoryCacheFromPrerender(serverDir) {
949
955
  buildAppPageHtmlKey(pathname) {
950
956
  return __isrHtmlKey(pathname);
951
957
  },
958
+ buildAppPageFallbackShellKey(pathname, suffix) {
959
+ return __isrFallbackShellKey(pathname, suffix);
960
+ },
952
961
  buildAppPageRscKey(pathname) {
953
962
  return __isrRscKey(pathname);
954
963
  },
@@ -993,6 +1002,7 @@ ${rootParamNameEntries.join("\n")}
993
1002
  };
994
1003
 
995
1004
  __setPagesClientAssets(__pagesClientAssets);
1005
+ export const __clientBuildFiles = __pagesClientAssets.clientBuildFiles ?? [];
996
1006
  function __VINEXT_ACTION_OWNERS() { return ${actionOwners === void 0 ? "__vinextActionOwners" : safeJsonStringify(actionOwners)}; }
997
1007
  ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandler = createAppRscHandler({"}
998
1008
  assetPrefix: __assetPrefix,
@@ -1013,6 +1023,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1013
1023
  imageConfig: __runtimeImageConfig,
1014
1024
  isDev: process.env.NODE_ENV !== "production",
1015
1025
  draftModeSecret: __draftModeSecret,
1026
+ devForwardedMiddlewareContextKey: ${JSON.stringify(config?.devForwardedMiddlewareContextKey ?? null)},
1016
1027
  dispatchMatchedPage({
1017
1028
  bypassInterceptionContextCache,
1018
1029
  cachePathname,
@@ -1136,6 +1147,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1136
1147
  isRscRequest,
1137
1148
  isrDebug: __isrDebug,
1138
1149
  isrGet: __isrGet,
1150
+ isrFallbackShellHtmlKey: __isrFallbackShellHtmlKey,
1139
1151
  isrHtmlKey(pathname) {
1140
1152
  return __isrHtmlKey(pathname === cleanPathname ? cachePathname : pathname);
1141
1153
  },
@@ -1254,6 +1266,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1254
1266
  draftModeSecret: __draftModeSecret,
1255
1267
  i18n: __i18nConfig,
1256
1268
  trailingSlash: __trailingSlash,
1269
+ skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
1257
1270
  isrDebug: __isrDebug,
1258
1271
  isrGet: __isrGet,
1259
1272
  isrRouteKey(pathname) {
@@ -1617,6 +1630,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1617
1630
  middlewareRequest,
1618
1631
  module: middlewareModule,
1619
1632
  request,
1633
+ skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
1620
1634
  trailingSlash: __trailingSlash,
1621
1635
  validateExternalRewriteRequest,
1622
1636
  });
@@ -1655,7 +1669,6 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1655
1669
  };
1656
1670
  },
1657
1671
  buildRequestHeaders: __buildRequestHeadersFromMiddlewareResponse,
1658
- decodePathParams: __decodePathParams,
1659
1672
  applyRouteHandlerMiddlewareContext: __applyRouteHandlerMiddlewareContext,
1660
1673
  getDraftModeCookieHeader,
1661
1674
  }
@@ -1663,6 +1676,7 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1663
1676
  },` : ""}
1664
1677
  rootParamNamesByPattern: rootParamNamesMap,
1665
1678
  setNavigationContext,
1679
+ skipTrailingSlashRedirect: ${JSON.stringify(config?.skipTrailingSlashRedirect ?? false)},
1666
1680
  staticParamsMap: generateStaticParamsMap,
1667
1681
  trailingSlash: __trailingSlash,
1668
1682
  validateDevRequestOrigin: __validateDevRequestOrigin,