vinext 1.4.0 → 1.4.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 (156) hide show
  1. package/README.md +21 -21
  2. package/dist/build/action-owner-manifest.js +1 -0
  3. package/dist/build/prerender.js +3 -2
  4. package/dist/check.js +4 -7
  5. package/dist/client/dev-error-overlay-store.d.ts +1 -0
  6. package/dist/client/dev-error-overlay.d.ts +2 -0
  7. package/dist/client/dev-error-overlay.js +19 -3
  8. package/dist/config/config-matchers.js +4 -2
  9. package/dist/config/destination-params.d.ts +2 -1
  10. package/dist/config/destination-params.js +55 -2
  11. package/dist/config/next-config.d.ts +22 -1
  12. package/dist/config/next-config.js +49 -4
  13. package/dist/entries/app-rsc-entry.js +41 -19
  14. package/dist/entries/app-rsc-manifest.js +4 -0
  15. package/dist/entries/pages-server-entry.js +5 -1
  16. package/dist/index.js +44 -32
  17. package/dist/init-cloudflare.js +18 -2
  18. package/dist/plugins/css-target.d.ts +18 -0
  19. package/dist/plugins/css-target.js +93 -0
  20. package/dist/plugins/strip-server-exports.js +2 -1
  21. package/dist/routing/app-route-graph.d.ts +10 -0
  22. package/dist/routing/app-route-graph.js +15 -1
  23. package/dist/server/api-handler.d.ts +2 -0
  24. package/dist/server/api-handler.js +5 -6
  25. package/dist/server/app-action-forwarding.js +3 -1
  26. package/dist/server/app-browser-entry.js +28 -7
  27. package/dist/server/app-browser-rsc-redirect.js +3 -3
  28. package/dist/server/app-browser-server-action-client.js +2 -2
  29. package/dist/server/app-browser-visible-commit.js +2 -2
  30. package/dist/server/app-elements.d.ts +3 -0
  31. package/dist/server/app-elements.js +14 -1
  32. package/dist/server/app-fallback-renderer.js +2 -2
  33. package/dist/server/app-optimistic-routing.d.ts +12 -1
  34. package/dist/server/app-optimistic-routing.js +40 -19
  35. package/dist/server/app-page-boundary-render.js +7 -12
  36. package/dist/server/app-page-cache-render.js +1 -1
  37. package/dist/server/app-page-dispatch.d.ts +10 -2
  38. package/dist/server/app-page-dispatch.js +73 -31
  39. package/dist/server/app-page-element-builder.d.ts +9 -20
  40. package/dist/server/app-page-element-builder.js +40 -52
  41. package/dist/server/app-page-execution.js +9 -6
  42. package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
  43. package/dist/server/app-page-intercept-segment-config.js +90 -0
  44. package/dist/server/app-page-navigation-params.d.ts +23 -0
  45. package/dist/server/app-page-navigation-params.js +49 -0
  46. package/dist/server/app-page-render.d.ts +5 -3
  47. package/dist/server/app-page-render.js +31 -17
  48. package/dist/server/app-page-request.d.ts +24 -2
  49. package/dist/server/app-page-request.js +10 -10
  50. package/dist/server/app-page-response.js +1 -1
  51. package/dist/server/app-page-route-wiring.d.ts +10 -0
  52. package/dist/server/app-page-route-wiring.js +34 -13
  53. package/dist/server/app-page-segment-plan.js +9 -1
  54. package/dist/server/app-page-segment-state.d.ts +9 -0
  55. package/dist/server/app-page-segment-state.js +54 -1
  56. package/dist/server/app-page-stream.d.ts +10 -8
  57. package/dist/server/app-page-stream.js +2 -1
  58. package/dist/server/app-request-stage-independent-entry.js +1 -1
  59. package/dist/server/app-response-stage-entry.js +1 -0
  60. package/dist/server/app-route-handler-execution.js +3 -2
  61. package/dist/server/app-route-handler-runtime.d.ts +1 -1
  62. package/dist/server/app-route-handler-runtime.js +11 -7
  63. package/dist/server/app-route-module-loader.d.ts +2 -0
  64. package/dist/server/app-route-module-loader.js +1 -0
  65. package/dist/server/app-router-entry.js +1 -1
  66. package/dist/server/app-rsc-cache-busting.d.ts +10 -10
  67. package/dist/server/app-rsc-cache-busting.js +27 -68
  68. package/dist/server/app-rsc-error-handler.js +1 -1
  69. package/dist/server/app-rsc-errors.js +4 -1
  70. package/dist/server/app-rsc-handler.d.ts +10 -1
  71. package/dist/server/app-rsc-handler.js +126 -103
  72. package/dist/server/app-rsc-request-normalization.d.ts +10 -12
  73. package/dist/server/app-rsc-request-normalization.js +11 -14
  74. package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
  75. package/dist/server/app-rsc-response-finalizer.js +11 -1
  76. package/dist/server/app-rsc-response-stage.js +4 -12
  77. package/dist/server/app-rsc-route-matching.d.ts +14 -0
  78. package/dist/server/app-rsc-route-matching.js +42 -18
  79. package/dist/server/app-server-action-execution.js +24 -14
  80. package/dist/server/app-ssr-entry.d.ts +6 -0
  81. package/dist/server/app-ssr-entry.js +13 -8
  82. package/dist/server/app-worker-stages.d.ts +12 -3
  83. package/dist/server/app-worker-stages.js +37 -4
  84. package/dist/server/bfcache-identity.d.ts +7 -0
  85. package/dist/server/bfcache-identity.js +10 -1
  86. package/dist/server/cache-control.d.ts +2 -0
  87. package/dist/server/cache-control.js +3 -1
  88. package/dist/server/cacheability-manifest.js +1 -2
  89. package/dist/server/dev-origin-check.d.ts +2 -1
  90. package/dist/server/dev-origin-check.js +2 -1
  91. package/dist/server/dev-server.js +2 -1
  92. package/dist/server/image-local-patterns.d.ts +21 -0
  93. package/dist/server/image-local-patterns.js +59 -0
  94. package/dist/server/image-optimization.d.ts +28 -22
  95. package/dist/server/image-optimization.js +17 -2
  96. package/dist/server/isr-cache.js +4 -1
  97. package/dist/server/metadata-route-response.js +25 -7
  98. package/dist/server/middleware-matcher.js +19 -6
  99. package/dist/server/middleware-runtime.js +6 -2
  100. package/dist/server/multi-stage.d.ts +7 -3
  101. package/dist/server/nitro-public-files-plugin.js +20 -8
  102. package/dist/server/pages-data-route.d.ts +5 -1
  103. package/dist/server/pages-data-route.js +14 -6
  104. package/dist/server/pages-node-compat.d.ts +1 -1
  105. package/dist/server/pages-node-compat.js +2 -0
  106. package/dist/server/pages-page-data.js +2 -1
  107. package/dist/server/pages-page-handler.js +17 -6
  108. package/dist/server/pages-page-response.d.ts +9 -0
  109. package/dist/server/pages-page-response.js +18 -4
  110. package/dist/server/pages-request-pipeline.js +6 -5
  111. package/dist/server/pages-request-stage-entry.js +25 -4
  112. package/dist/server/pages-router-entry.js +3 -2
  113. package/dist/server/prod-server.d.ts +2 -2
  114. package/dist/server/prod-server.js +59 -17
  115. package/dist/server/request-error-log.d.ts +9 -0
  116. package/dist/server/request-error-log.js +13 -0
  117. package/dist/server/request-pipeline.d.ts +14 -4
  118. package/dist/server/request-pipeline.js +33 -15
  119. package/dist/server/response-stage-cacheability.d.ts +7 -0
  120. package/dist/server/response-stage-cacheability.js +6 -5
  121. package/dist/server/rsc-completion-metadata.js +3 -0
  122. package/dist/server/static-file-cache.d.ts +9 -0
  123. package/dist/server/static-file-cache.js +13 -2
  124. package/dist/server/worker-image-optimization.d.ts +2 -2
  125. package/dist/server/worker-image-optimization.js +18 -3
  126. package/dist/server/worker-utils.d.ts +8 -0
  127. package/dist/server/worker-utils.js +19 -2
  128. package/dist/shims/cache-request-state.d.ts +6 -6
  129. package/dist/shims/cache-request-state.js +6 -36
  130. package/dist/shims/cache-runtime.d.ts +3 -1
  131. package/dist/shims/cache-runtime.js +77 -47
  132. package/dist/shims/cache.d.ts +10 -5
  133. package/dist/shims/cache.js +35 -22
  134. package/dist/shims/client-hook-error.d.ts +2 -0
  135. package/dist/shims/client-hook-error.js +16 -1
  136. package/dist/shims/fetch-cache.js +6 -2
  137. package/dist/shims/headers.d.ts +2 -1
  138. package/dist/shims/headers.js +5 -3
  139. package/dist/shims/image-props.d.ts +6 -0
  140. package/dist/shims/image-props.js +39 -3
  141. package/dist/shims/image.js +3 -3
  142. package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
  143. package/dist/shims/link.js +5 -10
  144. package/dist/shims/navigation.js +2 -3
  145. package/dist/shims/request-state-types.d.ts +2 -1
  146. package/dist/shims/slot.d.ts +9 -2
  147. package/dist/shims/slot.js +76 -11
  148. package/dist/shims/unified-request-context.d.ts +6 -0
  149. package/dist/shims/unified-request-context.js +1 -0
  150. package/dist/utils/base-path.d.ts +7 -0
  151. package/dist/utils/base-path.js +11 -1
  152. package/dist/utils/cache-life-profiles.d.ts +33 -0
  153. package/dist/utils/cache-life-profiles.js +111 -0
  154. package/dist/utils/middleware-request-headers.d.ts +14 -3
  155. package/dist/utils/middleware-request-headers.js +54 -7
  156. package/package.json +1 -1
