vinext 1.2.1 → 1.3.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 (212) hide show
  1. package/README.md +12 -9
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/pages-client-assets-module.js +1 -1
  13. package/dist/build/prerender-paths.js +5 -2
  14. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  15. package/dist/build/server-actions-encryption-key.js +101 -0
  16. package/dist/build/ssr-manifest.d.ts +3 -0
  17. package/dist/build/ssr-manifest.js +10 -1
  18. package/dist/client/client-rewrite-params.d.ts +9 -0
  19. package/dist/client/client-rewrite-params.js +20 -0
  20. package/dist/client/dev-error-overlay.js +2 -1
  21. package/dist/client/navigation-runtime.d.ts +25 -2
  22. package/dist/client/navigation-runtime.js +42 -11
  23. package/dist/client/vinext-next-data.d.ts +0 -1
  24. package/dist/config/config-matchers.d.ts +15 -40
  25. package/dist/config/config-matchers.js +183 -255
  26. package/dist/config/config-source.d.ts +34 -0
  27. package/dist/config/config-source.js +141 -0
  28. package/dist/config/header-params.d.ts +29 -0
  29. package/dist/config/header-params.js +106 -0
  30. package/dist/config/next-config.d.ts +7 -5
  31. package/dist/config/next-config.js +120 -7
  32. package/dist/entries/app-browser-entry.d.ts +14 -1
  33. package/dist/entries/app-browser-entry.js +26 -36
  34. package/dist/entries/app-rsc-entry.d.ts +2 -0
  35. package/dist/entries/app-rsc-entry.js +92 -57
  36. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  37. package/dist/entries/app-rsc-manifest.js +20 -1
  38. package/dist/entries/app-ssr-entry.d.ts +4 -1
  39. package/dist/entries/app-ssr-entry.js +9 -2
  40. package/dist/entries/pages-client-entry.d.ts +1 -0
  41. package/dist/entries/pages-client-entry.js +6 -6
  42. package/dist/entries/pages-server-entry.js +17 -14
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.js +239 -83
  45. package/dist/init.js +17 -0
  46. package/dist/plugins/optimize-imports.d.ts +25 -2
  47. package/dist/plugins/optimize-imports.js +106 -20
  48. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  49. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  50. package/dist/plugins/use-cache-callable.d.ts +5 -0
  51. package/dist/plugins/use-cache-callable.js +30 -8
  52. package/dist/plugins/worker-image-imports.d.ts +1 -0
  53. package/dist/plugins/worker-image-imports.js +1 -1
  54. package/dist/routing/app-route-graph.d.ts +1 -1
  55. package/dist/routing/browser-route-manifest.d.ts +43 -0
  56. package/dist/routing/browser-route-manifest.js +195 -0
  57. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  58. package/dist/routing/hashed-route-patterns.js +22 -0
  59. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  60. package/dist/routing/optimistic-route-trie.js +102 -0
  61. package/dist/routing/route-validation.d.ts +6 -1
  62. package/dist/routing/route-validation.js +26 -10
  63. package/dist/server/app-action-forwarding.d.ts +8 -0
  64. package/dist/server/app-action-forwarding.js +15 -1
  65. package/dist/server/app-browser-entry.js +147 -60
  66. package/dist/server/app-browser-error.d.ts +3 -1
  67. package/dist/server/app-browser-error.js +7 -2
  68. package/dist/server/app-browser-interception-context.d.ts +2 -2
  69. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  70. package/dist/server/app-browser-mpa-navigation.js +6 -5
  71. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  72. package/dist/server/app-browser-navigation-controller.js +88 -26
  73. package/dist/server/app-browser-state.d.ts +2 -2
  74. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  75. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  76. package/dist/server/app-client-reference-preloader.js +30 -7
  77. package/dist/server/app-fallback-renderer.js +2 -1
  78. package/dist/server/app-middleware.d.ts +6 -0
  79. package/dist/server/app-middleware.js +8 -10
  80. package/dist/server/app-optimistic-routing.d.ts +8 -10
  81. package/dist/server/app-optimistic-routing.js +4 -95
  82. package/dist/server/app-page-boundary-render.js +8 -1
  83. package/dist/server/app-page-cache-render.js +1 -0
  84. package/dist/server/app-page-dispatch.js +2 -0
  85. package/dist/server/app-page-render.js +3 -1
  86. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  87. package/dist/server/app-page-rsc-render-status.js +1 -0
  88. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  89. package/dist/server/app-page-search-params-observation.js +8 -10
  90. package/dist/server/app-page-stream.d.ts +7 -0
  91. package/dist/server/app-page-stream.js +1 -0
  92. package/dist/server/app-pages-bridge.d.ts +2 -1
  93. package/dist/server/app-pages-bridge.js +11 -7
  94. package/dist/server/app-prerender-static-params.js +3 -2
  95. package/dist/server/app-render-dependency.js +42 -2
  96. package/dist/server/app-request-stage-independent-entry.js +2 -2
  97. package/dist/server/app-response-stage-entry.js +3 -3
  98. package/dist/server/app-route-handler-dispatch.js +3 -1
  99. package/dist/server/app-route-handler-execution.d.ts +2 -0
  100. package/dist/server/app-route-handler-execution.js +9 -2
  101. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  102. package/dist/server/app-route-handler-middleware-context.js +3 -3
  103. package/dist/server/app-route-handler-response.d.ts +2 -1
  104. package/dist/server/app-route-handler-response.js +2 -2
  105. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  106. package/dist/server/app-route-handler-runtime.js +20 -3
  107. package/dist/server/app-route-module-loader.js +7 -6
  108. package/dist/server/app-route-tree.d.ts +20 -0
  109. package/dist/server/app-route-tree.js +18 -0
  110. package/dist/server/app-router-entry.js +2 -2
  111. package/dist/server/app-rsc-combined-handler.js +8 -1
  112. package/dist/server/app-rsc-errors.d.ts +7 -0
  113. package/dist/server/app-rsc-errors.js +9 -2
  114. package/dist/server/app-rsc-handler.d.ts +4 -1
  115. package/dist/server/app-rsc-handler.js +146 -130
  116. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  117. package/dist/server/app-rsc-response-finalizer.js +4 -1
  118. package/dist/server/app-rsc-response-stage.js +3 -1
  119. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  120. package/dist/server/app-rsc-route-matching.js +1 -1
  121. package/dist/server/app-server-action-execution.d.ts +23 -6
  122. package/dist/server/app-server-action-execution.js +50 -56
  123. package/dist/server/app-ssr-entry.d.ts +6 -0
  124. package/dist/server/app-ssr-entry.js +16 -7
  125. package/dist/server/app-ssr-stream.d.ts +7 -0
  126. package/dist/server/app-ssr-stream.js +13 -1
  127. package/dist/server/config-headers.js +12 -3
  128. package/dist/server/isolate-shared-promise.d.ts +10 -0
  129. package/dist/server/isolate-shared-promise.js +33 -0
  130. package/dist/server/isr-cache.js +3 -2
  131. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  132. package/dist/server/middleware-matcher-pattern.js +11 -140
  133. package/dist/server/middleware-matcher.js +5 -6
  134. package/dist/server/middleware-response-headers.d.ts +31 -0
  135. package/dist/server/middleware-response-headers.js +57 -1
  136. package/dist/server/middleware-runtime.js +26 -13
  137. package/dist/server/navigation-planner.d.ts +2 -2
  138. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  139. package/dist/server/nitro-public-files-plugin.js +106 -0
  140. package/dist/server/nitro-public-files.d.ts +21 -0
  141. package/dist/server/nitro-public-files.js +39 -0
  142. package/dist/server/pages-asset-tags.d.ts +5 -0
  143. package/dist/server/pages-asset-tags.js +9 -2
  144. package/dist/server/pages-client-assets.d.ts +4 -1
  145. package/dist/server/pages-i18n.d.ts +18 -0
  146. package/dist/server/pages-i18n.js +18 -2
  147. package/dist/server/pages-node-compat.d.ts +5 -3
  148. package/dist/server/pages-node-compat.js +35 -16
  149. package/dist/server/pages-request-pipeline.d.ts +6 -1
  150. package/dist/server/pages-request-pipeline.js +31 -35
  151. package/dist/server/pages-request-stage-entry.js +16 -6
  152. package/dist/server/pages-response-stage-entry.js +1 -1
  153. package/dist/server/pages-revalidate.js +1 -0
  154. package/dist/server/pages-router-entry.js +1 -1
  155. package/dist/server/prod-server.d.ts +2 -2
  156. package/dist/server/prod-server.js +71 -33
  157. package/dist/server/proxy-trust.d.ts +6 -0
  158. package/dist/server/proxy-trust.js +12 -6
  159. package/dist/server/request-pipeline.d.ts +5 -0
  160. package/dist/server/request-pipeline.js +12 -1
  161. package/dist/server/server-reference-loader.js +10 -1
  162. package/dist/server/static-file-cache.js +15 -3
  163. package/dist/server/worker-utils.js +1 -1
  164. package/dist/shims/cache-handler.js +3 -2
  165. package/dist/shims/cache-request-state.d.ts +40 -3
  166. package/dist/shims/cache-request-state.js +70 -5
  167. package/dist/shims/cache-runtime.js +47 -19
  168. package/dist/shims/cache.d.ts +2 -2
  169. package/dist/shims/cache.js +17 -8
  170. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  171. package/dist/shims/cdn-purge-routes.js +77 -0
  172. package/dist/shims/dynamic.js +17 -4
  173. package/dist/shims/form.js +8 -3
  174. package/dist/shims/image-props.d.ts +93 -0
  175. package/dist/shims/image-props.js +323 -0
  176. package/dist/shims/image.d.ts +4 -18
  177. package/dist/shims/image.js +4 -319
  178. package/dist/shims/internal/headers-state.d.ts +7 -0
  179. package/dist/shims/internal/headers-state.js +14 -2
  180. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  181. package/dist/shims/internal/hybrid-client-route-owner-direct.js +31 -14
  182. package/dist/shims/internal/hybrid-client-route-owner.js +8 -8
  183. package/dist/shims/link.js +5 -3
  184. package/dist/shims/navigation.d.ts +1 -1
  185. package/dist/shims/navigation.js +17 -5
  186. package/dist/shims/og.js +35 -10
  187. package/dist/shims/request-context.d.ts +13 -0
  188. package/dist/shims/router.js +19 -40
  189. package/dist/shims/server.d.ts +31 -4
  190. package/dist/shims/server.js +58 -10
  191. package/dist/shims/thenable-params.d.ts +6 -1
  192. package/dist/shims/thenable-params.js +11 -2
  193. package/dist/shims/unified-request-context.d.ts +5 -0
  194. package/dist/shims/unified-request-context.js +2 -0
  195. package/dist/utils/asset-prefix.d.ts +7 -0
  196. package/dist/utils/asset-prefix.js +10 -1
  197. package/dist/utils/client-build-manifest.js +12 -5
  198. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  199. package/dist/utils/client-runtime-metadata.js +15 -2
  200. package/dist/utils/lazy-chunks.d.ts +4 -0
  201. package/dist/utils/manifest-paths.d.ts +14 -0
  202. package/dist/utils/manifest-paths.js +22 -1
  203. package/dist/utils/path-to-regexp.d.ts +21 -0
  204. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  205. package/dist/utils/plugin-react-version.d.ts +15 -0
  206. package/dist/utils/plugin-react-version.js +64 -0
  207. package/dist/utils/public-routes.d.ts +2 -0
  208. package/dist/utils/public-routes.js +18 -7
  209. package/package.json +1 -1
  210. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  211. package/dist/utils/regex-safety.d.ts +0 -17
  212. package/dist/utils/regex-safety.js +0 -789
