vinext 1.2.0 → 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 (283) hide show
  1. package/README.md +13 -10
  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/output-root-externals.d.ts +21 -0
  13. package/dist/build/output-root-externals.js +40 -0
  14. package/dist/build/pages-client-assets-module.js +1 -1
  15. package/dist/build/prerender-paths.js +6 -3
  16. package/dist/build/prerender.js +1 -1
  17. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  18. package/dist/build/server-actions-encryption-key.js +101 -0
  19. package/dist/build/ssr-manifest.d.ts +3 -0
  20. package/dist/build/ssr-manifest.js +10 -1
  21. package/dist/check.js +5 -6
  22. package/dist/cli-dev-config.js +3 -3
  23. package/dist/cli.js +1 -1
  24. package/dist/client/client-rewrite-params.d.ts +9 -0
  25. package/dist/client/client-rewrite-params.js +20 -0
  26. package/dist/client/dev-error-overlay.js +2 -1
  27. package/dist/client/navigation-runtime.d.ts +25 -2
  28. package/dist/client/navigation-runtime.js +42 -11
  29. package/dist/client/vinext-next-data.d.ts +0 -1
  30. package/dist/config/config-matchers.d.ts +15 -40
  31. package/dist/config/config-matchers.js +195 -262
  32. package/dist/config/config-source.d.ts +34 -0
  33. package/dist/config/config-source.js +141 -0
  34. package/dist/config/header-params.d.ts +29 -0
  35. package/dist/config/header-params.js +106 -0
  36. package/dist/config/next-config.d.ts +7 -5
  37. package/dist/config/next-config.js +120 -7
  38. package/dist/entries/app-browser-entry.d.ts +14 -1
  39. package/dist/entries/app-browser-entry.js +26 -36
  40. package/dist/entries/app-rsc-entry.d.ts +2 -0
  41. package/dist/entries/app-rsc-entry.js +92 -57
  42. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  43. package/dist/entries/app-rsc-manifest.js +20 -1
  44. package/dist/entries/app-ssr-entry.d.ts +4 -1
  45. package/dist/entries/app-ssr-entry.js +9 -2
  46. package/dist/entries/pages-client-entry.d.ts +1 -0
  47. package/dist/entries/pages-client-entry.js +6 -6
  48. package/dist/entries/pages-server-entry.js +17 -14
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.js +350 -175
  51. package/dist/init.d.ts +1 -1
  52. package/dist/init.js +103 -6
  53. package/dist/plugins/ast-utils.d.ts +53 -2
  54. package/dist/plugins/ast-utils.js +90 -2
  55. package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
  56. package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
  57. package/dist/plugins/commonjs-esm-facade.js +2 -2
  58. package/dist/plugins/css-module-imports.js +13 -20
  59. package/dist/plugins/dynamic-preload-metadata.js +2 -3
  60. package/dist/plugins/extensionless-dynamic-import.js +2 -3
  61. package/dist/plugins/fonts.d.ts +1 -1
  62. package/dist/plugins/fonts.js +3 -3
  63. package/dist/plugins/ignore-dynamic-requests.js +2 -3
  64. package/dist/plugins/import-meta-url.js +3 -4
  65. package/dist/plugins/instrumentation-client.js +3 -2
  66. package/dist/plugins/middleware-export-validation.js +2 -3
  67. package/dist/plugins/og-harfbuzz.js +2 -3
  68. package/dist/plugins/optimize-imports.d.ts +25 -2
  69. package/dist/plugins/optimize-imports.js +109 -24
  70. package/dist/plugins/pages-node-externals.js +2 -3
  71. package/dist/plugins/remove-console.js +2 -18
  72. package/dist/plugins/require-condition-resolution.js +3 -3
  73. package/dist/plugins/require-context.js +2 -3
  74. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  75. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  76. package/dist/plugins/strip-server-exports.js +3 -4
  77. package/dist/plugins/styled-jsx.js +2 -3
  78. package/dist/plugins/use-cache-callable.d.ts +26 -2
  79. package/dist/plugins/use-cache-callable.js +101 -36
  80. package/dist/plugins/worker-image-imports.d.ts +1 -0
  81. package/dist/plugins/worker-image-imports.js +31 -34
  82. package/dist/plugins/worker-use-server.js +38 -14
  83. package/dist/routing/app-route-graph.d.ts +1 -1
  84. package/dist/routing/browser-route-manifest.d.ts +43 -0
  85. package/dist/routing/browser-route-manifest.js +195 -0
  86. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  87. package/dist/routing/hashed-route-patterns.js +22 -0
  88. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  89. package/dist/routing/optimistic-route-trie.js +102 -0
  90. package/dist/routing/route-validation.d.ts +6 -1
  91. package/dist/routing/route-validation.js +26 -10
  92. package/dist/server/api-handler.js +1 -1
  93. package/dist/server/app-action-forwarding.d.ts +8 -0
  94. package/dist/server/app-action-forwarding.js +17 -3
  95. package/dist/server/app-browser-entry.js +149 -62
  96. package/dist/server/app-browser-error.d.ts +3 -1
  97. package/dist/server/app-browser-error.js +7 -2
  98. package/dist/server/app-browser-interception-context.d.ts +2 -2
  99. package/dist/server/app-browser-interception-context.js +1 -1
  100. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  101. package/dist/server/app-browser-mpa-navigation.js +6 -5
  102. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  103. package/dist/server/app-browser-navigation-controller.js +88 -26
  104. package/dist/server/app-browser-prefetch-response.js +2 -2
  105. package/dist/server/app-browser-state.d.ts +2 -2
  106. package/dist/server/app-browser-state.js +1 -1
  107. package/dist/server/app-browser-supplemental-refresh.js +1 -1
  108. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  109. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  110. package/dist/server/app-client-reference-preloader.js +30 -7
  111. package/dist/server/app-fallback-renderer.js +2 -1
  112. package/dist/server/app-middleware.d.ts +6 -0
  113. package/dist/server/app-middleware.js +8 -10
  114. package/dist/server/app-optimistic-routing.d.ts +8 -10
  115. package/dist/server/app-optimistic-routing.js +4 -95
  116. package/dist/server/app-page-boundary-render.js +8 -1
  117. package/dist/server/app-page-cache-render.js +1 -0
  118. package/dist/server/app-page-dispatch.js +3 -1
  119. package/dist/server/app-page-render.js +4 -2
  120. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  121. package/dist/server/app-page-rsc-render-status.js +1 -0
  122. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  123. package/dist/server/app-page-search-params-observation.js +8 -10
  124. package/dist/server/app-page-stream.d.ts +7 -0
  125. package/dist/server/app-page-stream.js +1 -0
  126. package/dist/server/app-pages-bridge.d.ts +2 -1
  127. package/dist/server/app-pages-bridge.js +12 -8
  128. package/dist/server/app-prerender-endpoints.js +1 -1
  129. package/dist/server/app-prerender-static-params.js +3 -2
  130. package/dist/server/app-render-abort-error.d.ts +19 -0
  131. package/dist/server/app-render-abort-error.js +31 -1
  132. package/dist/server/app-render-dependency.js +42 -2
  133. package/dist/server/app-request-stage-independent-entry.js +7 -7
  134. package/dist/server/app-response-stage-entry.js +5 -5
  135. package/dist/server/app-route-handler-dispatch.js +3 -1
  136. package/dist/server/app-route-handler-execution.d.ts +2 -0
  137. package/dist/server/app-route-handler-execution.js +9 -2
  138. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  139. package/dist/server/app-route-handler-middleware-context.js +3 -3
  140. package/dist/server/app-route-handler-response.d.ts +2 -1
  141. package/dist/server/app-route-handler-response.js +2 -2
  142. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  143. package/dist/server/app-route-handler-runtime.js +21 -4
  144. package/dist/server/app-route-module-loader.js +7 -6
  145. package/dist/server/app-route-tree.d.ts +20 -0
  146. package/dist/server/app-route-tree.js +18 -0
  147. package/dist/server/app-router-entry.js +7 -7
  148. package/dist/server/app-rsc-cache-busting.d.ts +16 -0
  149. package/dist/server/app-rsc-cache-busting.js +29 -12
  150. package/dist/server/app-rsc-combined-handler.js +8 -1
  151. package/dist/server/app-rsc-errors.d.ts +7 -0
  152. package/dist/server/app-rsc-errors.js +9 -2
  153. package/dist/server/app-rsc-handler.d.ts +4 -1
  154. package/dist/server/app-rsc-handler.js +151 -135
  155. package/dist/server/app-rsc-request-normalization.js +3 -3
  156. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  157. package/dist/server/app-rsc-response-finalizer.js +4 -1
  158. package/dist/server/app-rsc-response-stage.js +5 -3
  159. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  160. package/dist/server/app-rsc-route-matching.js +1 -1
  161. package/dist/server/app-server-action-execution.d.ts +23 -6
  162. package/dist/server/app-server-action-execution.js +51 -57
  163. package/dist/server/app-ssr-entry.d.ts +6 -0
  164. package/dist/server/app-ssr-entry.js +21 -11
  165. package/dist/server/app-ssr-stream.d.ts +7 -0
  166. package/dist/server/app-ssr-stream.js +13 -1
  167. package/dist/server/app-visited-response-cache.js +2 -2
  168. package/dist/server/config-headers.js +13 -4
  169. package/dist/server/defer-until-stream-consumed.d.ts +2 -1
  170. package/dist/server/defer-until-stream-consumed.js +3 -1
  171. package/dist/server/dev-server.js +1 -1
  172. package/dist/server/image-optimization.js +1 -0
  173. package/dist/server/isolate-shared-promise.d.ts +10 -0
  174. package/dist/server/isolate-shared-promise.js +33 -0
  175. package/dist/server/isr-cache.js +3 -2
  176. package/dist/server/metadata-route-response.js +2 -2
  177. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  178. package/dist/server/middleware-matcher-pattern.js +11 -140
  179. package/dist/server/middleware-matcher.js +5 -6
  180. package/dist/server/middleware-response-headers.d.ts +31 -0
  181. package/dist/server/middleware-response-headers.js +57 -1
  182. package/dist/server/middleware-runtime.js +30 -17
  183. package/dist/server/navigation-planner.d.ts +2 -2
  184. package/dist/server/navigation-planner.js +1 -1
  185. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  186. package/dist/server/nitro-public-files-plugin.js +106 -0
  187. package/dist/server/nitro-public-files.d.ts +21 -0
  188. package/dist/server/nitro-public-files.js +39 -0
  189. package/dist/server/open-redirect.d.ts +11 -4
  190. package/dist/server/open-redirect.js +11 -4
  191. package/dist/server/pages-api-route.js +2 -2
  192. package/dist/server/pages-asset-tags.d.ts +5 -0
  193. package/dist/server/pages-asset-tags.js +9 -2
  194. package/dist/server/pages-client-assets.d.ts +4 -1
  195. package/dist/server/pages-data-route.js +2 -1
  196. package/dist/server/pages-i18n.d.ts +18 -0
  197. package/dist/server/pages-i18n.js +18 -2
  198. package/dist/server/pages-node-compat.d.ts +5 -3
  199. package/dist/server/pages-node-compat.js +35 -16
  200. package/dist/server/pages-page-data.js +1 -1
  201. package/dist/server/pages-page-handler.js +1 -1
  202. package/dist/server/pages-page-response.js +1 -1
  203. package/dist/server/pages-request-pipeline.d.ts +6 -1
  204. package/dist/server/pages-request-pipeline.js +35 -39
  205. package/dist/server/pages-request-stage-entry.js +20 -10
  206. package/dist/server/pages-response-stage-entry.js +1 -1
  207. package/dist/server/pages-revalidate.js +3 -2
  208. package/dist/server/pages-router-entry.js +2 -2
  209. package/dist/server/prod-server.d.ts +2 -2
  210. package/dist/server/prod-server.js +74 -36
  211. package/dist/server/proxy-trust.d.ts +6 -0
  212. package/dist/server/proxy-trust.js +12 -6
  213. package/dist/server/request-pipeline.d.ts +5 -0
  214. package/dist/server/request-pipeline.js +12 -1
  215. package/dist/server/rsc-stream-hints.d.ts +1 -1
  216. package/dist/server/rsc-stream-hints.js +21 -3
  217. package/dist/server/server-reference-loader.js +10 -1
  218. package/dist/server/static-file-cache.js +15 -3
  219. package/dist/server/worker-image-optimization.js +19 -6
  220. package/dist/server/worker-utils.js +1 -1
  221. package/dist/shims/cache-handler.js +3 -2
  222. package/dist/shims/cache-request-state.d.ts +40 -3
  223. package/dist/shims/cache-request-state.js +70 -5
  224. package/dist/shims/cache-runtime.js +47 -19
  225. package/dist/shims/cache.d.ts +2 -2
  226. package/dist/shims/cache.js +17 -8
  227. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  228. package/dist/shims/cdn-purge-routes.js +77 -0
  229. package/dist/shims/dynamic.js +17 -4
  230. package/dist/shims/form.js +8 -3
  231. package/dist/shims/head.js +1 -1
  232. package/dist/shims/headers.js +2 -2
  233. package/dist/shims/image-props.d.ts +93 -0
  234. package/dist/shims/image-props.js +323 -0
  235. package/dist/shims/image.d.ts +4 -18
  236. package/dist/shims/image.js +4 -319
  237. package/dist/shims/internal/headers-state.d.ts +7 -0
  238. package/dist/shims/internal/headers-state.js +14 -2
  239. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  240. package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
  241. package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
  242. package/dist/shims/link-prefetch.js +5 -4
  243. package/dist/shims/link.js +7 -5
  244. package/dist/shims/navigation.d.ts +1 -1
  245. package/dist/shims/navigation.js +21 -10
  246. package/dist/shims/og.js +35 -10
  247. package/dist/shims/request-context.d.ts +13 -0
  248. package/dist/shims/router.js +28 -52
  249. package/dist/shims/server.d.ts +42 -8
  250. package/dist/shims/server.js +99 -15
  251. package/dist/shims/thenable-params.d.ts +6 -1
  252. package/dist/shims/thenable-params.js +11 -2
  253. package/dist/shims/unified-request-context.d.ts +5 -0
  254. package/dist/shims/unified-request-context.js +2 -0
  255. package/dist/shims/url-utils.d.ts +7 -0
  256. package/dist/shims/url-utils.js +12 -3
  257. package/dist/utils/asset-prefix.d.ts +7 -0
  258. package/dist/utils/asset-prefix.js +10 -1
  259. package/dist/utils/client-build-manifest.js +12 -5
  260. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  261. package/dist/utils/client-runtime-metadata.js +15 -2
  262. package/dist/utils/domain-locale.js +1 -1
  263. package/dist/utils/lazy-chunks.d.ts +4 -0
  264. package/dist/utils/manifest-paths.d.ts +14 -0
  265. package/dist/utils/manifest-paths.js +22 -1
  266. package/dist/utils/path-to-regexp.d.ts +21 -0
  267. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  268. package/dist/utils/plugin-react-version.d.ts +15 -0
  269. package/dist/utils/plugin-react-version.js +64 -0
  270. package/dist/utils/plugin-rsc-version.d.ts +2 -0
  271. package/dist/utils/plugin-rsc-version.js +28 -2
  272. package/dist/utils/public-routes.d.ts +2 -0
  273. package/dist/utils/public-routes.js +18 -7
  274. package/dist/utils/react-version.d.ts +7 -0
  275. package/dist/utils/react-version.js +39 -16
  276. package/package.json +6 -6
  277. package/dist/build/nitro-route-rules.d.ts +0 -47
  278. package/dist/build/nitro-route-rules.js +0 -79
  279. package/dist/plugins/cache-flight-codec.d.ts +0 -19
  280. package/dist/plugins/cache-flight-codec.js +0 -68
  281. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  282. package/dist/utils/regex-safety.d.ts +0 -17
  283. package/dist/utils/regex-safety.js +0 -789