package/README.md CHANGED
@@ -659,26 +659,26 @@ Every `next/*` import is shimmed to a Vite-compatible implementation.
659
659
 
660
660
  ### Server features
661
661
 
662
- | Feature | | Notes |
663
- | ------------------------------------------ | --- | ------------------------------------------------------------------------------------------- |
664
- | SSR (Pages Router) | ✅ | Streaming, `_app`/`_document`, `__NEXT_DATA__`, hydration |
665
- | SSR (App Router) | ✅ | RSC pipeline, nested layouts, streaming, nav context for client components |
666
- | `getStaticProps` | ✅ | Props, redirect, notFound, revalidate |
667
- | `getStaticPaths` | ✅ | `fallback: false`, `true`, `"blocking"` |
668
- | `getServerSideProps` | ✅ | Full context including locale |
669
- | ISR | ✅ | Stale-while-revalidate, pluggable `CacheHandler`, background regeneration |
670
- | Server Actions (`"use server"`) | ✅ | Action execution, FormData, re-render after mutation, `redirect()` in actions |
671
- | React Server Components | ✅ | Via `@vitejs/plugin-rsc`. `"use client"` boundaries work correctly |
672
- | Streaming SSR | ✅ | Both routers |
673
- | Metadata API | ✅ | `metadata`, `generateMetadata`, `viewport`, `generateViewport`, title templates |
674
- | `generateStaticParams` | ✅ | With `dynamicParams` enforcement |
675
- | Metadata file routes | ✅ | sitemap.xml, robots.txt, manifest, favicon, OG images (static + dynamic) |
676
- | Static export (`output: 'export'`) | ✅ | Generates static HTML/JSON for all routes |
677
- | Standalone output (`output: 'standalone'`) | ✅ | Generates `dist/standalone` with `server.js`, build artifacts, and runtime deps |
678
- | `connection()` | ✅ | Forces dynamic rendering |
679
- | `"use cache"` directive | ✅ | File-level and function-level. `cacheLife()` profiles, `cacheTag()`, stale-while-revalidate |
680
- | `instrumentation.ts` | ✅ | `register()`, `onRequestError()`, and [framework tracing](docs/tracing.mdx) |
681
- | Route segment config | 🟡 | `revalidate`, `dynamic`, `dynamicParams`, `runtime` (not placement). No `preferredRegion` |
662
+ | Feature | | Notes |
663
+ | ------------------------------------------ | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
664
+ | SSR (Pages Router) | ✅ | Streaming, `_app`/`_document`, `__NEXT_DATA__`, hydration |
665
+ | SSR (App Router) | ✅ | RSC pipeline, nested layouts, streaming, nav context for client components |
666
+ | `getStaticProps` | ✅ | Props, redirect, notFound, revalidate |
667
+ | `getStaticPaths` | ✅ | `fallback: false`, `true`, `"blocking"` |
668
+ | `getServerSideProps` | ✅ | Full context including locale |
669
+ | ISR | ✅ | Stale-while-revalidate, pluggable `CacheHandler`, background regeneration |
670
+ | Server Actions (`"use server"`) | ✅ | Action execution, FormData, re-render after mutation, `redirect()` in actions |
671
+ | React Server Components | ✅ | Via `@vitejs/plugin-rsc`. `"use client"` boundaries work correctly |
672
+ | Streaming SSR | ✅ | Both routers |
673
+ | Metadata API | ✅ | `metadata`, `generateMetadata`, `viewport`, `generateViewport`, title templates |
674
+ | `generateStaticParams` | ✅ | With `dynamicParams` enforcement |
675
+ | Metadata file routes | ✅ | sitemap.xml, robots.txt, manifest, favicon, OG images (static + dynamic) |
676
+ | Static export (`output: 'export'`) | ✅ | Generates static HTML/JSON for all routes |
677
+ | Standalone output (`output: 'standalone'`) | ✅ | Generates `dist/standalone` with `server.js`, build artifacts, and runtime deps |
678
+ | `connection()` | ✅ | Forces dynamic rendering |
679
+ | `"use cache"` directive | ✅ | File-level and function-level. `cacheLife()` with built-in and next.config `cacheLife` (or legacy `experimental.cacheLife`) profiles, `cacheTag()`, stale-while-revalidate |
680
+ | `instrumentation.ts` | ✅ | `register()`, `onRequestError()`, and [framework tracing](docs/tracing.mdx) |
681
+ | Route segment config | 🟡 | `revalidate`, `dynamic`, `dynamicParams`, `runtime` (not placement). No `preferredRegion` |
682
682
 