@@ -1,6 +1,6 @@
1
1
  import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
2
2
  import { createNonceAttribute } from "./html.js";
3
- import { assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
3
+ import { SSR_MANIFEST_SHARED_CHUNKS_KEY, assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
4
4
  import { getPagesClientAssets } from "./pages-client-assets.js";
5
5
  //#region src/server/pages-asset-tags.ts
6
6
  /**
@@ -55,7 +55,14 @@ function findModuleKey(manifest, moduleId) {
55
55
  }
56
56
  return matchedKey;
57
57
  }
58
+ /**
59
+ * Fallback for when no build-time `sharedChunks` list is registered. Prefers
60
+ * the chunk-name based list the build writes into the SSR manifest; the file
61
+ * name scan only matches `[name]-[hash]` names, not hash-only ones.
62
+ */
58
63
  function getSharedChunkFiles(manifest) {
64
+ const recorded = manifest[SSR_MANIFEST_SHARED_CHUNKS_KEY];
65
+ if (recorded) return recorded;
59
66
  const cached = sharedChunkFiles.get(manifest);
60
67
  if (cached) return cached;
61
68
  const files = /* @__PURE__ */ new Set();
@@ -186,7 +193,7 @@ function collectAssetTags(options) {
186
193
  const files = getManifestFilesForModule(m, id);
187
194
  if (files) for (let fi = 0; fi < files.length; fi++) allFiles.push(files[fi]);
188
195
  }
189
- const sharedFiles = m === runtimeAssets.ssrManifest && runtimeAssets.sharedChunks ? runtimeAssets.sharedChunks : getSharedChunkFiles(m);
196
+ const sharedFiles = runtimeAssets.sharedChunks ?? getSharedChunkFiles(m);
190
197
  for (const file of sharedFiles) allFiles.push(file);
191
198
  } else for (const akey in m) {
192
199
  const avals = m[akey];
@@ -4,7 +4,10 @@ export type PagesClientAssets = {
4
4
  clientEntry?: string;
5
5
  appBootstrapPreinitModules?: string[];
6
6
  ssrManifest?: Record<string, string[]>;
7
- /** Build-time shared file list, valid only for this ssrManifest object. */
7
+ /**
8
+ * Shared Pages chunk files (framework, vinext runtime, client entry) keyed on
9
+ * chunk names from this client build, in the SSR-manifest key-space.
10
+ */
8
11
  sharedChunks?: string[];
9
12
  cssGraph?: Record<string, {
10
13
  imports?: string[];
@@ -63,12 +63,30 @@ export declare function detectPathnameLocale(pathname: string, locales: readonly
63
63
  * `:locale`. After normalisation the request looks like `/en/to-sv` and
64
64
  * the rule matches with `:locale=en`.
65
65
  *
66
+ * `restoreRootTrailingSlash` makes the root `/en/` rather than `/en`; header
67
+ * callers compute it with `shouldRestoreLocaleRootTrailingSlash`. Redirect
68
+ * and rewrite callers do not pass it yet.
69
+ *
66
70
  * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
67
71
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
68
72
  */
69
73
  export declare function normalizeDefaultLocalePathname(pathname: string, i18n: NextI18nConfig | null | undefined, options?: {
70
74
  hostname?: string | null;
75
+ restoreRootTrailingSlash?: boolean;
71
76
  }): string;
77
+ /**
78
+ * Whether Next.js re-adds the root's trailing slash after splicing in the
79
+ * default locale: the raw request pathname (basePath included, so `/docs`
80
+ * stays `/docs/en` while `/docs/` becomes `/docs/en/`) ends with `/`, and
81
+ * `trailingSlash` is on without `skipProxyUrlNormalize`.
82
+ *
83
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
84
+ * (`hadTrailingSlash` + `maybeAddTrailingSlash`).
85
+ */
86
+ export declare function shouldRestoreLocaleRootTrailingSlash(rawPathname: string, config: {
87
+ trailingSlash?: boolean;
88
+ skipProxyUrlNormalize?: boolean;
89
+ }): boolean;
72
90
  /**
73
91
  * Extract locale prefix from a URL path.
74
92
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
@@ -51,6 +51,10 @@ function detectPathnameLocale(pathname, locales) {
51
51
  * `:locale`. After normalisation the request looks like `/en/to-sv` and
52
52
  * the rule matches with `:locale=en`.
53
53
  *
54
+ * `restoreRootTrailingSlash` makes the root `/en/` rather than `/en`; header
55
+ * callers compute it with `shouldRestoreLocaleRootTrailingSlash`. Redirect
56
+ * and rewrite callers do not pass it yet.
57
+ *
54
58
  * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
55
59
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
56
60
  */
@@ -59,10 +63,22 @@ function normalizeDefaultLocalePathname(pathname, i18n, options = {}) {
59
63
  if (pathname.startsWith("/_next/") || pathname.startsWith("/__vinext/")) return pathname;
60
64
  if (detectPathnameLocale(pathname, i18n.locales)) return pathname;
61
65
  const defaultLocale = detectDomainLocale(i18n.domains, options.hostname ?? void 0)?.defaultLocale ?? i18n.defaultLocale;
62
- if (pathname === "/") return `/${defaultLocale}`;
66
+ if (pathname === "/") return options.restoreRootTrailingSlash ? `/${defaultLocale}/` : `/${defaultLocale}`;
63
67
  return `/${defaultLocale}${pathname}`;
64
68
  }
65
69
  /**
70
+ * Whether Next.js re-adds the root's trailing slash after splicing in the
71
+ * default locale: the raw request pathname (basePath included, so `/docs`
72
+ * stays `/docs/en` while `/docs/` becomes `/docs/en/`) ends with `/`, and
73
+ * `trailingSlash` is on without `skipProxyUrlNormalize`.
74
+ *
75
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
76
+ * (`hadTrailingSlash` + `maybeAddTrailingSlash`).
77
+ */
78
+ function shouldRestoreLocaleRootTrailingSlash(rawPathname, config) {
79
+ return Boolean(config.trailingSlash && !config.skipProxyUrlNormalize && rawPathname.endsWith("/"));
80
+ }
81
+ /**
66
82
  * Extract locale prefix from a URL path.
67
83
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
68
84
  * /about -> { locale: defaultLocale, url: "/about", hadPrefix: false }
@@ -243,4 +259,4 @@ function resolvePagesI18nRequest(url, i18nConfig, headers, hostname, basePath =
243
259
  };
244
260
  }
245
261
  //#endregion
246
- export { detectDomainLocale, detectLocaleFromAcceptLanguage, detectPathnameLocale, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
262
+ export { detectDomainLocale, detectLocaleFromAcceptLanguage, detectPathnameLocale, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, shouldRestoreLocaleRootTrailingSlash, stripI18nLocaleForApiRoute };
@@ -15,15 +15,17 @@ export type PagesReqResRequest = Readable & {
15
15
  draftMode?: true;
16
16
  previewData: PagesPreviewData | false;
17
17
  };
18
+ type PagesReqResHeaderValue = string | number | boolean | string[];
18
19
  type PagesReqResHeaders = {
19
- [key: string]: string | number | boolean | string[];
20
+ [key: string]: PagesReqResHeaderValue;
20
21
  };
21
22
  export type PagesReqResResponse = Writable & {
22
23
  statusCode: number;
23
24
  readonly headersSent: boolean;
24
25
  writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;
25
- setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;
26
- getHeader: (name: string) => string | number | boolean | string[] | undefined;
26
+ setHeader: (name: string, value: PagesReqResHeaderValue) => PagesReqResResponse;
27
+ appendHeader: (name: string, value: string | readonly string[]) => PagesReqResResponse;
28
+ getHeader: (name: string) => PagesReqResHeaderValue | undefined;
27
29
  status: (code: number) => PagesReqResResponse;
28
30
  json: (data: unknown) => void;
29
31
  send: (data: unknown) => void;
@@ -1,4 +1,5 @@
1
1
  import { parseCookieHeader } from "../utils/parse-cookie.js";
2
+ import { getRequestExecutionContext } from "../shims/request-context.js";
2
3
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
3
4
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
4
5
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
@@ -13,6 +14,18 @@ const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
13
14
  205,
14
15
  304
15
16
  ]);
17
+ const HTTP_TOKEN_PATTERN = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
18
+ const INVALID_HEADER_VALUE_CHAR_PATTERN = /[^\t\x20-\x7e\x80-\xff]/;
19
+ function createNodeTypeError(code, message) {
20
+ return Object.assign(new TypeError(message), { code });
21
+ }
22
+ function validateAppendedHeader(name, value) {
23
+ if (typeof name !== "string" || !name || !HTTP_TOKEN_PATTERN.test(name)) throw createNodeTypeError("ERR_INVALID_HTTP_TOKEN", `Header name must be a valid HTTP token ["${String(name)}"]`);
24
+ for (const item of Array.isArray(value) ? value : [value]) {
25
+ if (item === void 0) throw createNodeTypeError("ERR_HTTP_INVALID_HEADER_VALUE", `Invalid value "undefined" for header "${name}"`);
26
+ if (INVALID_HEADER_VALUE_CHAR_PATTERN.test(String(item))) throw createNodeTypeError("ERR_INVALID_CHAR", `Invalid character in header content ["${name}"]`);
27
+ }
28
+ }
16
29
  async function readPagesRequestBodyWithLimit(request, maxBytes) {
17
30
  if (!request.body) return "";
18
31
  return readStreamAsTextWithLimit(request.body, maxBytes, () => {
@@ -120,9 +133,9 @@ var PagesResponseStream = class extends Writable {
120
133
  resolveResponse;
121
134
  rejectResponse;
122
135
  resStatusCode = 200;
123
- resHeaders = {};
124
- setCookieHeaders = [];
136
+ resHeaders = Object.create(null);
125
137
  resolved = false;
138
+ headWritten = false;
126
139
  controller = null;
127
140
  bufferedChunks = [];
128
141
  streamEnded = false;
@@ -150,15 +163,21 @@ var PagesResponseStream = class extends Writable {
150
163
  }
151
164
  writeHead(code, headers) {
152
165
  this.resStatusCode = code;
153
- if (headers) for (const [key, value] of Object.entries(headers)) this.setHeaderValue(key, value, { replaceSetCookie: true });
166
+ if (headers) for (const [key, value] of Object.entries(headers)) this.setHeaderValue(key, value, { append: false });
167
+ this.headWritten = true;
154
168
  return this;
155
169
  }
156
170
  setHeader(name, value) {
157
- this.setHeaderValue(name, value, { replaceSetCookie: true });
171
+ this.setHeaderValue(name, value, { append: false });
172
+ return this;
173
+ }
174
+ appendHeader(name, value) {
175
+ if (this.headWritten || this.headersSent) throw Object.assign(/* @__PURE__ */ new Error("Cannot append headers after they are sent to the client"), { code: "ERR_HTTP_HEADERS_SENT" });
176
+ validateAppendedHeader(name, value);
177
+ this.setHeaderValue(name, value, { append: true });
158
178
  return this;
159
179
  }
160
180
  getHeader(name) {
161
- if (name.toLowerCase() === "set-cookie") return this.setCookieHeaders.length > 0 ? this.setCookieHeaders : void 0;
162
181
  return this.resHeaders[name.toLowerCase()];
163
182
  }
164
183
  status(code) {
@@ -196,9 +215,7 @@ var PagesResponseStream = class extends Writable {
196
215
  return this;
197
216
  }
198
217
  getHeaders() {
199
- const headers = { ...this.resHeaders };
200
- if (this.setCookieHeaders.length > 0) headers["set-cookie"] = this.setCookieHeaders;
201
- return headers;
218
+ return { ...this.resHeaders };
202
219
  }
203
220
  setPreviewData(data, options = {}) {
204
221
  setPagesPreviewData(this, data, options);
@@ -250,13 +267,15 @@ var PagesResponseStream = class extends Writable {
250
267
  callback(error);
251
268
  }
252
269
  setHeaderValue(name, value, options) {
253
- if (name.toLowerCase() === "set-cookie") {
254
- const values = Array.isArray(value) ? value.map(String) : [String(value)];
255
- if (options.replaceSetCookie) this.setCookieHeaders.length = 0;
256
- this.setCookieHeaders.push(...values);
270
+ const key = name.toLowerCase();
271
+ const existing = this.resHeaders[key];
272
+ if (!options.append || existing === void 0) {
273
+ this.resHeaders[key] = value;
257
274
  return;
258
275
  }
259
- this.resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
276
+ const values = Array.isArray(existing) ? existing : [existing];
277
+ values.push(...Array.isArray(value) ? value : [value]);
278
+ this.resHeaders[key] = values;
260
279
  }
261
280
  releasePendingWrite(error) {
262
281
  const callback = this.pendingWrite;
@@ -267,8 +286,8 @@ var PagesResponseStream = class extends Writable {
267
286
  if (this.resolved) return;
268
287
  this.resolved = true;
269
288
  const headers = new Headers();
270
- for (const [key, value] of Object.entries(this.resHeaders)) headers.set(key, String(value));
271
- for (const cookie of this.setCookieHeaders) headers.append("set-cookie", cookie);
289
+ for (const [key, value] of Object.entries(this.resHeaders)) if (Array.isArray(value)) for (const item of value) headers.append(key, String(item));
290
+ else headers.set(key, String(value));
272
291
  if (NO_BODY_RESPONSE_STATUSES.has(this.resStatusCode)) {
273
292
  this.discardBody = true;
274
293
  this.bufferedChunks.length = 0;
@@ -359,10 +378,10 @@ function createPagesReqRes(options) {
359
378
  */
360
379
  function createPagesApiReqRes(options) {
361
380
  const { req, res, responsePromise } = createPagesReqRes(options);
362
- const trustedRevalidateOrigin = options.trustedRevalidateOrigin ?? new URL(options.request.url).origin;
363
381
  return {
364
382
  req,
365
383
  res: Object.assign(res, { async revalidate(urlPath, opts) {
384
+ const trustedRevalidateOrigin = options.trustedRevalidateOrigin ?? (getRequestExecutionContext()?.dispatchPagesRevalidate ? new URL(options.request.url).origin : void 0);
366
385
  await performOnDemandRevalidate(options.request.headers, urlPath, opts, trustedRevalidateOrigin, options.allowedRevalidateHeaderKeys);
367
386
  } }),
368
387
  responsePromise
@@ -15,7 +15,7 @@ type PageRouteMatch = {
15
15
  dataKind?: PagesRouteDataKind;
16
16
  };
17
17
  };
18
- export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles: ReadonlySet<string>, basePath?: string, assetPathPrefix?: string, hadBasePath?: boolean): Promise<Response | false>;
18
+ export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles: ReadonlySet<string>, basePath?: string, assetPathPrefix?: string, pathnameHasBasePath?: boolean): Promise<Response | false>;
19
19
  export type MiddlewareResult = {
20
20
  continue: boolean;
21
21
  /** The pathname matches middleware, irrespective of request `has`/`missing` conditions. */
@@ -54,6 +54,11 @@ export type PagesPipelineDeps = {
54
54
  recordCacheability?: boolean;
55
55
  rawSearch?: string;
56
56
  configMatchPathname?: string;
57
+ /**
58
+ * `shouldRestoreLocaleRootTrailingSlash` for the raw request pathname
59
+ * (basePath included), which the basePath-stripped request no longer shows.
60
+ */
61
+ restoreLocaleRootTrailingSlash?: boolean;
57
62
  /**
58
63
  * Validate an on-demand revalidation credential using the runtime's
59
64
  * authoritative build secret. Production adapters must inject the verifier
@@ -6,7 +6,7 @@ import { VINEXT_PRERENDER_REWRITTEN_HEADER } from "./headers.js";
6
6
  import { methodNotAllowedResponse, notFoundStaticAssetResponse, sanitizeMethodNotAllowedHeaders } from "./http-error-responses.js";
7
7
  import { cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
8
8
  import { applyMiddlewareRequestHeaders, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
9
- import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
9
+ import { assetPrefixPathname, isAssetPrefixBuildAsset, isNextStaticPath } from "../utils/asset-prefix.js";
10
10
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
11
11
  import { patternToNextFormat } from "../routing/route-validation.js";
12
12
  import { detectPathnameLocale, normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
@@ -14,6 +14,7 @@ import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
14
14
  import { markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
15
15
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
16
16
  import { mergeRewriteQuery } from "../utils/query.js";
17
+ import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
17
18
  import { setFrameworkRequestRoute } from "./request-tracing.js";
18
19
  import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
19
20
  import { finalizeMissingStaticAssetResponse, mergeHeaders } from "./worker-utils.js";
@@ -33,7 +34,7 @@ function headersFromRecord(record) {
33
34
  else headers.set(name, value);
34
35
  return headers;
35
36
  }
36
- async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset, publicFiles, basePath = "", assetPathPrefix = "", hadBasePath = true) {
37
+ async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset, publicFiles, basePath = "", assetPathPrefix = "", pathnameHasBasePath = true) {
37
38
  const isRetrievalMethod = request.method === "GET" || request.method === "HEAD";
38
39
  const assetUrl = new URL(request.url);
39
40
  assetUrl.pathname = requestPathname;
@@ -46,7 +47,8 @@ async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetch
46
47
  } catch {
47
48
  return false;
48
49
  }
49
- const isPublicFile = (phase !== "direct" || hadBasePath) && publicFiles.has(publicFileKey);
50
+ if (!pathnameHasBasePath && !isAssetPrefixBuildAsset(decodedAssetUrl.pathname, assetPathPrefix)) return false;
51
+ const isPublicFile = pathnameHasBasePath && publicFiles.has(publicFileKey);
50
52
  if (!isPublicFile && (requestPathname === "/api" || requestPathname.startsWith("/api/"))) return false;
51
53
  if (phase === "direct" && isRetrievalMethod && !isPublicFile) return false;
52
54
  if (!isPublicFile && !isNextStaticPath(decodedAssetUrl.pathname, basePath, assetPathPrefix)) return false;
@@ -118,6 +120,10 @@ async function runPagesRequest(request, deps) {
118
120
  const reqCtx = requestContextFromRequest(request);
119
121
  const requestHostname = i18nConfig ? url.hostname : "";
120
122
  const requestConfigMatchPathname = i18nConfig ? normalizeDefaultLocalePathname(requestConfigPathname, i18nConfig, { hostname: requestHostname }) : requestConfigPathname;
123
+ const requestHeaderMatchPathname = i18nConfig ? normalizeDefaultLocalePathname(requestConfigPathname, i18nConfig, {
124
+ hostname: requestHostname,
125
+ restoreRootTrailingSlash: deps.restoreLocaleRootTrailingSlash
126
+ }) : requestConfigPathname;
121
127
  if (configRedirects.length) {
122
128
  const redirect = matchRedirect(requestConfigMatchPathname, configRedirects, reqCtx, basePathState, conditionalRedirectCacheability);
123
129
  if (redirect) {
@@ -141,14 +147,16 @@ async function runPagesRequest(request, deps) {
141
147
  hadBasePath: resolvedPathnameHasBasePath
142
148
  });
143
149
  const middlewareHeaders = {};
150
+ let middlewareCookies = [];
144
151
  const mergeConfigHeadersIntoEarlyResponse = (response) => {
145
152
  if (configHeaders.length === 0) return response;
146
153
  const matchedConfigHeaders = {};
147
154
  applyConfigHeadersToHeaderRecord(matchedConfigHeaders, {
148
155
  configHeaders,
149
- pathname: requestConfigMatchPathname,
156
+ pathname: requestHeaderMatchPathname,
150
157
  requestContext: reqCtx,
151
158
  basePathState,
159
+ middlewareHeaders: response.headers,
152
160
  recordCacheability: deps.recordCacheability
153
161
  });
154
162
  return mergeHeaders(response, matchedConfigHeaders);
@@ -210,6 +218,8 @@ async function runPagesRequest(request, deps) {
210
218
  else if (existing) middlewareHeaders[key] = [existing, value];
211
219
  else middlewareHeaders[key] = [value];
212
220
  } else middlewareHeaders[key] = value;
221
+ const stagedCookies = middlewareHeaders["set-cookie"];
222
+ if (Array.isArray(stagedCookies)) middlewareCookies = [...stagedCookies];
213
223
  if (result.rewriteUrl) {
214
224
  resolvedUrl = result.rewriteUrl;
215
225
  resolvedPathnameIsRequestPathname = false;
@@ -249,26 +259,24 @@ async function runPagesRequest(request, deps) {
249
259
  };
250
260
  if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
251
261
  configHeaders,
252
- pathname: requestConfigMatchPathname,
262
+ pathname: requestHeaderMatchPathname,
253
263
  requestContext: reqCtx,
254
264
  basePathState,
255
265
  recordCacheability: deps.recordCacheability
256
266
  });
257
- if (isExternalUrl(resolvedUrl)) {
258
- const proxyResponse = await proxyExternal(request, resolvedUrl);
259
- return {
260
- type: "response",
261
- response: mergeHeaders(proxyResponse, middlewareHeaders, void 0)
262
- };
263
- }
267
+ const proxyConfigRewrite = async (destination) => ({
268
+ type: "response",
269
+ response: withExternalRewriteResponseHeaders(await proxyExternal(request, destination), new Headers(), middlewareCookies)
270
+ });
271
+ if (isExternalUrl(resolvedUrl)) return {
272
+ type: "response",
273
+ response: withExternalRewriteResponseHeaders(await proxyExternal(request, resolvedUrl), headersFromRecord(middlewareHeaders), middlewareCookies)
274
+ };
264
275
  let configRewriteFired = false;
265
276
  for (const rewrite of configRewrites.beforeFiles ?? []) {
266
277
  const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
267
278
  if (rewritten) {
268
- if (isExternalUrl(rewritten)) return {
269
- type: "response",
270
- response: await proxyExternal(request, rewritten)
271
- };
279
+ if (isExternalUrl(rewritten)) return proxyConfigRewrite(rewritten);
272
280
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
273
281
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
274
282
  resolvedPathnameIsRequestPathname = false;
@@ -279,13 +287,13 @@ async function runPagesRequest(request, deps) {
279
287
  const initialFilesystemResult = await serveFilesystemRoute(resolvedPathname, resolvedPathnameIsRequestPathname ? "direct" : "beforeFiles");
280
288
  if (initialFilesystemResult) return initialFilesystemResult;
281
289
  const isMissingBuildAsset = () => isNextStaticPath(resolvedPathname, "", assetPrefixPathname(deps.assetPrefix ?? ""));
282
- const isOutsideBasePathUnclaimed = () => basePath && !hadBasePath && !configRewriteFired;
290
+ const isOutsideBasePathUnclaimed = () => basePath && !resolvedPathnameHasBasePath;
283
291
  const outOfBasePathNotFound = () => ({
284
292
  type: "response",
285
- response: isMissingBuildAsset() ? notFoundStaticAssetResponse(headersFromRecord(middlewareHeaders)) : new Response("This page could not be found", {
293
+ response: isMissingBuildAsset() ? notFoundStaticAssetResponse(headersFromRecord(middlewareHeaders)) : mergeHeaders(new Response("This page could not be found", {
286
294
  status: 404,
287
295
  headers: { "Content-Type": "text/html; charset=utf-8" }
288
- })
296
+ }), middlewareHeaders)
289
297
  });
290
298
  const handleResolvedApiRoute = async () => {
291
299
  if (isOutsideBasePathUnclaimed()) return null;
@@ -327,10 +335,7 @@ async function runPagesRequest(request, deps) {
327
335
  if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
328
336
  const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
329
337
  if (rewritten) {
330
- if (isExternalUrl(rewritten)) return {
331
- type: "response",
332
- response: await proxyExternal(request, rewritten)
333
- };
338
+ if (isExternalUrl(rewritten)) return proxyConfigRewrite(rewritten);
334
339
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
335
340
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
336
341
  resolvedPathnameIsRequestPathname = false;
@@ -355,10 +360,7 @@ async function runPagesRequest(request, deps) {
355
360
  if ((isOutsideBasePathUnclaimed() || isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
356
361
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
357
362
  if (!fallbackRewrite) continue;
358
- if (isExternalUrl(fallbackRewrite)) return {
359
- type: "response",
360
- response: await proxyExternal(request, fallbackRewrite)
361
- };
363
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
362
364
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
363
365
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
364
366
  resolvedPathnameIsRequestPathname = false;
@@ -384,10 +386,7 @@ async function runPagesRequest(request, deps) {
384
386
  if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
385
387
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
386
388
  if (!fallbackRewrite) continue;
387
- if (isExternalUrl(fallbackRewrite)) return {
388
- type: "response",
389
- response: await proxyExternal(request, fallbackRewrite)
390
- };
389
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
391
390
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
392
391
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
393
392
  resolvedPathnameIsRequestPathname = false;
@@ -437,10 +436,7 @@ async function runPagesRequest(request, deps) {
437
436
  if (!devPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
438
437
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
439
438
  if (!fallbackRewrite) continue;
440
- if (isExternalUrl(fallbackRewrite)) return {
441
- type: "response",
442
- response: await proxyExternal(request, fallbackRewrite)
443
- };
439
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
444
440
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
445
441
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
446
442
  resolvedPathnameIsRequestPathname = false;
@@ -7,7 +7,7 @@ import { attachRequestCfMetadata, cloneRequestWithHeaders, cloneRequestWithUrl,
7
7
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
8
8
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
9
9
  import { runWithExecutionContext } from "../shims/request-context.js";
10
- import { normalizeDefaultLocalePathname } from "./pages-i18n.js";
10
+ import { normalizeDefaultLocalePathname, shouldRestoreLocaleRootTrailingSlash } from "./pages-i18n.js";
11
11
  import { isNextDataPathname } from "./pages-data-route.js";
12
12
  import { getExplicitCdnCacheAdapter } from "../shims/cdn-cache-state.js";
13
13
  import { CACHEABILITY_REQUEST_STATE } from "../shims/cacheability-classification.js";
@@ -48,6 +48,10 @@ const pagesRequestStagePrerenderSecret = pagesEntry.prerenderSecret ?? null;
48
48
  const basePath = vinextConfig?.basePath ?? "";
49
49
  const assetPathPrefix = assetPrefixPathname(vinextConfig?.assetPrefix ?? "");
50
50
  const trailingSlash = vinextConfig?.trailingSlash ?? false;
51
+ const localeRootTrailingSlashConfig = {
52
+ trailingSlash,
53
+ skipProxyUrlNormalize: vinextConfig?.skipProxyUrlNormalize
54
+ };
51
55
  const skipTrailingSlashRedirect = vinextConfig?.skipTrailingSlashRedirect ?? false;
52
56
  const i18nConfig = vinextConfig?.i18n ?? null;
53
57
  const configRedirects = vinextConfig?.redirects ?? [];
@@ -88,7 +92,7 @@ function handleRequestStageLocally(request, env, ctx, dispatchResponseStage) {
88
92
  function handleRequest(request, env, platformCtx, dispatchResponseStage, forceCacheBypass, defaultHostRuntime, assets) {
89
93
  const url = new URL(request.url);
90
94
  const trace = async () => {
91
- await pagesEntry.__ensureInstrumentation?.();
95
+ await pagesEntry.__ensureInstrumentation?.(platformCtx);
92
96
  return traceFrameworkRequest({
93
97
  callback: () => handleRequestImpl(request, env, platformCtx, dispatchResponseStage, forceCacheBypass, defaultHostRuntime, assets),
94
98
  getStatus: (response) => response?.status,
@@ -175,6 +179,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
175
179
  }
176
180
  const missingBuildAsset = isNextStaticPath(pathname, basePath, assetPathPrefix);
177
181
  const hadBasePath = !basePath || hasBasePath(pathname, basePath);
182
+ const restoreLocaleRootTrailingSlash = shouldRestoreLocaleRootTrailingSlash(pathname, localeRootTrailingSlashConfig);
178
183
  {
179
184
  const stripped = stripBasePath(pathname, basePath);
180
185
  if (stripped !== pathname) {
@@ -193,7 +198,10 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
193
198
  request = dataNorm.request;
194
199
  pathname = dataNorm.normalizedPathname;
195
200
  }
196
- const responseStagePolicyPathname = i18nConfig ? normalizeDefaultLocalePathname(pathname, i18nConfig, { hostname: url.hostname }) : pathname;
201
+ const responseStagePolicyPathname = i18nConfig ? normalizeDefaultLocalePathname(pathname, i18nConfig, {
202
+ hostname: url.hostname,
203
+ restoreRootTrailingSlash: restoreLocaleRootTrailingSlash
204
+ }) : pathname;
197
205
  const responseStagePolicyHeaders = resolveResponseStageCachePolicy({
198
206
  basePathState: {
199
207
  basePath,
@@ -219,6 +227,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
219
227
  hasMiddleware,
220
228
  ctx,
221
229
  recordCacheability: forceCacheBypass,
230
+ restoreLocaleRootTrailingSlash,
222
231
  middlewareRequest: isDataReq && vinextConfig?.skipProxyUrlNormalize ? middlewareRequest : void 0,
223
232
  dataNotFoundResponse: vinextConfig?.skipProxyUrlNormalize ? dataNorm.notFoundResponse : null,
224
233
  authorizeOnDemandRevalidate: typeof authorizeOnDemandRevalidate === "function" ? authorizeOnDemandRevalidate : void 0,
@@ -320,7 +329,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
320
329
  fetchPublicFile: (sourceRequest) => resolvePublicImageSource(sourceRequest, assets)
321
330
  }), allowedWidths, imageConfig);
322
331
  }
323
- return fetchWorkerFilesystemRoute(filesystemRequest, requestPathname, phase, (assetRequest) => Promise.resolve(assets.fetch(assetRequest)), publicFiles, basePath, assetPathPrefix, hadBasePath);
332
+ return fetchWorkerFilesystemRoute(filesystemRequest, requestPathname, phase, (assetRequest) => Promise.resolve(assets.fetch(assetRequest)), publicFiles, basePath, assetPathPrefix, resolvedPathnameHasBasePath);
324
333
  }
325
334
  };
326
335
  const resolvePublicImageSource = async (sourceRequest, sourceAssets) => {
@@ -333,6 +342,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
333
342
  const sourceResult = await runPagesRequest(attachRequestCfMetadata(new Request(new URL(sourcePathname + sourceUrl.search, sourceUrl), { signal: sourceRequest.signal }), sourceRequest), {
334
343
  ...deps,
335
344
  hadBasePath: sourceHadBasePath,
345
+ restoreLocaleRootTrailingSlash: shouldRestoreLocaleRootTrailingSlash(sourceUrl.pathname, localeRootTrailingSlashConfig),
336
346
  isDataReq: false,
337
347
  isDataRequest: false,
338
348
  middlewareRequest: void 0,
@@ -341,9 +351,9 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
341
351
  runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, sourceHadBasePath) : null,
342
352
  renderPage: null,
343
353
  handleApi: null,
344
- serveFilesystemRoute: async (candidate, _stagedHeaders, phase, _resolvedUrl, filesystemRequest) => {
354
+ serveFilesystemRoute: async (candidate, _stagedHeaders, phase, _resolvedUrl, filesystemRequest, candidateHasBasePath) => {
345
355
  if (isImageOptimizationPath(candidate)) return false;
346
- const asset = await fetchWorkerFilesystemRoute(filesystemRequest, candidate, phase, (assetRequest) => Promise.resolve(sourceAssets.fetch(assetRequest)), publicFiles, basePath, assetPathPrefix, sourceHadBasePath);
356
+ const asset = await fetchWorkerFilesystemRoute(filesystemRequest, candidate, phase, (assetRequest) => Promise.resolve(sourceAssets.fetch(assetRequest)), publicFiles, basePath, assetPathPrefix, candidateHasBasePath);
347
357
  if (asset === false) return false;
348
358
  sourceAsset = asset;
349
359
  return new Response(null);
@@ -36,7 +36,7 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
36
36
  if (!isPagesResponseStageProps(props)) return new Response("Invalid vinext Pages response stage", { status: 400 });
37
37
  if (props.buildId !== pagesEntry.buildId) return new Response("Vinext Pages response stage deployment mismatch", { status: 409 });
38
38
  if (props.requestHost !== new URL(request.url).host) return new Response("Invalid vinext Pages response stage", { status: 400 });
39
- await pagesEntry.__ensureInstrumentation?.();
39
+ await pagesEntry.__ensureInstrumentation?.(platformCtx);
40
40
  registerConfiguredImageOptimizer(env);
41
41
  const renderHeaders = new Headers(stagedHeaders ?? props.stagedHeaders ?? []);
42
42
  renderHeaders.delete("Content-Length");
@@ -12,6 +12,7 @@ async function performOnDemandRevalidate(source, urlPath, opts = {}, trustedOrig
12
12
  if (isSourceRevalidationRequest(source)) throw new Error(`Cannot revalidate ${urlPath} from an internal revalidation request`);
13
13
  const executionContext = getRequestExecutionContext();
14
14
  const dispatchRevalidate = executionContext?.dispatchPagesRevalidate;
15
+ if (!dispatchRevalidate && !trustedOrigin) throw new Error(`Cannot revalidate ${urlPath}: no in-process dispatcher or server-owned origin is available`);
15
16
  const target = createRevalidateTarget(source, urlPath, trustedOrigin);
16
17
  const headers = { [PRERENDER_REVALIDATE_HEADER]: getRevalidateSecret() };
17
18
  if (trustedOrigin && !dispatchRevalidate) {
@@ -20,7 +20,7 @@ async function handleSingleStageRequest(request, env, platformCtx) {
20
20
  let ctx = createWorkerPrerenderDiscoveryContext(ctxWithRevalidation, request, pagesRequestStagePrerenderSecret);
21
21
  const readinessResponse = createWorkerPrerenderReadinessResponse(ctx, request);
22
22
  if (readinessResponse) {
23
- if (readinessResponse.status === 204) await Promise.all([__ensureInstrumentation(), __ensureInstrumentation$1()]);
23
+ if (readinessResponse.status === 204) await Promise.all([__ensureInstrumentation(ctx), __ensureInstrumentation$1(ctx)]);
24
24
  return await validateCdnRequest(request) ?? readinessResponse;
25
25
  }
26
26
  const isClientBuildFile = isPagesClientBuildFileRequest(request, env, ctx);
@@ -3,7 +3,7 @@ import { negotiateEncoding } from "./accept-encoding.js";
3
3
  import { StaticFileCache } from "./static-file-cache.js";
4
4
  import { resolveRequestHost, trustProxy, trustedHosts } from "./proxy-trust.js";
5
5
  import { COMPRESS_THRESHOLD, isCompressibleContentType } from "./response-compression.js";
6
- import { IncomingMessage, ServerResponse } from "node:http";
6
+ import { IncomingMessage, Server, ServerResponse } from "node:http";
7
7
  //#region src/server/prod-server.d.ts
8
8
  /**
9
9
  * Import a built server entry module (App Router RSC entry or Pages Router
@@ -127,7 +127,7 @@ declare function waitForNodeResponseCompletion(res: ServerResponse): Promise<voi
127
127
  * Pages Router (dist/server/entry.js) and configures the appropriate handler.
128
128
  */
129
129
  export declare function startProdServer(options?: ProdServerOptions): Promise<{
130
- server: import("node:http").Server<typeof IncomingMessage, typeof ServerResponse>;
130
+ server: Server<typeof IncomingMessage, typeof ServerResponse>;
131
131
  port: number;
132
132
  }>;
133
133
  type AppRouterPrerenderSeeder = (serverDir: string) => Promise<number>;