@@ -3,10 +3,11 @@ import { MIDDLEWARE_SET_COOKIE_HEADER } from "../utils/protocol-headers.js";
3
3
  import { encodeMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
4
4
  import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
5
5
  import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
6
- import { getRequestExecutionContext } from "./request-context.js";
7
6
  import { MIDDLEWARE_NEXT_HEADER, MIDDLEWARE_REWRITE_HEADER } from "../server/headers.js";
7
+ import { getRequestExecutionContext } from "./request-context.js";
8
8
  import { validateCookieAttributeValue, validateCookieName } from "./internal/cookie-serialize.js";
9
9
  import { assertSafeNavigationUrl } from "./url-safety.js";
10
+ import { trustProxy } from "../server/proxy-trust.js";
10
11
  import { userAgent, userAgentFromString } from "./user-agent.js";
11
12
  //#region src/shims/server.ts
12
13
  /**
@@ -97,13 +98,26 @@ function initWithoutInputBody(input, init) {
97
98
  body: null
98
99
  };
99
100
  }
101
+ /**
102
+ * workerd's `request.cf` metadata. Only the Workers runtime sets it, so its
103
+ * presence means the request came through Cloudflare's edge rather than
104
+ * straight from a client.
105
+ */
106
+ function readCloudflareMetadata(request) {
107
+ const cf = Reflect.get(request, "cf");
108
+ return cf !== null && typeof cf === "object" ? cf : void 0;
109
+ }
110
+ function readStringField(source, key) {
111
+ const value = Reflect.get(source, key);
112
+ return typeof value === "string" && value !== "" ? value : void 0;
113
+ }
100
114
  var NextRequest = class extends Request {
101
115
  _nextUrl;
102
116
  _url;
103
117
  _cookies;
104
118
  constructor(input, init) {
105
119
  validateURL(typeof input !== "string" && "url" in input ? input.url : String(input));
106
- const { nextConfig: _nextConfig, ...plainInit } = init ?? {};
120
+ const { nextConfig: _nextConfig, requestHost, ...plainInit } = init ?? {};
107
121
  const requestInit = init instanceof Request ? requestInitFromRequest(init) : plainInit;
108
122
  if (input instanceof Request) {
109
123
  super(input, initWithoutInputBody(input, requestInit));
@@ -129,6 +143,7 @@ var NextRequest = class extends Request {
129
143
  } : void 0;
130
144
  const urlConfig = _nextConfig ? {
131
145
  basePath: _nextConfig.basePath,
146
+ headers: requestHost === void 0 ? void 0 : { host: requestHost },
132
147
  nextConfig: {
133
148
  i18n,
134
149
  trailingSlash: _nextConfig.trailingSlash,
@@ -155,17 +170,39 @@ var NextRequest = class extends Request {
155
170
  throw new Error("NextRequest.ua has been removed; use userAgent() instead");
156
171
  }
157
172
  /**
158
- * Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header
159
- * over the spoofable X-Forwarded-For. Returns undefined if unavailable.
173
+ * Client IP address. Next.js removed `ip` in v15; vinext keeps it as an
174
+ * extension. Returns undefined unless the value comes from a trusted source.
175
+ *
176
+ * On Cloudflare Workers (the request carries `cf` metadata), Cloudflare's
177
+ * edge sets `CF-Connecting-IP`. Elsewhere these headers are client-supplied
178
+ * and are only honored behind a trusted proxy (`VINEXT_TRUST_PROXY` /
179
+ * `VINEXT_TRUSTED_HOSTS`), matching the `X-Forwarded-*` policy.
160
180
  */
161
181
  get ip() {
182
+ if (readCloudflareMetadata(this)) return this.headers.get("cf-connecting-ip") ?? void 0;
183
+ if (!trustProxy) return void 0;
162
184
  return this.headers.get("cf-connecting-ip") ?? this.headers.get("x-real-ip") ?? this.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? void 0;
163
185
  }
164
186
  /**
165
- * Geolocation data. Platform-dependent (e.g., Cloudflare, Vercel).
166
- * Returns undefined if not available.
187
+ * Geolocation data. Next.js removed `geo` in v15; vinext keeps it as an
188
+ * extension. Read from Cloudflare's `request.cf` metadata on Workers, or
189
+ * from platform geo headers behind a trusted proxy. Returns undefined
190
+ * otherwise, because any client can send these headers.
167
191
  */
168
192
  get geo() {
193
+ const cf = readCloudflareMetadata(this);
194
+ if (cf) {
195
+ const country = readStringField(cf, "country");
196
+ if (!country) return void 0;
197
+ return {
198
+ country,
199
+ city: readStringField(cf, "city"),
200
+ region: readStringField(cf, "region"),
201
+ latitude: readStringField(cf, "latitude"),
202
+ longitude: readStringField(cf, "longitude")
203
+ };
204
+ }
205
+ if (!trustProxy) return void 0;
169
206
  const country = this.headers.get("cf-ipcountry") ?? this.headers.get("x-vercel-ip-country") ?? void 0;
170
207
  if (!country) return void 0;
171
208
  return {
@@ -257,6 +294,9 @@ var NextResponse = class NextResponse extends Response {
257
294
  });
258
295
  }
259
296
  };
297
+ function isRawDataPathname(pathname) {
298
+ return pathname.startsWith("/_next/data/") && pathname.endsWith(".json");
299
+ }
260
300
  var NextURL = class NextURL {
261
301
  /** Internal URL stores the pathname WITHOUT basePath or locale prefix. */
262
302
  _url;
@@ -276,8 +316,15 @@ var NextURL = class NextURL {
276
316
  _locales;
277
317
  _domains;
278
318
  _domainLocale;
319
+ _headers;
320
+ _buildId;
321
+ /** First page segment of a raw data pathname, where its locale sits. */
322
+ _dataPathSegment;
323
+ /** The locale parsed from that segment, if it is one. */
324
+ _dataPathLocale;
279
325
  constructor(input, base, config) {
280
326
  this._url = new URL(input.toString(), base);
327
+ this._headers = config?.headers;
281
328
  this._configBasePath = config?.basePath ?? "";
282
329
  this._basePath = this._configBasePath;
283
330
  this._configTrailingSlash = config?.nextConfig?.trailingSlash ?? false;
@@ -285,6 +332,7 @@ var NextURL = class NextURL {
285
332
  this._trailingSlash = this._configTrailingSlash;
286
333
  this._analyzeTrailingSlash();
287
334
  this._stripBasePath();
335
+ this._parseBuildId();
288
336
  const i18n = config?.nextConfig?.i18n;
289
337
  if (i18n) {
290
338
  this._locales = [...i18n.locales];
@@ -325,6 +373,22 @@ var NextURL = class NextURL {
325
373
  this._basePath = this._configBasePath;
326
374
  this._url.pathname = stripBasePath(this._url.pathname, this._configBasePath);
327
375
  }
376
+ /**
377
+ * Take the build ID from a raw `/_next/data/<buildId>/….json` pathname, as
378
+ * getNextPathnameInfo does. Middleware only sees one when proxy URL
379
+ * normalization is skipped; the pathname is left as is.
380
+ */
381
+ _parseBuildId() {
382
+ const { pathname } = this._url;
383
+ if (!isRawDataPathname(pathname)) {
384
+ this._buildId = void 0;
385
+ this._dataPathSegment = void 0;
386
+ return;
387
+ }
388
+ const [buildId, pageSegment] = pathname.slice(12, -5).split("/");
389
+ this._buildId = buildId;
390
+ this._dataPathSegment = pageSegment === "index" ? void 0 : pageSegment;
391
+ }
328
392
  /** Extract locale from pathname, stripping it from the internal URL. */
329
393
  _detectPathnameLocale(locales) {
330
394
  const segments = this._url.pathname.split("/");
@@ -336,11 +400,29 @@ var NextURL = class NextURL {
336
400
  _analyzeI18n() {
337
401
  if (!this._locales || !this._configDefaultLocale) return;
338
402
  const detectedLocale = this._detectPathnameLocale(this._locales);
403
+ this._dataPathLocale = void 0;
404
+ if (!detectedLocale && this._buildId && this._dataPathSegment) {
405
+ const candidate = this._dataPathSegment.toLowerCase();
406
+ this._dataPathLocale = this._locales.find((l) => l.toLowerCase() === candidate);
407
+ }
339
408
  const detectedLocaleLower = detectedLocale?.toLowerCase();
340
- const hostname = this._url.hostname.toLowerCase();
409
+ const hostHeader = this._headers?.host;
410
+ const hostname = (typeof hostHeader === "string" && hostHeader ? hostHeader.split(":", 1)[0] : this._url.hostname).toLowerCase();
341
411
  this._domainLocale = this._domains?.find((domain) => domain.domain.split(":", 1)[0].toLowerCase() === hostname || detectedLocaleLower === domain.defaultLocale.toLowerCase() || domain.locales?.some((locale) => locale.toLowerCase() === detectedLocaleLower));
342
412
  this._defaultLocale = this._domainLocale?.defaultLocale ?? this._configDefaultLocale;
343
- this._locale = detectedLocale ?? this._defaultLocale;
413
+ this._locale = detectedLocale ?? this._dataPathLocale ?? this._defaultLocale;
414
+ }
415
+ /**
416
+ * A raw data pathname keeps its locale segment, replaced by the current
417
+ * locale once it has been changed.
418
+ */
419
+ _formatDataPathLocale(pathname) {
420
+ if (!this._dataPathLocale || this._locale === this._dataPathLocale) return pathname;
421
+ if (!this._locale || !isRawDataPathname(pathname)) return pathname;
422
+ const segments = pathname.slice(12, -5).split("/");
423
+ if (segments[1]?.toLowerCase() !== this._dataPathLocale.toLowerCase()) return pathname;
424
+ segments[1] = this._locale;
425
+ return "/_next/data/" + segments.join("/") + ".json";
344
426
  }
345
427
  /**
346
428
  * Reconstruct the full pathname with basePath + locale prefix and apply
@@ -349,9 +431,9 @@ var NextURL = class NextURL {
349
431
  */
350
432
  _formatPathname() {
351
433
  let prefix = this._basePath;
352
- const inner = this._url.pathname;
434
+ const inner = this._formatDataPathLocale(this._url.pathname);
353
435
  const innerLower = inner.toLowerCase();
354
- if (!(innerLower === "/api" || innerLower.startsWith("/api/")) && this._locale && this._locale !== this._defaultLocale) prefix += "/" + this._locale;
436
+ if (!(innerLower === "/api" || innerLower.startsWith("/api/")) && !isRawDataPathname(inner) && this._locale && this._locale !== this._defaultLocale) prefix += "/" + this._locale;
355
437
  const composed = !prefix ? inner : inner === "/" ? prefix : prefix + inner;
356
438
  return this._applyTrailingSlash(composed);
357
439
  }
@@ -379,6 +461,7 @@ var NextURL = class NextURL {
379
461
  this._url.href = value;
380
462
  this._analyzeTrailingSlash();
381
463
  this._stripBasePath();
464
+ this._parseBuildId();
382
465
  this._analyzeI18n();
383
466
  }
384
467
  get origin() {
@@ -490,6 +573,7 @@ var NextURL = class NextURL {
490
573
  } else if (this._trailingSlash) nextConfig.trailingSlash = true;
491
574
  const config = {
492
575
  basePath: this._configBasePath,
576
+ headers: this._headers,
493
577
  nextConfig: Object.keys(nextConfig).length > 0 ? nextConfig : void 0
494
578
  };
495
579
  return new NextURL(this.href, void 0, config);
@@ -501,13 +585,13 @@ var NextURL = class NextURL {
501
585
  return this.href;
502
586
  }
503
587
  /**
504
- * The build ID of the Next.js application.
505
- * Set from `generateBuildId` in next.config.js, or a random UUID if not configured.
506
- * Can be used in middleware to detect deployment skew between client and server.
507
- * Matches the Next.js API: `request.nextUrl.buildId`.
588
+ * Matches the Next.js API: `request.nextUrl.buildId`. Next.js derives it
589
+ * from the URL (only `/_next/data/<buildId>/…` paths carry one) and never
590
+ * from the deployment, so a Client Component reads the same value on the
591
+ * server and in the browser.
508
592
  */
509
593
  get buildId() {
510
- return process.env.__VINEXT_BUILD_ID ?? void 0;
594
+ return this._buildId;
511
595
  }
512
596
  };
513
597
  var RequestCookies = class {
@@ -3,7 +3,12 @@ import { WellKnownProperty } from "./internal/thenable-well-known-properties.js"
3
3
  export type ThenableParams<T extends Record<string, unknown>> = Promise<T> & Omit<T, WellKnownProperty>;
4
4
  export type ThenableParamsObserver = Readonly<{
5
5
  observeParamAccess: (keys: readonly string[]) => void;
6
- observeReactPromiseStatus?: boolean;
6
+ /**
7
+ * Runs when `then` is read, and when `catch` or `finally` is called (they
8
+ * read `then` on a native promise). Throwing here fails the read itself
9
+ * before React counts any pending work, as Next.js does.
10
+ */
11
+ observeThenRead?: () => void;
7
12
  }>;
8
13
  /** Serialize backing values without reading a framework fallback-key proxy. */
9
14
  export declare function getFallbackParamsSnapshot(value: unknown): Promise<Record<string, unknown>> | undefined;
@@ -117,14 +117,20 @@ function createThenableParams(obj, observer, fallbackShellState) {
117
117
  const params = createThenableParamsProxy(promise, {
118
118
  get(target, prop, receiver) {
119
119
  if (isPromiseContinuation(prop)) {
120
+ if (prop === "then") observer?.observeThenRead?.();
120
121
  const value = Reflect.get(target, prop, receiver);
121
122
  if (typeof value !== "function") return value;
122
123
  return (...args) => {
123
- if (!fallbackParamNames) observeAllParamKeys(observer, plain);
124
+ if (prop !== "then") observer?.observeThenRead?.();
125
+ if (!fallbackParamNames) try {
126
+ observeAllParamKeys(observer, plain);
127
+ } catch (error) {
128
+ return Reflect.apply(value, Promise.reject(error), args);
129
+ }
124
130
  return Reflect.apply(value, target, args);
125
131
  };
126
132
  }
127
- if (prop === "status" && observer?.observeReactPromiseStatus === true) observeAllParamKeys(observer, plain);
133
+ if (prop === "reason" && Object.hasOwn(target, prop)) return Reflect.get(target, prop);
128
134
  if (typeof prop === "string" && !isWellKnownProperty(prop)) observeParamKeys(observer, [prop]);
129
135
  if (!isWellKnownProperty(prop) && hasParamProperty(plain, prop)) {
130
136
  if (isFallbackParam(prop)) {
@@ -164,6 +170,9 @@ function createThenableParams(obj, observer, fallbackShellState) {
164
170
  ownKeys() {
165
171
  observeReadableParamKeys(observer, plain);
166
172
  return Reflect.ownKeys(plain).filter((prop) => !isWellKnownProperty(prop));
173
+ },
174
+ set(target, prop, value) {
175
+ return Reflect.set(target, prop, value);
167
176
  }
168
177
  });
169
178
  paramsState.set(params, {
@@ -21,6 +21,11 @@ import "./request-state-types.js";
21
21
  export type UnifiedRequestContext = {
22
22
  /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */
23
23
  executionContext: ExecutionContextLike | null;
24
+ /**
25
+ * The host's client-connection signal for the incoming request, before any
26
+ * clone follows it. Null for requests vinext creates itself (regeneration).
27
+ */
28
+ requestSignal: AbortSignal | null;
24
29
  /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */
25
30
  requestCache: WeakMap<(...args: any[]) => any, unknown>;
26
31
  /** Shared lifecycle state for work deferred until the response closes. */
@@ -18,6 +18,7 @@ function createRequestContext(opts) {
18
18
  headersContext: null,
19
19
  actionRevalidationKind: 0,
20
20
  cacheLifeSink: null,
21
+ pendingCdnTagInvalidations: [],
21
22
  pendingRevalidatedTags: /* @__PURE__ */ new Set(),
22
23
  pendingRevalidations: /* @__PURE__ */ new Set(),
23
24
  dynamicUsageDetected: false,
@@ -50,6 +51,7 @@ function createRequestContext(opts) {
50
51
  currentFetchDedupeEntries: /* @__PURE__ */ new Map(),
51
52
  nextFetchId: 1,
52
53
  executionContext: _getInheritedExecutionContext(),
54
+ requestSignal: null,
53
55
  requestCache: /* @__PURE__ */ new WeakMap(),
54
56
  afterContext: {
55
57
  callbacks: [],
@@ -2,6 +2,13 @@
2
2
  export declare function isAbsoluteUrl(url: string): boolean;
3
3
  export declare function isAbsoluteOrProtocolRelativeUrl(url: string): boolean;
4
4
  export declare function getWindowOrigin(): string | null;
5
+ /**
6
+ * A same-origin pathname can start with "//" (e.g. `https://app.com//evil.com`),
7
+ * and as a local path that is a protocol-relative reference to another host.
8
+ * Collapse the leading slashes: Next.js does the same for these URLs, on the
9
+ * client (`resolveHref`) or with its server's repeated-slash 308.
10
+ */
11
+ export declare function collapseLeadingSlashes(pathname: string): string;
5
12
  /**
6
13
  * If `url` is an absolute same-origin URL, return the local path
7
14
  * (pathname + search + hash). Returns null for truly external URLs
@@ -25,6 +25,15 @@ function getWindowOrigin() {
25
25
  }
26
26
  }
27
27
  /**
28
+ * A same-origin pathname can start with "//" (e.g. `https://app.com//evil.com`),
29
+ * and as a local path that is a protocol-relative reference to another host.
30
+ * Collapse the leading slashes: Next.js does the same for these URLs, on the
31
+ * client (`resolveHref`) or with its server's repeated-slash 308.
32
+ */
33
+ function collapseLeadingSlashes(pathname) {
34
+ return pathname.replace(/^\/{2,}/, "/");
35
+ }
36
+ /**
28
37
  * If `url` is an absolute same-origin URL, return the local path
29
38
  * (pathname + search + hash). Returns null for truly external URLs
30
39
  * or on the server (where origin is unknown).
@@ -34,7 +43,7 @@ function toSameOriginPath(url) {
34
43
  if (!origin) return null;
35
44
  try {
36
45
  const parsed = url.startsWith("//") ? new URL(url, origin) : new URL(url);
37
- if (parsed.origin === origin) return parsed.pathname + parsed.search + parsed.hash;
46
+ if (parsed.origin === origin) return collapseLeadingSlashes(parsed.pathname) + parsed.search + parsed.hash;
38
47
  } catch {}
39
48
  return null;
40
49
  }
@@ -49,7 +58,7 @@ function toSameOriginAppPath(url, basePath) {
49
58
  try {
50
59
  const parsed = new URL(localPath, "http://vinext.local");
51
60
  if (!hasBasePath(parsed.pathname, basePath)) return null;
52
- return stripBasePath(parsed.pathname, basePath) + parsed.search + parsed.hash;
61
+ return collapseLeadingSlashes(stripBasePath(parsed.pathname, basePath)) + parsed.search + parsed.hash;
53
62
  } catch {
54
63
  return localPath;
55
64
  }
@@ -164,4 +173,4 @@ function isHashOnlyBrowserUrlChange(href, currentHref, basePath = "") {
164
173
  }
165
174
  }
166
175
  //#endregion
167
- export { getWindowOrigin, isAbsoluteOrProtocolRelativeUrl, isAbsoluteUrl, isHashOnlyBrowserUrlChange, normalizePathTrailingSlash, resolveRelativeHref, toBrowserNavigationHref, toCanonicalBrowserNavigationHref, toSameOriginAppPath, toSameOriginPath, withBasePath };
176
+ export { collapseLeadingSlashes, getWindowOrigin, isAbsoluteOrProtocolRelativeUrl, isAbsoluteUrl, isHashOnlyBrowserUrlChange, normalizePathTrailingSlash, resolveRelativeHref, toBrowserNavigationHref, toCanonicalBrowserNavigationHref, toSameOriginAppPath, toSameOriginPath, withBasePath };
@@ -92,4 +92,11 @@ export declare function assetPrefixPathname(assetPrefix: string): string;
92
92
  * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-server.ts
93
93
  */
94
94
  export declare function isNextStaticPath(pathname: string, basePath: string, assetPathPrefix: string): boolean;
95
+ /**
96
+ * Whether `pathname` is a build asset under a path `assetPrefix`. Next.js adds
97
+ * a built-in beforeFiles rewrite from `${assetPrefix}/_next/:path+` into the
98
+ * basePath (`loadRewrites` in `packages/next/src/lib/load-custom-routes.ts`),
99
+ * so such a path resolves even when it lies outside the basePath.
100
+ */
101
+ export declare function isAssetPrefixBuildAsset(pathname: string, assetPathPrefix: string): boolean;
95
102
  //#endregion
@@ -118,5 +118,14 @@ function isNextStaticPath(pathname, basePath, assetPathPrefix) {
118
118
  if (assetPathPrefix && (p === assetPathPrefix || p.startsWith(assetPathPrefix + "/"))) p = p.slice(assetPathPrefix.length) || "/";
119
119
  return p.startsWith(`/${ASSET_PREFIX_URL_DIR}/`);
120
120
  }
121
+ /**
122
+ * Whether `pathname` is a build asset under a path `assetPrefix`. Next.js adds
123
+ * a built-in beforeFiles rewrite from `${assetPrefix}/_next/:path+` into the
124
+ * basePath (`loadRewrites` in `packages/next/src/lib/load-custom-routes.ts`),
125
+ * so such a path resolves even when it lies outside the basePath.
126
+ */
127
+ function isAssetPrefixBuildAsset(pathname, assetPathPrefix) {
128
+ return !!assetPathPrefix && (pathname === assetPathPrefix || pathname.startsWith(assetPathPrefix + "/")) && isNextStaticPath(pathname, "", assetPathPrefix);
129
+ }
121
130
  //#endregion
122
- export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, isNextStaticPath, resolveAssetUrlPrefix, resolveAssetsDir };
131
+ export { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, isAssetPrefixBuildAsset, isNextStaticPath, resolveAssetUrlPrefix, resolveAssetsDir };
@@ -19,6 +19,8 @@ function readClientBuildManifest(manifestPath) {
19
19
  const assets = readStringArray(entry.assets);
20
20
  manifest[key] = {
21
21
  file: entry.file,
22
+ ...typeof entry.src === "string" ? { src: entry.src } : {},
23
+ ...typeof entry.name === "string" ? { name: entry.name } : {},
22
24
  ...entry.isEntry === true ? { isEntry: true } : {},
23
25
  ...entry.isDynamicEntry === true ? { isDynamicEntry: true } : {},
24
26
  ...imports ? { imports } : {},
@@ -39,14 +41,19 @@ function findPagesClientEntryFileFromManifest(buildManifest, assetBase) {
39
41
  return findEntryFileFromManifest(buildManifest, assetBase, PAGES_CLIENT_ENTRY_MARKERS, false);
40
42
  }
41
43
  function findEntryFileFromManifest(buildManifest, assetBase, markers, fallbackToFirstEntry) {
42
- const entries = Object.values(buildManifest).filter((entry) => entry.isEntry && entry.file);
43
- for (const marker of markers) {
44
- const markedEntry = entries.find((entry) => entry.file.includes(marker));
45
- if (markedEntry) return manifestFileWithBase(markedEntry.file, assetBase);
44
+ const entries = Object.entries(buildManifest).filter(([, entry]) => entry.isEntry && entry.file);
45
+ const matchers = [(marker, key, entry) => entry.name === marker || isVirtualEntryId(key, marker) || entry.src !== void 0 && isVirtualEntryId(entry.src, marker), (marker, _key, entry) => entry.file.includes(marker)];
46
+ for (const matches of matchers) for (const marker of markers) {
47
+ const markedEntry = entries.find(([key, entry]) => matches(marker, key, entry));
48
+ if (markedEntry) return manifestFileWithBase(markedEntry[1].file, assetBase);
46
49
  }
47
- const chosen = fallbackToFirstEntry ? entries[0] : void 0;
50
+ const chosen = fallbackToFirstEntry ? entries[0]?.[1] : void 0;
48
51
  return chosen ? manifestFileWithBase(chosen.file, assetBase) : void 0;
49
52
  }
53
+ function isVirtualEntryId(id, marker) {
54
+ const virtualId = `virtual:${marker}`;
55
+ return id === virtualId || id.endsWith(`/${virtualId}`);
56
+ }
50
57
  function listFilesRecursive(dir) {
51
58
  const out = [];
52
59
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
@@ -8,6 +8,7 @@ type ClientRuntimeMetadata = {
8
8
  }>;
9
9
  lazyChunks?: string[];
10
10
  dynamicPreloads?: Record<string, string[]>;
11
+ sharedChunks?: string[];
11
12
  };
12
13
  /**
13
14
  * Read the client build manifest and compute runtime metadata used by
@@ -1,10 +1,20 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { isAbsoluteAssetPrefix, resolveAssetsDir } from "./asset-prefix.js";
3
- import { manifestFileWithAssetPrefix, manifestFileWithBase } from "./manifest-paths.js";
3
+ import { isSharedClientChunkName, manifestFileWithAssetPrefix, manifestFileWithBase } from "./manifest-paths.js";
4
4
  import { findClientEntryFileFromVinextManifest, findPagesClientEntryFileFromVinextManifest, readClientEntryManifest } from "./client-entry-manifest.js";
5
5
  import { findClientEntryFile, findPagesClientEntryFile, readClientBuildManifest } from "./client-build-manifest.js";
6
6
  import { computeDynamicImportPreloads, computeLazyChunks, dynamicImportPreloadsWithBase } from "./lazy-chunks.js";
7
7
  //#region src/utils/client-runtime-metadata.ts
8
+ /**
9
+ * Shared Pages Router chunk files, keyed on Rolldown chunk names rather than
10
+ * emitted file names so user-configured `chunkFileNames` (e.g. hash-only
11
+ * patterns) keep their modulepreload/script tags.
12
+ */
13
+ function collectSharedChunkFiles(buildManifest, applyBase) {
14
+ const files = /* @__PURE__ */ new Set();
15
+ for (const chunk of Object.values(buildManifest)) if (chunk.file.endsWith(".js") && isSharedClientChunkName(chunk.name)) files.add(applyBase(chunk.file));
16
+ return files.size > 0 ? [...files] : void 0;
17
+ }
8
18
  function collectCssGraph(buildManifest, applyBase) {
9
19
  const cssGraph = {};
10
20
  for (const [key, chunk] of Object.entries(buildManifest)) {
@@ -74,7 +84,10 @@ function computeClientRuntimeMetadata(opts) {
74
84
  if (entry) metadata.clientEntryFile = entry;
75
85
  }
76
86
  if (!buildManifest) return metadata;
77
- if (opts.includeClientEntry) metadata.cssGraph = collectCssGraph(buildManifest, (file) => manifestFileWithBase(file, opts.assetBase));
87
+ if (opts.includeClientEntry) {
88
+ metadata.cssGraph = collectCssGraph(buildManifest, (file) => manifestFileWithBase(file, opts.assetBase));
89
+ metadata.sharedChunks = collectSharedChunkFiles(buildManifest, (file) => manifestFileWithBase(file, opts.assetBase));
90
+ }
78
91
  metadata.appBootstrapPreinitModules = collectAppBootstrapPreinitModules(buildManifest, clientEntryManifest?.appBrowserEntry, (file) => {
79
92
  const url = manifestFileWithAssetPrefix(file, opts.assetBase, opts.assetPrefix);
80
93
  return isAbsoluteAssetPrefix(opts.assetPrefix) ? url : "/" + url;
@@ -42,7 +42,7 @@ function getDomainLocaleUrl(url, locale, { basePath, currentHostname, domainItem
42
42
  const targetDomain = detectDomainLocale(domainItems, void 0, locale);
43
43
  if (!targetDomain) return void 0;
44
44
  const currentDomain = detectDomainLocale(domainItems, currentHostname ?? void 0);
45
- const localizedPath = addLocalePrefix(url, locale, targetDomain.defaultLocale);
45
+ const localizedPath = addLocalePrefix(/^[/?#]/.test(url) ? url : `/${url}`, locale, targetDomain.defaultLocale);
46
46
  if (currentDomain && normalizeDomainHostname(currentDomain.domain) === normalizeDomainHostname(targetDomain.domain)) return;
47
47
  return `${`http${targetDomain.http ? "" : "s"}://`}${targetDomain.domain}${prefixBasePath(localizedPath, basePath)}`;
48
48
  }
@@ -4,6 +4,10 @@
4
4
  */
5
5
  export type BuildManifestChunk = {
6
6
  file: string;
7
+ /** Source module id (or virtual id) of an entry chunk. */
8
+ src?: string;
9
+ /** Rolldown chunk name, independent of the configured output file name. */
10
+ name?: string;
7
11
  isEntry?: boolean;
8
12
  isDynamicEntry?: boolean;
9
13
  imports?: string[];
@@ -26,4 +26,18 @@ export declare function assetServingUrlFromBaseAnchored(value: string, basePath:
26
26
  * `<base>/<base>/` prefix is collapsed; a single prefix is left untouched.
27
27
  */
28
28
  export declare function collapseDuplicateBase(file: string, base: string): string;
29
+ /**
30
+ * Whether a Rolldown chunk belongs to the shared Pages Router runtime, judged
31
+ * by its exact chunk name rather than its emitted file name so user-configured
32
+ * or hash-only `chunkFileNames` keep their modulepreload/script tags.
33
+ */
34
+ export declare function isSharedClientChunkName(name: string | undefined): boolean;
35
+ /**
36
+ * Reserved `ssr-manifest.json` key listing the shared runtime chunk files.
37
+ * Consumers that pass the on-disk manifest straight to `renderPage()` (the
38
+ * legacy two-call Pages build) have no registered build metadata, and file
39
+ * names alone can't identify these chunks. The `\0` prefix keeps it from
40
+ * matching any module id.
41
+ */
42
+ export declare const SSR_MANIFEST_SHARED_CHUNKS_KEY = "\0vinext:shared-chunks";
29
43
  //#endregion
@@ -62,5 +62,26 @@ function collapseDuplicateBase(file, base) {
62
62
  const doubledPrefix = `${normalizedBase}/${normalizedBase}/`;
63
63
  return normalizedFile.startsWith(doubledPrefix) ? normalizedFile.slice(normalizedBase.length + 1) : normalizedFile;
64
64
  }
65
+ const SHARED_CHUNK_NAMES = /* @__PURE__ */ new Set([
66
+ "framework",
67
+ "vinext",
68
+ "vinext-client-entry"
69
+ ]);
70
+ /**
71
+ * Whether a Rolldown chunk belongs to the shared Pages Router runtime, judged
72
+ * by its exact chunk name rather than its emitted file name so user-configured
73
+ * or hash-only `chunkFileNames` keep their modulepreload/script tags.
74
+ */
75
+ function isSharedClientChunkName(name) {
76
+ return name !== void 0 && SHARED_CHUNK_NAMES.has(name);
77
+ }
78
+ /**
79
+ * Reserved `ssr-manifest.json` key listing the shared runtime chunk files.
80
+ * Consumers that pass the on-disk manifest straight to `renderPage()` (the
81
+ * legacy two-call Pages build) have no registered build metadata, and file
82
+ * names alone can't identify these chunks. The `\0` prefix keeps it from
83
+ * matching any module id.
84
+ */
85
+ const SSR_MANIFEST_SHARED_CHUNKS_KEY = "\0vinext:shared-chunks";
65
86
  //#endregion
66
- export { assetServingUrlFromBaseAnchored, collapseDuplicateBase, manifestFileWithAssetPrefix, manifestFileWithBase };
87
+ export { SSR_MANIFEST_SHARED_CHUNKS_KEY, assetServingUrlFromBaseAnchored, collapseDuplicateBase, isSharedClientChunkName, manifestFileWithAssetPrefix, manifestFileWithBase };
@@ -0,0 +1,21 @@
1
+ //#region src/utils/path-to-regexp.d.ts
2
+ export type PathToken = string | PathKey;
3
+ export type PathKey = {
4
+ name: string | number;
5
+ prefix: string;
6
+ suffix: string;
7
+ pattern: string;
8
+ modifier: string;
9
+ };
10
+ export type ParsePathPatternOptions = {
11
+ /** Characters a default param cannot contain. path-to-regexp defaults to `/#?`. */
12
+ delimiter?: string;
13
+ };
14
+ export declare function parsePathPattern(value: string, options?: ParsePathPatternOptions): PathToken[];
15
+ export declare function normalizePathTokens(tokens: PathToken[]): PathToken[];
16
+ /**
17
+ * path-to-regexp's `tokensToRegexp` with `strict: true`, without the closing
18
+ * `$`. Callers append the ending their Next.js matcher uses.
19
+ */
20
+ export declare function pathTokensToRegExpSource(tokens: PathToken[]): string;
21
+ //#endregion
@@ -1,4 +1,4 @@
1
- //#region src/server/middleware-path-to-regexp.ts
1
+ //#region src/utils/path-to-regexp.ts
2
2
  function lexer(value) {
3
3
  const tokens = [];
4
4
  let index = 0;
@@ -101,11 +101,12 @@ function lexer(value) {
101
101
  });
102
102
  return tokens;
103
103
  }
104
- function parseMiddlewarePath(value) {
104
+ function parsePathPattern(value, options = {}) {
105
105
  const tokens = lexer(value);
106
106
  const result = [];
107
107
  const prefixes = "./";
108
- const delimiter = "/#?";
108
+ const delimiter = options.delimiter ?? "/#?";
109
+ const delimiterClass = `[^${escapeRegex(delimiter)}]`;
109
110
  let key = 0;
110
111
  let index = 0;
111
112
  let path = "";
@@ -135,8 +136,8 @@ function parseMiddlewarePath(value) {
135
136
  const name = typeof previous === "string" ? previous : previous.name;
136
137
  throw new TypeError(`Must have text between two parameters, missing text after "${name}"`);
137
138
  }
138
- if (!previousText || containsDelimiter(previousText)) return "[^\\/#\\?]+?";
139
- return `(?:(?!${escapeRegex(previousText)})[^\\/#\\?])+?`;
139
+ if (!previousText || containsDelimiter(previousText)) return `${delimiterClass}+?`;
140
+ return `(?:(?!${escapeRegex(previousText)})${delimiterClass})+?`;
140
141
  };
141
142
  while (index < tokens.length) {
142
143
  const character = tryConsume("CHAR");
@@ -192,7 +193,7 @@ function parseMiddlewarePath(value) {
192
193
  function escapeRegex(value) {
193
194
  return value.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
194
195
  }
195
- function normalizeMiddlewarePathTokens(tokens) {
196
+ function normalizePathTokens(tokens) {
196
197
  return tokens.map((token) => {
197
198
  if (typeof token === "object" && (token.modifier === "*" || token.modifier === "+") && token.prefix === "" && token.suffix === "") return {
198
199
  ...token,
@@ -201,8 +202,11 @@ function normalizeMiddlewarePathTokens(tokens) {
201
202
  return token;
202
203
  });
203
204
  }
204
- function middlewarePathTokensToRegExp(tokens) {
205
- const delimiterRegex = `[${escapeRegex("/#?")}]`;
205
+ /**
206
+ * path-to-regexp's `tokensToRegexp` with `strict: true`, without the closing
207
+ * `$`. Callers append the ending their Next.js matcher uses.
208
+ */
209
+ function pathTokensToRegExpSource(tokens) {
206
210
  let route = "^";
207
211
  for (const token of tokens) {
208
212
  if (typeof token === "string") {
@@ -223,8 +227,7 @@ function middlewarePathTokensToRegExp(tokens) {
223
227
  }
224
228
  } else route += `(?:${prefix}${suffix})${token.modifier}`;
225
229
  }
226
- route += `${delimiterRegex}?$`;
227
- return new RegExp(route, "i");
230
+ return route;
228
231
  }
229
232
  //#endregion
230
- export { middlewarePathTokensToRegExp, normalizeMiddlewarePathTokens, parseMiddlewarePath };
233
+ export { normalizePathTokens, parsePathPattern, pathTokensToRegExpSource };
@@ -0,0 +1,15 @@
1
+ //#region src/utils/plugin-react-version.d.ts
2
+ /**
3
+ * Resolve @vitejs/plugin-react from the project, falling back to vinext's own
4
+ * install when the project has none or reaches an unsupported version.
5
+ * Returns null when it is not installed, and throws when every copy found is
6
+ * unsupported.
7
+ */
8
+ export declare function resolvePluginReactPath(projectRoot: string, fallbackFrom?: string): string | null;
9
+ /**
10
+ * The @vitejs/plugin-react upgrade vinext init must install before vinext.
11
+ * A declared copy below the floor conflicts with vinext's peer range: npm stops
12
+ * with ERESOLVE, and pnpm installs but vinext refuses to start.
13
+ */
14
+ export declare function getPluginReactUpgradeDeps(root: string): string[];
15
+ //#endregion