683
683
  ### Configuration
684
684
 
@@ -687,7 +687,7 @@ Every `next/*` import is shimmed to a Vite-compatible implementation.
687
687
  | `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
688
688
  | `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation. A source Next.js rejects fails config loading, as it fails the Next.js build: missing, not starting with `/`, over the 4,096-character built-regex limit, or rejected by path-to-regexp, such as a header glob `/api/*` |
689
689
  | Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
690
- | `images` config | 🟡 | Parsed but not used for optimization |
690
+ | `images` config | 🟡 | Parsed but not used for optimization; the production image endpoint enforces `localPatterns` (dev serves any local source) |
691
691
  | `experimental.optimizePackageImports` | ✅ | Rewrites barrel imports to direct sub-module imports in RSC/SSR environments. A default set (lucide-react, date-fns, radix-ui, antd, MUI, and others) are always optimized. Add package names here to extend the list. |
692
692
  | `vinext({ nextConfig })` | ✅ | Inline Next-style config from `vite.config.*`. Supports object-form and function-form config. When provided, this overrides root `next.config.*`. |
693
693
  | `vinext({ react: { compiler: true } })` | ✅ | React Compiler auto memoization. Needs `@vitejs/plugin-react` 6.1+ and the optional `oxc-transform-react` package. |
@@ -26,6 +26,7 @@ function actionOwnerRouteEntryIds(route) {
26
26
  slot.loadingPath,
27
27
  ...slot.loadingPaths ?? [],
28
28
  slot.errorPath,
29
+ ...slot.errorPaths ?? [],
29
30
  slot.notFoundPath,
30
31
  ...slot.notFoundPaths ?? [],
31
32
  ...slot.interceptingRoutes.flatMap((intercept) => [
@@ -608,12 +608,13 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
608
608
  fs.writeFileSync(htmlFullPath, html, "utf-8");
609
609
  outputFiles.push(htmlOutputPath);
610
610
  }
611
+ const renderedRevalidate = isStaticPropsResponse ? readPrerenderCacheLifeHeader(response.headers)?.revalidate ?? false : revalidate;
611
612
  result = {
612
613
  route: route.pattern,
613
614
  status: "rendered",
614
615
  outputFiles,
615
- revalidate,
616
- ...typeof revalidate === "number" ? { expire: config.expireTime } : {},
616
+ revalidate: renderedRevalidate,
617
+ ...typeof renderedRevalidate === "number" ? { expire: config.expireTime } : {},
617
618
  router: "pages",
618
619
  ...urlPath !== route.pattern ? { path: urlPath } : {},
619
620
  ...locale ? { locale } : {},
package/dist/check.js CHANGED
@@ -197,7 +197,7 @@ const CONFIG_SUPPORT = {
197
197
  env: { status: "supported" },
198
198
  images: {
199
199
  status: "partial",
200
- detail: "remotePatterns, deviceSizes/imageSizes, qualities and SVG/CSP options honoured; resizing needs an optimizer via vinext({ images: { optimizer } }), images are served as-is otherwise; loader/loaderFile are ignored"
200
+ detail: "remotePatterns, deviceSizes/imageSizes, qualities, localPatterns (production only) and SVG/CSP options honoured; resizing needs an optimizer via vinext({ images: { optimizer } }), images are served as-is otherwise; loader/loaderFile are ignored"
201
201
  },
202
202
  allowedDevOrigins: {
203
203
  status: "supported",
@@ -243,13 +243,10 @@ const CONFIG_SUPPORT = {
243
243
  status: "unsupported",
244
244
  detail: "ignored; configure cache adapters with vinext({ cache }) in vite.config"
245
245
  },
246
- cacheLife: {
247
- status: "unsupported",
248
- detail: "custom cacheLife profiles are ignored; only the built-in profiles are available"
249
- },
246
+ cacheLife: { status: "supported" },
250
247
  "experimental.cacheLife": {
251
- status: "unsupported",
252
- detail: "custom cacheLife profiles are ignored; only the built-in profiles are available"
248
+ status: "supported",
249
+ detail: "legacy alias of cacheLife"
253
250
  },
254
251
  skipTrailingSlashRedirect: { status: "supported" },
255
252
  "experimental.skipTrailingSlashRedirect": {
@@ -3,6 +3,7 @@ export type Source = "server" | "vite" | "uncaught" | "caught" | "window-error"
3
3
  export type ReportedError = {
4
4
  id: number;
5
5
  source: Source;
6
+ name: string | undefined;
6
7
  message: string;
7
8
  stack: string | undefined;
8
9
  ignoredStackFrames: boolean[] | undefined;
@@ -1,9 +1,11 @@
1
1
  import { ReportedError, dismissOverlay } from "./dev-error-overlay-store.js";
2
+ import { InitialDevServerErrorPayload } from "../server/dev-initial-server-error.js";
2
3
  //#region src/client/dev-error-overlay.d.ts
3
4
  export declare const DEV_ERROR_OVERLAY_HOST_ID = "__vinext_dev_error_overlay_root";
4
5
  export declare const DEV_ERROR_OVERLAY_MOUNT_ID = "__vinext_dev_error_overlay_mount";
5
6
  export declare function installDevErrorOverlay(): void;
6
7
  export declare function installReactRefreshErrorRecovery(): void;
8
+ export declare function selectUnreportedInitialDevServerErrors(payloads: readonly InitialDevServerErrorPayload[], reported: readonly ReportedError[]): InitialDevServerErrorPayload[];
7
9
  export declare function reportInitialDevServerErrors(): void;
8
10
  type ViteHmrErrorPayload = {
9
11
  err?: ViteHmrError;
@@ -11,6 +11,7 @@ const DEV_ERROR_OVERLAY_MOUNT_ID = "__vinext_dev_error_overlay_mount";
11
11
  const VITE_ERROR_HANDLER_DATA_KEY = "__vinext_vite_error_handler__";
12
12
  const REACT_REFRESH_RECOVERY_RETRY_DELAY_MS = 16;
13
13
  let reactRoot = null;
14
+ let overlayHost = null;
14
15
  let installed = false;
15
16
  const reportedErrors = /* @__PURE__ */ new WeakSet();
16
17
  function rememberReported(error) {
@@ -81,12 +82,21 @@ function tryInstallReactRefreshErrorRecovery() {
81
82
  });
82
83
  return true;
83
84
  }
85
+ function selectUnreportedInitialDevServerErrors(payloads, reported) {
86
+ const rethrownErrors = reported.filter((error) => error.source === "caught" || error.source === "uncaught" || error.source === "window-error");
87
+ return payloads.filter((payload) => {
88
+ const rethrownIndex = rethrownErrors.findIndex((error) => error.message === payload.message && (error.name || "Error") === (payload.name || "Error"));
89
+ if (rethrownIndex === -1) return true;
90
+ rethrownErrors.splice(rethrownIndex, 1);
91
+ return false;
92
+ });
93
+ }
84
94
  function reportInitialDevServerErrors() {
85
95
  if (typeof window === "undefined") return;
86
96
  const errors = window.__VINEXT_INITIAL_DEV_ERRORS__;
87
97
  if (!errors || errors.length === 0) return;
88
98
  window.__VINEXT_INITIAL_DEV_ERRORS__ = [];
89
- for (const payload of errors) {
99
+ for (const payload of selectUnreportedInitialDevServerErrors(errors, getOverlaySnapshot().errors)) {
90
100
  const error = new Error(payload.message);
91
101
  if (payload.name) error.name = payload.name;
92
102
  if (payload.stack) error.stack = payload.stack;
@@ -130,6 +140,7 @@ function reportDevError(error, options) {
130
140
  ensureMounted();
131
141
  const id = reportToOverlay({
132
142
  source: options.source,
143
+ name: error instanceof Error ? error.name : void 0,
133
144
  message,
134
145
  stack,
135
146
  ignoredStackFrames: void 0,
@@ -176,8 +187,13 @@ function stringValue(value) {
176
187
  return typeof value === "string" && value.length > 0 ? value : void 0;
177
188
  }
178
189
  function ensureMounted() {
179
- if (reactRoot) return;
190
+ if (reactRoot) {
191
+ const host = overlayHost;
192
+ if (host && !host.isConnected) (document.body ?? document.documentElement).appendChild(host);
193
+ return;
194
+ }
180
195
  const node = createDevErrorOverlayMountNode(document);
196
+ overlayHost = document.getElementById(DEV_ERROR_OVERLAY_HOST_ID);
181
197
  reactRoot = createRoot(node);
182
198
  reactRoot.render(/* @__PURE__ */ jsx(DevErrorOverlayApp, {}));
183
199
  }
@@ -1342,4 +1358,4 @@ const componentStackStyle = {
1342
1358
  color: "var(--vinext-overlay-muted)"
1343
1359
  };
1344
1360
  //#endregion
1345
- export { DEV_ERROR_OVERLAY_HOST_ID, DEV_ERROR_OVERLAY_MOUNT_ID, createDevErrorOverlayMountNode, createViteOpenInEditorUrl, devOnCaughtError, devOnUncaughtError, dismissOverlay, formatErrorInfoForClipboard, formatOverlayDisplayFile, formatViteOpenInEditorFile, installDevErrorOverlay, installReactRefreshErrorRecovery, installViteHmrErrorHandler, normalizeViteHmrError, reportInitialDevServerErrors };
1361
+ export { DEV_ERROR_OVERLAY_HOST_ID, DEV_ERROR_OVERLAY_MOUNT_ID, createDevErrorOverlayMountNode, createViteOpenInEditorUrl, devOnCaughtError, devOnUncaughtError, dismissOverlay, formatErrorInfoForClipboard, formatOverlayDisplayFile, formatViteOpenInEditorFile, installDevErrorOverlay, installReactRefreshErrorRecovery, installViteHmrErrorHandler, normalizeViteHmrError, reportInitialDevServerErrors, selectUnreportedInitialDevServerErrors };
@@ -719,7 +719,7 @@ function preserveRedirectDestinationQuery(destination, requestSearch, destinatio
719
719
  }
720
720
  const LOCATION_STRIPPED_RE = /^[\u0000- ]+|[\u0000- ]+$|[\t\n\r]/g;
721
721
  const LOCATION_UNSAFE_RE = /[\u0000-\u0008\u000A-\u001F\u007F]|[^\u0000-\u007F]/gu;
722
- const LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
722
+ const SURROGATE_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDFFF]/g;
723
723
  /**
724
724
  * Percent-encode what a config-redirect `Location` header cannot carry.
725
725
  *
@@ -731,7 +731,7 @@ const LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF
731
731
  * constructor throws the same way); vinext percent-encodes them instead.
732
732
  */
733
733
  function encodeRedirectLocation(location) {
734
- return location.replace(LONE_SURROGATE_RE, "�").replace(LOCATION_UNSAFE_RE, encodeURIComponent);
734
+ return location.replace(SURROGATE_RE, (surrogate) => surrogate.length === 2 ? surrogate : "�").replace(LOCATION_UNSAFE_RE, encodeURIComponent);
735
735
  }
736
736
  function parseExternalRewriteUrl(externalUrl) {
737
737
  try {
@@ -759,8 +759,10 @@ async function proxyExternalRequest(request, externalUrl) {
759
759
  const destinationKeys = new Set(targetUrl.searchParams.keys());
760
760
  for (const [key, value] of originalUrl.searchParams) if (!destinationKeys.has(key)) targetUrl.searchParams.append(key, value);
761
761
  const headers = new Headers(request.headers);
762
+ const requestHost = headers.get("host") ?? "";
762
763
  headers.set("host", targetUrl.host);
763
764
  stripHopByHopRequestHeaders(headers);
765
+ headers.set("x-forwarded-host", requestHost);
764
766
  const keysToDelete = [];
765
767
  for (const key of headers.keys()) if (key.startsWith("x-middleware-") && !key.startsWith("x-middleware-request-")) keysToDelete.push(key);
766
768
  for (const key of keysToDelete) headers.delete(key);
@@ -25,7 +25,8 @@
25
25
  * `%XX` escapes a raw path capture already carries. A decoded `has` capture
26
26
  * carrying `#`, `/`, `?`, `@` or `:` then makes the host invalid instead of
27
27
  * moving the proxy to another host. Next.js substitutes the hostname verbatim
28
- * and can be retargeted this way; vinext is stricter.
28
+ * and can be retargeted this way; vinext is stricter. Params in a rewrite's
29
+ * path follow substituteRewritePath.
29
30
  *
30
31
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
31
32
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
@@ -33,7 +33,8 @@ const _compiledDestinationParamCache = /* @__PURE__ */ new Map();
33
33
  * `%XX` escapes a raw path capture already carries. A decoded `has` capture
34
34
  * carrying `#`, `/`, `?`, `@` or `:` then makes the host invalid instead of
35
35
  * moving the proxy to another host. Next.js substitutes the hostname verbatim
36
- * and can be retargeted this way; vinext is stricter.
36
+ * and can be retargeted this way; vinext is stricter. Params in a rewrite's
37
+ * path follow substituteRewritePath.
37
38
  *
38
39
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
39
40
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/server-route-utils.ts
@@ -49,7 +50,59 @@ function substituteDestinationParams(destination, params, kind) {
49
50
  const queryIndex = beforeHash.indexOf("?");
50
51
  const beforeQuery = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);
51
52
  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
+ const [path, pathHash] = substituteRewritePath(beforeQuery.slice(authorityEnd), paramRe, params, authorityEnd > 0);
54
+ const query = queryIndex === -1 ? "" : `?${replaceParams(beforeHash.slice(queryIndex + 1), encodeRewriteQueryParamValue)}`;
55
+ return `${replaceParams(beforeQuery.slice(0, authorityEnd), encodeAuthorityParam)}${path}${query}${pathHash ?? replaceParams(hash, (value) => value)}`;
56
+ }
57
+ /**
58
+ * Substitute params into a rewrite destination's path, returning the path and,
59
+ * when a param carried a `#`, the hash it starts.
60
+ *
61
+ * Next.js inserts path params verbatim, splits the result at the first `#`
62
+ * and escapes a `?` when it formats the URL. A decoded `has` capture can end
63
+ * the path with `#`, but neither `?` nor `#` can displace the destination's
64
+ * own query.
65
+ *
66
+ * An absolute destination is proxied with the URL parser, which removes tab
67
+ * and newlines, trims trailing control characters and spaces, and resolves
68
+ * `.`/`..` segments against the destination's literal path. Next.js sends a
69
+ * param's control characters and spaces percent-encoded, as vinext does, and
70
+ * its dot segments as written. A parsed URL cannot carry a `..` segment, so a
71
+ * dot segment that a param is in or next to is escaped once more (`.` as
72
+ * `%252E`, `%2e` as `%252e`) and stays inside the destination's path. The
73
+ * destination's own dot segments still resolve.
74
+ *
75
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/prepare-destination.ts
76
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/format-url.ts
77
+ */
78
+ function substituteRewritePath(template, paramRe, params, absolute) {
79
+ const encodeParam = absolute ? encodeAbsoluteUrlPathParam : encodePathQueryDelimiter;
80
+ const paramRanges = [];
81
+ let substituted = "";
82
+ let templateIndex = 0;
83
+ for (const match of template.matchAll(paramRe)) {
84
+ substituted += template.slice(templateIndex, match.index);
85
+ const value = encodeParam(params[match[1]]);
86
+ paramRanges.push([substituted.length, substituted.length + value.length]);
87
+ substituted += value;
88
+ templateIndex = match.index + match[0].length;
89
+ }
90
+ substituted += template.slice(templateIndex);
91
+ const [path, hash] = substituted.split("#", 2);
92
+ const pathHash = hash === void 0 ? void 0 : hash ? `#${hash}` : "";
93
+ if (!absolute) return [path, pathHash];
94
+ return [path.replace(DOT_SEGMENT_RE, (_match, separator, segment, offset) => {
95
+ const start = offset + separator.length;
96
+ return paramRanges.some(([paramStart, end]) => paramStart <= start + segment.length && end >= start) ? separator + segment.replace(/\.|%(?=2e)/gi, (char) => char === "." ? "%252E" : "%25") : separator + segment;
97
+ }), pathHash];
98
+ }
99
+ const DOT_SEGMENT_RE = /(^|[/\\])((?:\.|%2e){1,2})(?=[/\\]|$)/gi;
100
+ function encodePathQueryDelimiter(value) {
101
+ return value.replaceAll("?", "%3F");
102
+ }
103
+ const ABSOLUTE_URL_PATH_PARAM_UNSAFE_RE = /[?\u0000- ]/g;
104
+ function encodeAbsoluteUrlPathParam(value) {
105
+ return value.replace(ABSOLUTE_URL_PATH_PARAM_UNSAFE_RE, encodeURIComponent);
53
106
  }
54
107
  function getAbsoluteUrlAuthorityEnd(value) {
55
108
  const scheme = /^[a-z][a-z0-9+.-]*:[/\\\t\n\r]*/i.exec(value);
@@ -1,3 +1,4 @@
1
+ import { CacheLifeConfig } from "../utils/cache-life-profiles.js";
1
2
  import { PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
2
3
  import { PluginOption } from "vite";
3
4
  //#region src/config/next-config.d.ts
@@ -182,12 +183,27 @@ export type NextConfig = {
182
183
  search?: string;
183
184
  }>;
184
185
  domains?: string[];
186
+ /**
187
+ * Local sources the image optimization endpoint may serve. Statically
188
+ * imported images are allowed too, except under a basePath (the added
189
+ * pattern is unprefixed, as in Next.js). When unset, any local path
190
+ * without a query string is allowed (matches Next.js).
191
+ */
192
+ localPatterns?: Array<{
193
+ pathname?: string;
194
+ search?: string;
195
+ }>;
185
196
  unoptimized?: boolean;
186
197
  /** Allowed device widths for image optimization. Defaults to Next.js defaults: [640, 750, 828, 1080, 1200, 1920, 2048, 3840] */
187
198
  deviceSizes?: number[];
188
199
  /** Allowed image sizes for fixed-width images. Defaults to Next.js defaults: [32, 48, 64, 96, 128, 256, 384] */
189
200
  imageSizes?: number[];
190
- /** Allowed image qualities. When unset, any quality from 1-100 is permitted (matches Next.js). */
201
+ /**
202
+ * Allowed image qualities. When set, the endpoint accepts only these and the
203
+ * default loader rounds `quality` to the closest entry, as in Next.js. When
204
+ * unset, any quality from 1-100 is permitted: a deliberate divergence from
205
+ * Next.js 16's `[75]` default that keeps Next.js 14/15 apps working.
206
+ */
191
207
  qualities?: number[];
192
208
  /** Allow SVG images through the image optimization endpoint. SVG can contain scripts, so only enable if you trust all image sources. */
193
209
  dangerouslyAllowSVG?: boolean;
@@ -551,6 +567,11 @@ export type ResolvedNextConfig = {
551
567
  dynamic: number;
552
568
  static: number;
553
569
  };
570
+ /**
571
+ * `cacheLife` profiles (or legacy `experimental.cacheLife`) merged over the
572
+ * built-ins with Next.js's rules; read by the `cacheLife()` shim.
573
+ */
574
+ cacheLife: Record<string, CacheLifeConfig>;
554
575
  /**
555
576
  * Mirrors Next.js `experimental.useLightningcss`. When `true`, switch
556
577
  * Vite's CSS pipeline from PostCSS to lightningcss for both transforms
@@ -6,6 +6,7 @@ import { isUnknownRecord } from "../utils/record.js";
6
6
  import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
7
7
  import { getHtmlLimitedBotRegex } from "../utils/html-limited-bots.js";
8
8
  import { flattenPluginOptions } from "../utils/plugin-options.js";
9
+ import { resolveCacheLifeProfiles } from "../utils/cache-life-profiles.js";
9
10
  import { configSourceError } from "./config-source.js";
10
11
  import { isExternalUrl } from "../utils/external-url.js";
11
12
  import { applyLocaleToRoutes } from "./config-matchers.js";
@@ -376,7 +377,11 @@ function warnDeprecatedConfigOptions(config, root) {
376
377
  ];
377
378
  for (const [propertyPath, warning] of warnings) if (hasConfigProperty(config, propertyPath)) warnConfigOnce(warning);
378
379
  const experimental = readOptionalRecord(config.experimental);
379
- for (const key of ["skipTrailingSlashRedirect", "cacheComponents"]) if (experimental?.[key] != null) warnConfigOnce(`\`experimental.${key}\` has been moved to \`${key}\`. Please update your ${configFileName} file accordingly.`);
380
+ for (const key of [
381
+ "skipTrailingSlashRedirect",
382
+ "cacheComponents",
383
+ "cacheLife"
384
+ ]) if (experimental?.[key] != null) warnConfigOnce(`\`experimental.${key}\` has been moved to \`${key}\`. Please update your ${configFileName} file accordingly.`);
380
385
  }
381
386
  async function resolveNextConfigInput(config, phase = PHASE_DEVELOPMENT_SERVER) {
382
387
  return await resolveConfigValue(config, phase);
@@ -502,6 +507,35 @@ async function resolveBuildId(generate) {
502
507
  return trimmed;
503
508
  }
504
509
  /**
510
+ * Mirror Next.js's config resolution of `images.localPatterns`: statically
511
+ * imported images (`/_next/static/media/**`) stay allowed whatever the app
512
+ * lists, though like Next.js the pattern is unprefixed, so it never matches
513
+ * under a basePath. An unset list stays unset; the image endpoint then applies the
514
+ * Next.js default.
515
+ */
516
+ function resolveImageLocalPatterns(localPatterns) {
517
+ if (localPatterns === void 0) return void 0;
518
+ if (!Array.isArray(localPatterns)) throw new Error(`Specified images.localPatterns should be an Array received ${localPatterns === null ? "null" : typeof localPatterns}.\nSee more info here: https://nextjs.org/docs/messages/invalid-images-config`);
519
+ if (localPatterns.length > 25) throw new Error("Specified images.localPatterns can have at most 25 entries.");
520
+ const patterns = Array.from(localPatterns, (pattern, index) => {
521
+ const entry = pattern;
522
+ let valid = typeof pattern === "object" && pattern !== null && !Array.isArray(pattern) && !(pattern instanceof Date) && !(pattern instanceof Map) && !(pattern instanceof Set) && !(typeof entry.then === "function" && typeof pattern.catch === "function") && (entry.pathname === void 0 || typeof entry.pathname === "string") && (entry.search === void 0 || typeof entry.search === "string");
523
+ if (valid) {
524
+ for (const key in pattern) if (key !== "pathname" && key !== "search") valid = false;
525
+ }
526
+ if (!valid) throw new Error(`Specified images.localPatterns[${index}] should be an object with optional string \`pathname\` and \`search\` fields.`);
527
+ const resolved = {};
528
+ if (entry.pathname !== void 0) resolved.pathname = entry.pathname;
529
+ if (entry.search !== void 0) resolved.search = entry.search;
530
+ return resolved;
531
+ });
532
+ if (!patterns.some((pattern) => pattern.pathname === "/_next/static/media/**" && pattern.search === "")) patterns.push({
533
+ pathname: "/_next/static/media/**",
534
+ search: ""
535
+ });
536
+ return patterns;
537
+ }
538
+ /**
505
539
  * Normalize the `assetPrefix` option from next.config.
506
540
  *
507
541
  * Accepts both absolute URLs (`https://cdn.example.com[/subpath]`) and
@@ -935,6 +969,10 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
935
969
  instrumentationServerValueInjections: {},
936
970
  clientTraceMetadata: void 0,
937
971
  staleTimes: { ...DEFAULT_STALE_TIMES },
972
+ cacheLife: resolveCacheLifeProfiles(void 0, {
973
+ expireTime: DEFAULT_EXPIRE_TIME,
974
+ staticStaleTime: DEFAULT_STALE_TIMES.static
975
+ }, warnConfigOnce),
938
976
  useLightningcss: false,
939
977
  lightningCssFeatures: {
940
978
  include: 0,
@@ -1014,6 +1052,8 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
1014
1052
  const allowedDevOrigins = Array.isArray(config.allowedDevOrigins) ? config.allowedDevOrigins : [];
1015
1053
  const experimental = readOptionalRecord(config.experimental);
1016
1054
  const cacheComponents = (experimental?.cacheComponents ?? config.cacheComponents) === true;
1055
+ const expireTime = typeof config.expireTime === "number" ? config.expireTime : DEFAULT_EXPIRE_TIME;
1056
+ const staleTimes = resolveStaleTimes(experimental);
1017
1057
  const serverActionsConfig = readOptionalRecord(experimental?.serverActions);
1018
1058
  const serverActionsAllowedOrigins = readStringArray(serverActionsConfig?.allowedOrigins);
1019
1059
  const serverActionsBodySizeLimitConfig = readOptionalBodySizeLimit(serverActionsConfig?.bodySizeLimit);
@@ -1083,7 +1123,8 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
1083
1123
  port: pattern.port,
1084
1124
  pathname: pattern.pathname,
1085
1125
  search: pattern.search
1086
- } : { ...pattern })
1126
+ } : { ...pattern }),
1127
+ localPatterns: resolveImageLocalPatterns(config.images.localPatterns)
1087
1128
  } : void 0;
1088
1129
  const resolved = {
1089
1130
  env: config.env ?? {},
@@ -1124,7 +1165,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
1124
1165
  globalNotFound,
1125
1166
  serverActionsBodySizeLimit,
1126
1167
  serverActionsBodySizeLimitLabel,
1127
- expireTime: typeof config.expireTime === "number" ? config.expireTime : DEFAULT_EXPIRE_TIME,
1168
+ expireTime,
1128
1169
  reactMaxHeadersLength: typeof config.reactMaxHeadersLength === "number" ? config.reactMaxHeadersLength : DEFAULT_REACT_MAX_HEADERS_LENGTH,
1129
1170
  htmlLimitedBots,
1130
1171
  serverExternalPackages,
@@ -1144,7 +1185,11 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
1144
1185
  compilerDefine: serializeCompilerDefine(config.compiler?.define),
1145
1186
  compilerDefineServer: serializeCompilerDefine(config.compiler?.defineServer),
1146
1187
  clientTraceMetadata: Array.isArray(experimental?.clientTraceMetadata) ? experimental.clientTraceMetadata.filter((value) => typeof value === "string") : void 0,
1147
- staleTimes: resolveStaleTimes(experimental),
1188
+ staleTimes,
1189
+ cacheLife: resolveCacheLifeProfiles(experimental?.cacheLife ?? config.cacheLife, {
1190
+ expireTime,
1191
+ staticStaleTime: staleTimes.static
1192
+ }, warnConfigOnce),
1148
1193
  useLightningcss,
1149
1194
  lightningCssFeatures
1150
1195
  };
@@ -94,9 +94,10 @@ function appPageSegmentConfigPaths(route) {
94
94
  ];
95
95
  }
96
96
  /**
97
- * Patterns of the static App pages that answer a request whose raw pathname
98
- * reaches a dynamic sibling but whose segment-decoded pathname names them, so
99
- * `/%61` and `/caf%C3%A9` render `/a` and `/café` rather than `/[slug]`.
97
+ * Patterns of the static App pages that may answer a request whose raw
98
+ * pathname reaches a dynamic sibling but whose segment-decoded pathname names
99
+ * them, so `/%61` and `/caf%C3%A9` can render `/a` and `/café` rather than
100
+ * `/[slug]`.
100
101
  *
101
102
  * Next.js serves those requests from the response cached under the decoded
102
103
  * pathname, which exists only for a page it prerendered. The prerender listing
@@ -105,7 +106,10 @@ function appPageSegmentConfigPaths(route) {
105
106
  * runtime on any segment) and a Route Handler have no such entry, so the
106
107
  * dynamic sibling renders. So does a page whose sources can't be read here;
107
108
  * its sibling's render stays out of the shared caches. A cacheComponents
108
- * build lists every page route, as the prerender listing does.
109
+ * build lists every page route, as the prerender listing does. Segment config
110
+ * can't tell a page that reads request data, so the matcher renders the page
111
+ * for another spelling (`/%61dmin`) only once the build recorded the decoded
112
+ * pathname's prerender; the browser's own spelling needs none.
109
113
  */
110
114
  function buildAppDecodedPathnamePatterns(routes, config) {
111
115
  const isPrerenderedPage = (route) => {
@@ -148,6 +152,10 @@ function buildAppRequestRouteMetadata(routes) {
148
152
  slots: Object.fromEntries(route.parallelSlots.map((slot) => [slot.key, {
149
153
  id: slot.id ?? null,
150
154
  name: slot.name,
155
+ __loadPage: slot.pagePath ? true : null,
156
+ __loadDefault: slot.defaultPath ? true : null,
157
+ slotPatternParts: slot.slotPatternParts ?? null,
158
+ slotParamNames: slot.slotParamNames ?? null,
151
159
  intercepts: slot.interceptingRoutes.map((intercept) => ({
152
160
  id: intercept.id ?? null,
153
161
  targetPattern: intercept.targetPattern,
@@ -244,6 +252,8 @@ import { dispatchAppRequestStage as __dispatchAppRequestStage } from ${JSON.stri
244
252
  import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters } from "virtual:vinext-cdn-cache-adapter";
245
253
  import { clearAppRequestStageContext as __clearRequestContext, setAppRequestStageNavigationContext as setNavigationContext } from ${JSON.stringify(appRequestStageContextPath)};
246
254
  import { matchRoutePattern as __matchRoutePattern } from ${JSON.stringify(routePatternPath)};
255
+ import { initPregeneratedPathsFromGlobals as __initPregeneratedPathsFromGlobals } from ${JSON.stringify(pregeneratedConcretePathsPath)};
256
+ import "virtual:vinext-pregenerated-concrete-paths";
247
257
  import __pagesClientAssets from "virtual:vinext-pages-client-assets";
248
258
  ${middlewarePath ? `import { applyAppMiddleware as __applyAppMiddleware } from ${JSON.stringify(appMiddlewarePath)};` : ""}
249
259
  ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(toSlash(instrumentationPath))};
@@ -278,12 +288,16 @@ export { __basePath };
278
288
  export const __imageAllowedWidths = ${JSON.stringify([...config?.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...config?.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES])};
279
289
  export const __imageConfig = ${JSON.stringify({
280
290
  qualities: config?.imageConfig?.qualities,
291
+ localPatterns: config?.imageConfig?.localPatterns,
281
292
  dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
282
293
  dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
283
294
  contentDispositionType: config?.imageConfig?.contentDispositionType,
284
295
  contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy
285
296
  })};
286
297
  export const __clientBuildFiles = __pagesClientAssets.clientBuildFiles ?? [];
298
+ // The matcher reads recorded prerenders, and this stage can run without the
299
+ // response entry that also loads them.
300
+ __initPregeneratedPathsFromGlobals();
287
301
  const __routes = ${JSON.stringify(requestRoutes)};
288
302
  const __routeMatcher = __createAppRscRouteMatcher(__routes, ${JSON.stringify(buildAppDecodedPathnamePatterns(routes, config))});
289
303
  const __metadataRouteMatchers = ${JSON.stringify(metadataRouteMatchers)};
@@ -354,17 +368,21 @@ const __requestHandler = createAppRscRequestHandler({
354
368
  const intercept = __routeMatcher.findIntercept(pathname, sourcePathname, interceptionId);
355
369
  if (!intercept) return null;
356
370
  const route = __routes[intercept.sourceRouteIndex];
357
- if (!route) return null;
358
- const params = Object.create(null);
359
- for (const name of route.params) {
360
- if (Object.prototype.hasOwnProperty.call(intercept.sourceMatchedParams, name)) {
361
- params[name] = intercept.sourceMatchedParams[name];
371
+ const authorizationRoute = __routes[intercept.authorizationSourceRouteIndex];
372
+ if (!route || !authorizationRoute) return null;
373
+ const pickParams = (targetRoute, source) => {
374
+ const params = Object.create(null);
375
+ for (const name of targetRoute.params) {
376
+ if (Object.prototype.hasOwnProperty.call(source, name)) params[name] = source[name];
362
377
  }
363
- }
378
+ return params;
379
+ };
364
380
  return {
381
+ authorizationParams: pickParams(authorizationRoute, intercept.authorizationSourceParams),
382
+ authorizationRoute,
365
383
  interceptionSourceIsConcrete: intercept.sourceRouteIsConcrete,
366
384
  route,
367
- params,
385
+ params: pickParams(route, intercept.sourceMatchedParams),
368
386
  };
369
387
  },
370
388
  ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
@@ -482,6 +500,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
482
500
  const imageAllowedWidths = [...config?.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...config?.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES];
483
501
  const imageConfig = {
484
502
  qualities: config?.imageConfig?.qualities,
503
+ localPatterns: config?.imageConfig?.localPatterns,
485
504
  dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
486
505
  dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
487
506
  contentDispositionType: config?.imageConfig?.contentDispositionType,
@@ -1161,7 +1180,6 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1161
1180
  getSourceRoute(sourceRouteIndex) {
1162
1181
  return routes[sourceRouteIndex];
1163
1182
  },
1164
- hasCustomGlobalError: ${globalErrorVar ? `Boolean(${globalErrorVar}?.default)` : "false"},
1165
1183
  hasAnyGenerateStaticParams: __generateStaticParams.length > 0,
1166
1184
  hasGenerateStaticParams: __staticGeneration.hasGenerateStaticParams,
1167
1185
  hasPageDefaultExport: !!PageComponent,
@@ -1636,17 +1654,21 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
1636
1654
  const intercept = findIntercept(pathname, sourcePathname, interceptionId);
1637
1655
  if (!intercept) return null;
1638
1656
  const route = routes[intercept.sourceRouteIndex];
1639
- if (!route) return null;
1640
- const params = Object.create(null);
1641
- for (const name of route.params) {
1642
- if (Object.prototype.hasOwnProperty.call(intercept.sourceMatchedParams, name)) {
1643
- params[name] = intercept.sourceMatchedParams[name];
1657
+ const authorizationRoute = routes[intercept.authorizationSourceRouteIndex];
1658
+ if (!route || !authorizationRoute) return null;
1659
+ const pickParams = (targetRoute, source) => {
1660
+ const params = Object.create(null);
1661
+ for (const name of targetRoute.params) {
1662
+ if (Object.prototype.hasOwnProperty.call(source, name)) params[name] = source[name];
1644
1663
  }
1645
- }
1664
+ return params;
1665
+ };
1646
1666
  return {
1667
+ authorizationParams: pickParams(authorizationRoute, intercept.authorizationSourceParams),
1668
+ authorizationRoute,
1647
1669
  interceptionSourceIsConcrete: intercept.sourceRouteIsConcrete,
1648
1670
  route,
1649
- params,
1671
+ params: pickParams(route, intercept.sourceMatchedParams),
1650
1672
  };
1651
1673
  },
1652
1674
  ${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
@@ -108,6 +108,7 @@ function registerRouteModules(routes, imports) {
108
108
  if (slot.loadingPath) imports.getLazyLoaderVar(slot.loadingPath);
109
109
  for (const loadingPath of slot.loadingPaths ?? []) imports.getLazyLoaderVar(loadingPath);
110
110
  if (slot.errorPath) imports.getLazyLoaderVar(slot.errorPath);
111
+ for (const errorPath of slot.errorPaths ?? []) imports.getLazyLoaderVar(errorPath);
111
112
  if (slot.notFoundPath) imports.getLazyLoaderVar(slot.notFoundPath);
112
113
  for (const notFoundPath of slot.notFoundPaths ?? []) imports.getLazyLoaderVar(notFoundPath);
113
114
  for (const ir of slot.interceptingRoutes) {
@@ -240,6 +241,9 @@ function buildRouteEntries(routes, imports) {
240
241
  loadingTreePositions: ${JSON.stringify(slot.loadingTreePositions ?? [])},
241
242
  error: null,
242
243
  __loadError: ${slot.errorPath ? imports.getLazyLoaderVar(slot.errorPath) : "null"},
244
+ errors: ${moduleArray(slot.errorPaths?.length ?? 0)},
245
+ __loadErrors: ${lazyLoaderArray(slot.errorPaths ?? [], imports)},
246
+ errorTreePositions: ${JSON.stringify(slot.errorTreePositions ?? [])},
243
247
  notFound: null,
244
248
  __loadNotFound: ${slot.notFoundPath ? imports.getLazyLoaderVar(slot.notFoundPath) : "null"},
245
249
  notFoundTreePosition: ${slot.notFoundTreePosition ?? "null"},