vinext 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/README.md +51 -30
  2. package/dist/build/inject-pregenerated-paths.d.ts +4 -0
  3. package/dist/build/inject-pregenerated-paths.js +18 -0
  4. package/dist/build/layout-classification.js +1 -1
  5. package/dist/build/nitro-route-rules.js +1 -1
  6. package/dist/build/pages-client-assets-module.d.ts +11 -0
  7. package/dist/build/pages-client-assets-module.js +27 -0
  8. package/dist/build/prerender.d.ts +2 -1
  9. package/dist/build/prerender.js +13 -6
  10. package/dist/build/report.d.ts +13 -2
  11. package/dist/build/report.js +99 -2
  12. package/dist/build/run-prerender.d.ts +7 -0
  13. package/dist/build/run-prerender.js +10 -1
  14. package/dist/build/standalone.js +2 -0
  15. package/dist/cache/cache-adapters-virtual.js +3 -3
  16. package/dist/check.js +40 -2
  17. package/dist/cli-args.d.ts +1 -2
  18. package/dist/cli-args.js +1 -1
  19. package/dist/cli-dev-config.d.ts +12 -0
  20. package/dist/cli-dev-config.js +23 -0
  21. package/dist/cli.js +111 -95
  22. package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
  23. package/dist/{server → client}/dev-error-overlay-store.js +1 -1
  24. package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
  25. package/dist/{server → client}/dev-error-overlay.js +2 -2
  26. package/dist/client/navigation-runtime.d.ts +2 -0
  27. package/dist/client/navigation-runtime.js +3 -1
  28. package/dist/client/window-next.d.ts +2 -1
  29. package/dist/cloudflare/index.d.ts +2 -2
  30. package/dist/cloudflare/index.js +2 -2
  31. package/dist/config/config-matchers.js +14 -10
  32. package/dist/config/next-config.d.ts +5 -3
  33. package/dist/config/next-config.js +44 -1
  34. package/dist/config/prerender.d.ts +34 -0
  35. package/dist/config/prerender.js +55 -0
  36. package/dist/entries/app-rsc-entry.d.ts +2 -1
  37. package/dist/entries/app-rsc-entry.js +40 -10
  38. package/dist/entries/app-rsc-manifest.js +2 -0
  39. package/dist/entries/pages-client-entry.d.ts +3 -0
  40. package/dist/entries/pages-client-entry.js +15 -1
  41. package/dist/entries/pages-server-entry.js +5 -2
  42. package/dist/image/image-adapters-virtual.d.ts +59 -0
  43. package/dist/image/image-adapters-virtual.js +59 -0
  44. package/dist/index.d.ts +33 -0
  45. package/dist/index.js +167 -100
  46. package/dist/init-cloudflare.d.ts +43 -0
  47. package/dist/init-cloudflare.js +839 -0
  48. package/dist/init-platform.d.ts +40 -0
  49. package/dist/init-platform.js +195 -0
  50. package/dist/init.d.ts +16 -38
  51. package/dist/init.js +209 -99
  52. package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
  53. package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
  54. package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
  55. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
  56. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +1 -1
  57. package/dist/packages/cloudflare/src/deploy-config.js +150 -0
  58. package/dist/packages/cloudflare/src/deploy-help.js +55 -0
  59. package/dist/packages/cloudflare/src/deploy.js +276 -0
  60. package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
  61. package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +18 -15
  62. package/dist/plugins/ast-scope.d.ts +16 -0
  63. package/dist/plugins/ast-scope.js +62 -0
  64. package/dist/plugins/ast-utils.d.ts +27 -1
  65. package/dist/plugins/ast-utils.js +32 -1
  66. package/dist/plugins/css-module-imports.d.ts +14 -0
  67. package/dist/plugins/css-module-imports.js +59 -0
  68. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  69. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  70. package/dist/plugins/ignore-dynamic-requests.js +530 -0
  71. package/dist/plugins/typeof-window.d.ts +1 -1
  72. package/dist/plugins/typeof-window.js +28 -56
  73. package/dist/routing/app-route-graph.d.ts +23 -2
  74. package/dist/routing/app-route-graph.js +126 -32
  75. package/dist/routing/file-matcher.d.ts +3 -0
  76. package/dist/routing/file-matcher.js +3 -0
  77. package/dist/routing/pages-router.js +2 -2
  78. package/dist/server/api-handler.js +9 -14
  79. package/dist/server/app-browser-action-result.d.ts +4 -1
  80. package/dist/server/app-browser-action-result.js +8 -1
  81. package/dist/server/app-browser-entry.js +161 -52
  82. package/dist/server/app-browser-interception-context.d.ts +1 -0
  83. package/dist/server/app-browser-interception-context.js +4 -2
  84. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  85. package/dist/server/app-browser-navigation-controller.js +60 -31
  86. package/dist/server/app-browser-server-action-client.d.ts +1 -1
  87. package/dist/server/app-browser-server-action-client.js +3 -4
  88. package/dist/server/app-browser-state.d.ts +11 -1
  89. package/dist/server/app-browser-state.js +25 -8
  90. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  91. package/dist/server/app-browser-visible-commit.js +43 -25
  92. package/dist/server/app-elements-wire.d.ts +9 -2
  93. package/dist/server/app-elements-wire.js +8 -1
  94. package/dist/server/app-elements.d.ts +2 -2
  95. package/dist/server/app-elements.js +4 -3
  96. package/dist/server/app-fallback-renderer.d.ts +2 -1
  97. package/dist/server/app-fallback-renderer.js +10 -6
  98. package/dist/server/app-hydration-cache-publication.d.ts +11 -0
  99. package/dist/server/app-hydration-cache-publication.js +43 -0
  100. package/dist/server/app-middleware.d.ts +4 -3
  101. package/dist/server/app-middleware.js +8 -3
  102. package/dist/server/app-optimistic-routing.js +11 -4
  103. package/dist/server/app-page-cache-finalizer.js +2 -1
  104. package/dist/server/app-page-cache-render.d.ts +1 -0
  105. package/dist/server/app-page-cache-render.js +8 -4
  106. package/dist/server/app-page-cache.d.ts +1 -0
  107. package/dist/server/app-page-cache.js +5 -2
  108. package/dist/server/app-page-dispatch.js +1 -0
  109. package/dist/server/app-page-element-builder.d.ts +2 -1
  110. package/dist/server/app-page-element-builder.js +58 -4
  111. package/dist/server/app-page-probe.js +5 -0
  112. package/dist/server/app-page-render-identity.d.ts +1 -0
  113. package/dist/server/app-page-render-identity.js +1 -1
  114. package/dist/server/app-page-render.js +18 -0
  115. package/dist/server/app-page-request.d.ts +14 -0
  116. package/dist/server/app-page-request.js +69 -4
  117. package/dist/server/app-page-route-wiring.d.ts +8 -1
  118. package/dist/server/app-page-route-wiring.js +32 -18
  119. package/dist/server/app-page-segment-state.d.ts +2 -1
  120. package/dist/server/app-page-segment-state.js +3 -1
  121. package/dist/server/app-page-stream.d.ts +5 -0
  122. package/dist/server/app-page-stream.js +3 -1
  123. package/dist/server/app-route-handler-execution.js +5 -1
  124. package/dist/server/app-route-handler-response.js +1 -0
  125. package/dist/server/app-route-handler-runtime.js +1 -1
  126. package/dist/server/app-router-entry.js +9 -2
  127. package/dist/server/app-rsc-handler.d.ts +1 -0
  128. package/dist/server/app-rsc-handler.js +62 -31
  129. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  130. package/dist/server/app-rsc-request-normalization.js +6 -3
  131. package/dist/server/app-segment-config.d.ts +11 -0
  132. package/dist/server/app-segment-config.js +62 -6
  133. package/dist/server/app-server-action-execution.d.ts +1 -0
  134. package/dist/server/app-server-action-execution.js +58 -28
  135. package/dist/server/app-ssr-entry.d.ts +3 -0
  136. package/dist/server/app-ssr-entry.js +15 -7
  137. package/dist/server/app-ssr-stream.d.ts +7 -3
  138. package/dist/server/app-ssr-stream.js +10 -6
  139. package/dist/server/app-visited-response-cache.d.ts +6 -0
  140. package/dist/server/app-visited-response-cache.js +3 -1
  141. package/dist/server/client-trace-metadata.js +26 -0
  142. package/dist/server/default-global-not-found-module.d.ts +14 -0
  143. package/dist/server/default-global-not-found-module.js +14 -0
  144. package/dist/server/dev-route-files.js +4 -0
  145. package/dist/server/dev-server.js +19 -18
  146. package/dist/server/dev-stack-sourcemap.d.ts +1 -1
  147. package/dist/server/dev-stack-sourcemap.js +1 -1
  148. package/dist/server/fetch-handler.d.ts +2 -0
  149. package/dist/server/fetch-handler.js +18 -0
  150. package/dist/server/headers.d.ts +3 -15
  151. package/dist/server/headers.js +2 -15
  152. package/dist/server/image-optimization.d.ts +51 -1
  153. package/dist/server/image-optimization.js +52 -2
  154. package/dist/server/implicit-tags.js +1 -1
  155. package/dist/server/isr-cache.d.ts +1 -1
  156. package/dist/server/isr-cache.js +2 -2
  157. package/dist/server/metadata-routes.d.ts +3 -1
  158. package/dist/server/metadata-routes.js +12 -2
  159. package/dist/server/middleware-runtime.js +6 -1
  160. package/dist/server/navigation-planner.d.ts +1 -0
  161. package/dist/server/navigation-planner.js +14 -3
  162. package/dist/server/pages-api-route.js +2 -2
  163. package/dist/server/pages-asset-tags.d.ts +4 -6
  164. package/dist/server/pages-asset-tags.js +12 -12
  165. package/dist/server/pages-client-assets.d.ts +12 -0
  166. package/dist/server/pages-client-assets.js +10 -0
  167. package/dist/server/pages-node-compat.d.ts +8 -1
  168. package/dist/server/pages-node-compat.js +32 -4
  169. package/dist/server/pages-page-data.d.ts +24 -1
  170. package/dist/server/pages-page-data.js +45 -24
  171. package/dist/server/pages-page-handler.d.ts +2 -1
  172. package/dist/server/pages-page-handler.js +19 -12
  173. package/dist/server/pages-page-response.d.ts +7 -0
  174. package/dist/server/pages-page-response.js +4 -1
  175. package/dist/server/pages-request-pipeline.d.ts +2 -0
  176. package/dist/server/pages-request-pipeline.js +25 -1
  177. package/dist/server/pages-router-entry.d.ts +30 -0
  178. package/dist/server/pages-router-entry.js +108 -0
  179. package/dist/server/prerender-manifest.d.ts +3 -1
  180. package/dist/server/prerender-route-params.js +1 -1
  181. package/dist/server/prod-server.d.ts +1 -1
  182. package/dist/server/prod-server.js +33 -20
  183. package/dist/server/request-pipeline.js +1 -0
  184. package/dist/server/seed-cache.js +4 -4
  185. package/dist/shims/app-router-scroll-state.d.ts +1 -0
  186. package/dist/shims/app-router-scroll-state.js +1 -0
  187. package/dist/shims/app-router-scroll.js +2 -1
  188. package/dist/shims/cache.js +19 -15
  189. package/dist/shims/cdn-cache.js +1 -1
  190. package/dist/shims/dynamic-preload-chunks.js +2 -1
  191. package/dist/shims/form.d.ts +3 -1
  192. package/dist/shims/form.js +37 -43
  193. package/dist/shims/headers.d.ts +7 -1
  194. package/dist/shims/headers.js +17 -3
  195. package/dist/shims/image.js +75 -14
  196. package/dist/shims/internal/app-route-detection.d.ts +2 -17
  197. package/dist/shims/internal/app-route-detection.js +4 -17
  198. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
  199. package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
  200. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -15
  201. package/dist/shims/internal/hybrid-client-route-owner.js +9 -60
  202. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +9 -5
  203. package/dist/shims/internal/pages-data-fetch-dedup.js +73 -14
  204. package/dist/shims/internal/pages-data-target.d.ts +10 -9
  205. package/dist/shims/internal/pages-data-target.js +91 -12
  206. package/dist/shims/internal/pages-router-components.d.ts +7 -0
  207. package/dist/shims/internal/pages-router-components.js +13 -0
  208. package/dist/shims/layout-segment-context.d.ts +4 -1
  209. package/dist/shims/layout-segment-context.js +18 -4
  210. package/dist/shims/link.js +55 -26
  211. package/dist/shims/navigation.d.ts +5 -1
  212. package/dist/shims/navigation.js +45 -10
  213. package/dist/shims/navigation.react-server.js +1 -1
  214. package/dist/shims/root-params.d.ts +15 -1
  215. package/dist/shims/root-params.js +21 -1
  216. package/dist/shims/router.d.ts +5 -7
  217. package/dist/shims/router.js +362 -93
  218. package/dist/shims/server.js +3 -2
  219. package/dist/shims/slot.js +3 -6
  220. package/dist/utils/client-runtime-metadata.d.ts +2 -18
  221. package/dist/utils/client-runtime-metadata.js +31 -22
  222. package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
  223. package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
  224. package/dist/utils/domain-locale.d.ts +6 -3
  225. package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
  226. package/dist/{server → utils}/middleware-request-headers.js +2 -2
  227. package/dist/utils/project.d.ts +48 -2
  228. package/dist/utils/project.js +225 -4
  229. package/dist/utils/protocol-headers.d.ts +17 -0
  230. package/dist/utils/protocol-headers.js +17 -0
  231. package/dist/utils/react-version.d.ts +4 -0
  232. package/dist/utils/react-version.js +44 -0
  233. package/package.json +47 -2
  234. package/dist/deploy.d.ts +0 -197
  235. package/dist/deploy.js +0 -1040
  236. package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
  237. /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { getDeploymentId } from "../utils/deployment-id.js";
2
3
  import { useMergedRef } from "./use-merged-ref.js";
3
4
  import { hasRemoteMatch, isPrivateIp } from "./image-config.js";
4
5
  import { forwardRef, useEffect, useLayoutEffect, useRef, useState } from "react";
@@ -54,6 +55,22 @@ const __imageDeviceSizes = (() => {
54
55
  ];
55
56
  }
56
57
  })();
58
+ const __imageSizes = (() => {
59
+ try {
60
+ return JSON.parse(process.env.__VINEXT_IMAGE_SIZES ?? "[16,32,48,64,96,128,256,384]");
61
+ } catch {
62
+ return [
63
+ 16,
64
+ 32,
65
+ 48,
66
+ 64,
67
+ 96,
68
+ 128,
69
+ 256,
70
+ 384
71
+ ];
72
+ }
73
+ })();
57
74
  /**
58
75
  * Whether dangerouslyAllowSVG is enabled in next.config.js.
59
76
  * When false (default), .svg sources auto-skip the optimization endpoint
@@ -68,6 +85,7 @@ const __dangerouslyAllowSVG = process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_SVG =
68
85
  * are blocked to mitigate SSRF risk.
69
86
  */
70
87
  const __dangerouslyAllowLocalIP = process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_LOCAL_IP === "true";
88
+ const __globallyUnoptimized = process.env.__VINEXT_IMAGE_UNOPTIMIZED === "true";
71
89
  /**
72
90
  * Validate that a remote URL is allowed by the configured remote patterns.
73
91
  * Returns true if the URL is allowed, false otherwise.
@@ -210,7 +228,33 @@ function resolveImageSource(v) {
210
228
  * These are the breakpoints used for srcSet generation.
211
229
  * Configurable via `images.deviceSizes` in next.config.js.
212
230
  */
213
- const RESPONSIVE_WIDTHS = __imageDeviceSizes;
231
+ const RESPONSIVE_WIDTHS = [...__imageDeviceSizes].sort((left, right) => left - right);
232
+ const ALL_IMAGE_WIDTHS = [...RESPONSIVE_WIDTHS, ...__imageSizes].sort((left, right) => left - right);
233
+ function extractLocalDeploymentId(src) {
234
+ let deploymentId = getDeploymentId();
235
+ if (!src.startsWith("/") || src.startsWith("//")) return {
236
+ src,
237
+ deploymentId
238
+ };
239
+ const queryIndex = src.indexOf("?");
240
+ if (queryIndex === -1) return {
241
+ src,
242
+ deploymentId
243
+ };
244
+ const params = new URLSearchParams(src.slice(queryIndex + 1));
245
+ const sourceDeploymentId = params.get("dpl");
246
+ if (!sourceDeploymentId) return {
247
+ src,
248
+ deploymentId
249
+ };
250
+ deploymentId = sourceDeploymentId;
251
+ params.delete("dpl");
252
+ const remainingQuery = params.toString();
253
+ return {
254
+ src: src.slice(0, queryIndex) + (remainingQuery ? `?${remainingQuery}` : ""),
255
+ deploymentId
256
+ };
257
+ }
214
258
  /**
215
259
  * Build a `/_next/image` optimization URL.
216
260
  *
@@ -219,7 +263,9 @@ const RESPONSIVE_WIDTHS = __imageDeviceSizes;
219
263
  * server handles it as a passthrough (serves the original file).
220
264
  */
221
265
  function imageOptimizationUrl(src, width, quality = 75) {
222
- return `/_next/image?url=${encodeURIComponent(src)}&w=${width}&q=${quality}`;
266
+ const source = extractLocalDeploymentId(src);
267
+ const deploymentQuery = source.src.startsWith("/") && source.deploymentId ? `&dpl=${source.deploymentId}` : "";
268
+ return `/_next/image?url=${encodeURIComponent(source.src)}&w=${width}&q=${quality}${deploymentQuery}`;
223
269
  }
224
270
  function preloadImageResource(input) {
225
271
  if (!input.shouldPreload) return;
@@ -235,13 +281,26 @@ function preloadImageResource(input) {
235
281
  * Generate a srcSet string for responsive images.
236
282
  *
237
283
  * Each width points to the `/_next/image` optimization endpoint so the
238
- * server can resize and transcode the image. Only includes widths that are
239
- * <= 2x the original image width to avoid pointless upscaling.
284
+ * server can resize and transcode the image.
240
285
  */
241
- function generateSrcSet(src, originalWidth, quality = 75) {
242
- const widths = RESPONSIVE_WIDTHS.filter((w) => w <= originalWidth * 2);
243
- if (widths.length === 0) return `${imageOptimizationUrl(src, originalWidth, quality)} ${originalWidth}w`;
244
- return widths.map((w) => `${imageOptimizationUrl(src, w, quality)} ${w}w`).join(", ");
286
+ function getImageWidths(width) {
287
+ return [...new Set([width, width * 2].map((targetWidth) => ALL_IMAGE_WIDTHS.find((configuredWidth) => configuredWidth >= targetWidth) ?? ALL_IMAGE_WIDTHS[ALL_IMAGE_WIDTHS.length - 1]))];
288
+ }
289
+ function generateImageAttributes(src, width, quality = 75, sizes) {
290
+ if (sizes) {
291
+ const viewportPercentages = Array.from(sizes.matchAll(/(^|\s)(1?\d?\d)vw/g), (match) => Number.parseInt(match[2], 10));
292
+ const minimumWidth = viewportPercentages.length > 0 ? RESPONSIVE_WIDTHS[0] * (Math.min(...viewportPercentages) * .01) : 0;
293
+ const candidates = ALL_IMAGE_WIDTHS.filter((candidateWidth) => candidateWidth >= minimumWidth);
294
+ return {
295
+ src: imageOptimizationUrl(src, candidates[candidates.length - 1], quality),
296
+ srcSet: candidates.map((candidateWidth) => `${imageOptimizationUrl(src, candidateWidth, quality)} ${candidateWidth}w`).join(", ")
297
+ };
298
+ }
299
+ const widths = getImageWidths(width);
300
+ return {
301
+ src: imageOptimizationUrl(src, widths[widths.length - 1], quality),
302
+ srcSet: widths.map((candidateWidth, index) => `${imageOptimizationUrl(src, candidateWidth, quality)} ${index + 1}x`).join(", ")
303
+ };
245
304
  }
246
305
  const Image = forwardRef(function Image({ src: srcProp, alt, width, height, fill, preload, priority, quality, placeholder, blurDataURL, loader, sizes, className, style, onLoad, onLoadingComplete, onError, unoptimized: _unoptimized, overrideSrc, loading, ...rest }, ref) {
247
306
  const lastLoadedSrcRef = useRef(void 0);
@@ -326,7 +385,7 @@ const Image = forwardRef(function Image({ src: srcProp, alt, width, height, fill
326
385
  lastErrorSrcRef.current = src;
327
386
  markBlurComplete();
328
387
  } : void 0;
329
- if (_unoptimized === true) {
388
+ if (_unoptimized === true || __globallyUnoptimized) {
330
389
  const renderedSrc = overrideSrc || src;
331
390
  const sanitizedBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : void 0;
332
391
  const blurStyle = !blurComplete && placeholder === "blur" && sanitizedBlur ? {
@@ -456,8 +515,9 @@ const Image = forwardRef(function Image({ src: srcProp, alt, width, height, fill
456
515
  }
457
516
  const imgQuality = quality ?? 75;
458
517
  const skipOptimization = isSvgUrl(src) && !__dangerouslyAllowSVG;
459
- const srcSet = imgWidth && !fill && !skipOptimization ? generateSrcSet(src, imgWidth, imgQuality) : imgWidth && !fill ? RESPONSIVE_WIDTHS.filter((w) => w <= imgWidth * 2).map((w) => `${src} ${w}w`).join(", ") || `${src} ${imgWidth}w` : void 0;
460
- const optimizedSrc = skipOptimization ? src : imgWidth ? imageOptimizationUrl(src, imgWidth, imgQuality) : imageOptimizationUrl(src, RESPONSIVE_WIDTHS[0], imgQuality);
518
+ const optimizedAttributes = imgWidth && !fill && !skipOptimization ? generateImageAttributes(src, imgWidth, imgQuality, sizes) : void 0;
519
+ const srcSet = optimizedAttributes ? optimizedAttributes.srcSet : imgWidth && !fill ? RESPONSIVE_WIDTHS.filter((w) => w <= imgWidth * 2).map((w) => `${src} ${w}w`).join(", ") || `${src} ${imgWidth}w` : void 0;
520
+ const optimizedSrc = skipOptimization ? src : optimizedAttributes ? optimizedAttributes.src : imageOptimizationUrl(src, RESPONSIVE_WIDTHS[0], imgQuality);
461
521
  const sanitizedLocalBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : void 0;
462
522
  const blurStyle = !blurComplete && placeholder === "blur" && sanitizedLocalBlur ? {
463
523
  backgroundImage: `url(${sanitizedLocalBlur})`,
@@ -508,7 +568,7 @@ function getImageProps(props) {
508
568
  blurDataURL: blurDataURLProp
509
569
  });
510
570
  const shouldPreload = _preload === true || priority === true;
511
- if (_unoptimized === true) {
571
+ if (_unoptimized === true || __globallyUnoptimized) {
512
572
  const renderedSrc = overrideSrc || src;
513
573
  const sanitizedBlurURL = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : void 0;
514
574
  const blurStyle = placeholder === "blur" && sanitizedBlurURL ? {
@@ -550,8 +610,9 @@ function getImageProps(props) {
550
610
  quality: imgQuality
551
611
  }) : src;
552
612
  const skipOpt = isSvgUrl(resolvedSrc) && !__dangerouslyAllowSVG || blockedInProd || !!loader || isRemoteUrl(resolvedSrc);
553
- const optimizedSrc = skipOpt ? resolvedSrc : imgWidth ? imageOptimizationUrl(resolvedSrc, imgWidth, imgQuality) : imageOptimizationUrl(resolvedSrc, RESPONSIVE_WIDTHS[0], imgQuality);
554
- const srcSet = imgWidth && !fill && !isRemoteUrl(resolvedSrc) && !loader && !skipOpt ? generateSrcSet(resolvedSrc, imgWidth, imgQuality) : void 0;
613
+ const optimizedAttributes = imgWidth && !fill && !skipOpt ? generateImageAttributes(resolvedSrc, imgWidth, imgQuality, sizes) : null;
614
+ const optimizedSrc = skipOpt ? resolvedSrc : optimizedAttributes ? optimizedAttributes.src : imageOptimizationUrl(resolvedSrc, RESPONSIVE_WIDTHS[0], imgQuality);
615
+ const srcSet = optimizedAttributes?.srcSet;
555
616
  const sanitizedBlurURL = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : void 0;
556
617
  const blurStyle = placeholder === "blur" && sanitizedBlurURL ? {
557
618
  backgroundImage: `url(${sanitizedBlurURL})`,
@@ -1,4 +1,5 @@
1
1
  import { VinextLinkPrefetchRoute } from "../../client/vinext-next-data.js";
2
+ import { getPagesRouterComponentsMap } from "./pages-router-components.js";
2
3
 
3
4
  //#region src/shims/internal/app-route-detection.d.ts
4
5
  declare global {
@@ -6,22 +7,6 @@ declare global {
6
7
  __VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];
7
8
  }
8
9
  }
9
- /**
10
- * Pages Router `components` map shape. Next.js types this loosely (route
11
- * pattern → `PrivateRouteInfo`), but for the App Router-detected case it
12
- * stores `{ __appRouter: true }` as a marker (see Next.js source link above).
13
- * Vinext only writes the marker variant; reads are by test code that checks
14
- * for `__appRouter: true`.
15
- */
16
- type PagesRouterComponentsMap = Record<string, {
17
- __appRouter: true;
18
- } | Record<string, unknown>>;
19
- /**
20
- * Get-or-create the Pages Router `components` map. Returns the same object
21
- * on every call so `router.components` and `window.next.router.components`
22
- * have referential identity.
23
- */
24
- declare function getPagesRouterComponentsMap(): PagesRouterComponentsMap;
25
10
  /**
26
11
  * Record `components[pathname] = { __appRouter: true }` on the shared
27
12
  * Pages Router map when the href matches an App Router route. No-op when the
@@ -34,6 +19,6 @@ declare function getPagesRouterComponentsMap(): PagesRouterComponentsMap;
34
19
  * first (e.g. `link.tsx` normalises to match `trailingSlash` config before
35
20
  * calling, while `router.prefetch()` passes the raw user-supplied URL).
36
21
  */
37
- declare function markAppRouteDetectedOnPrefetch(href: string, basePath: string): void;
22
+ declare function markAppRouteDetectedOnPrefetch(href: string, basePath: string): Promise<void>;
38
23
  //#endregion
39
24
  export { getPagesRouterComponentsMap, markAppRouteDetectedOnPrefetch };
@@ -1,22 +1,7 @@
1
1
  import { removeTrailingSlash, stripBasePath } from "../../utils/base-path.js";
2
2
  import { getLocalePathPrefix } from "../../utils/domain-locale.js";
3
- import { resolveHybridClientRouteOwner } from "./hybrid-client-route-owner.js";
3
+ import { getPagesRouterComponentsMap } from "./pages-router-components.js";
4
4
  //#region src/shims/internal/app-route-detection.ts
5
- const _COMPONENTS_KEY = Symbol.for("vinext.pagesRouter.components");
6
- /**
7
- * Get-or-create the Pages Router `components` map. Returns the same object
8
- * on every call so `router.components` and `window.next.router.components`
9
- * have referential identity.
10
- */
11
- function getPagesRouterComponentsMap() {
12
- const globalState = globalThis;
13
- let components = globalState[_COMPONENTS_KEY];
14
- if (!components) {
15
- components = {};
16
- globalState[_COMPONENTS_KEY] = components;
17
- }
18
- return components;
19
- }
20
5
  /**
21
6
  * Resolve a prefetch href to a same-origin pathname (basePath-stripped),
22
7
  * suitable as the key used by Next.js for `router.components[urlPathname]`.
@@ -50,8 +35,10 @@ function resolveSameOriginPathname(href, basePath) {
50
35
  * first (e.g. `link.tsx` normalises to match `trailingSlash` config before
51
36
  * calling, while `router.prefetch()` passes the raw user-supplied URL).
52
37
  */
53
- function markAppRouteDetectedOnPrefetch(href, basePath) {
38
+ async function markAppRouteDetectedOnPrefetch(href, basePath) {
54
39
  if (typeof window === "undefined") return;
40
+ if (!window.__VINEXT_LINK_PREFETCH_ROUTES__?.length) return;
41
+ const { resolveHybridClientRouteOwner } = await import("./hybrid-client-route-owner.js");
55
42
  if (resolveHybridClientRouteOwner(href, basePath) !== "app") return;
56
43
  const rawPathname = resolveSameOriginPathname(href, basePath);
57
44
  if (rawPathname === null) return;
@@ -0,0 +1,23 @@
1
+ import { VinextLinkPrefetchRoute, VinextPagesLinkPrefetchRoute } from "../../client/vinext-next-data.js";
2
+
3
+ //#region src/shims/internal/hybrid-client-route-owner-direct.d.ts
4
+ type HybridClientOwner = "app" | "document" | "pages";
5
+ type HybridClientRouteMatches = {
6
+ appMatch: VinextLinkPrefetchRoute | null;
7
+ pagesMatch: VinextPagesLinkPrefetchRoute | null;
8
+ };
9
+ declare global {
10
+ interface Window {
11
+ __VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];
12
+ __VINEXT_PAGES_LINK_PREFETCH_ROUTES__?: VinextPagesLinkPrefetchRoute[];
13
+ }
14
+ }
15
+ declare function resolveSameOriginPathname(href: string, basePath: string): string | null;
16
+ declare function matchDirectHybridClientRoutes(href: string, basePath: string): HybridClientRouteMatches;
17
+ declare function resolveMatchedHybridClientRouteOwner({
18
+ appMatch,
19
+ pagesMatch
20
+ }: HybridClientRouteMatches): HybridClientOwner | null;
21
+ declare function resolveDirectHybridClientRouteOwner(href: string, basePath: string): HybridClientOwner | null;
22
+ //#endregion
23
+ export { HybridClientOwner, matchDirectHybridClientRoutes, resolveDirectHybridClientRouteOwner, resolveMatchedHybridClientRouteOwner, resolveSameOriginPathname };
@@ -0,0 +1,51 @@
1
+ import { compareHybridRoutePatterns } from "../../routing/utils.js";
2
+ import { stripBasePath } from "../../utils/base-path.js";
3
+ import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
4
+ import { getLocalePathPrefix } from "../../utils/domain-locale.js";
5
+ //#region src/shims/internal/hybrid-client-route-owner-direct.ts
6
+ const appRouteTrieCache = createRouteTrieCache();
7
+ const pagesRouteTrieCache = createRouteTrieCache();
8
+ function patternFromParts(parts) {
9
+ return "/" + parts.join("/");
10
+ }
11
+ function resolveSameOriginPathname(href, basePath) {
12
+ if (typeof window === "undefined") return null;
13
+ let url;
14
+ try {
15
+ url = new URL(href, window.location.href);
16
+ } catch {
17
+ return null;
18
+ }
19
+ if (url.origin !== window.location.origin) return null;
20
+ const pathname = stripBasePath(url.pathname, basePath);
21
+ const locale = getLocalePathPrefix(pathname, window.__VINEXT_LOCALES__);
22
+ if (!locale) return pathname;
23
+ const localePrefixLength = locale.length + 1;
24
+ return pathname.length === localePrefixLength ? "/" : pathname.slice(localePrefixLength);
25
+ }
26
+ function matchDirectHybridClientRoutes(href, basePath) {
27
+ const pathname = resolveSameOriginPathname(href, basePath);
28
+ if (pathname === null) return {
29
+ appMatch: null,
30
+ pagesMatch: null
31
+ };
32
+ const appRoutes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
33
+ const pagesRoutes = window.__VINEXT_PAGES_LINK_PREFETCH_ROUTES__;
34
+ return {
35
+ appMatch: appRoutes ? matchRouteWithTrie(pathname, appRoutes, appRouteTrieCache)?.route ?? null : null,
36
+ pagesMatch: pagesRoutes ? matchRouteWithTrie(pathname, pagesRoutes, pagesRouteTrieCache)?.route ?? null : null
37
+ };
38
+ }
39
+ function resolveMatchedHybridClientRouteOwner({ appMatch, pagesMatch }) {
40
+ if (appMatch === null && pagesMatch === null) return null;
41
+ if (pagesMatch === null) return appMatch.documentOnly ? "document" : "app";
42
+ if (appMatch === null) return pagesMatch.documentOnly ? "document" : "pages";
43
+ const owner = compareHybridRoutePatterns(patternFromParts(pagesMatch.patternParts), pagesMatch.isDynamic, patternFromParts(appMatch.patternParts), appMatch.isDynamic);
44
+ return (owner === "app" ? appMatch : pagesMatch).documentOnly ? "document" : owner;
45
+ }
46
+ function resolveDirectHybridClientRouteOwner(href, basePath) {
47
+ if (typeof window === "undefined") return null;
48
+ return resolveMatchedHybridClientRouteOwner(matchDirectHybridClientRoutes(href, basePath));
49
+ }
50
+ //#endregion
51
+ export { matchDirectHybridClientRoutes, resolveDirectHybridClientRouteOwner, resolveMatchedHybridClientRouteOwner, resolveSameOriginPathname };
@@ -1,19 +1,6 @@
1
- import { NextRewrite } from "../../config/next-config.js";
2
- import { VinextLinkPrefetchRoute, VinextPagesLinkPrefetchRoute } from "../../client/vinext-next-data.js";
1
+ import { HybridClientOwner } from "./hybrid-client-route-owner-direct.js";
3
2
 
4
3
  //#region src/shims/internal/hybrid-client-route-owner.d.ts
5
- type HybridClientOwner = "app" | "document" | "pages";
6
- declare global {
7
- interface Window {
8
- __VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];
9
- __VINEXT_PAGES_LINK_PREFETCH_ROUTES__?: VinextPagesLinkPrefetchRoute[];
10
- __VINEXT_CLIENT_REWRITES__?: {
11
- afterFiles: NextRewrite[];
12
- beforeFiles: NextRewrite[];
13
- fallback: NextRewrite[];
14
- };
15
- }
16
- }
17
4
  /**
18
5
  * Decide which router should own a soft-navigated URL. Returns:
19
6
  * - "app" → the App Router runtime handles the navigation (RSC fetch).
@@ -28,4 +15,4 @@ declare global {
28
15
  */
29
16
  declare function resolveHybridClientRouteOwner(href: string, basePath: string): HybridClientOwner | null;
30
17
  //#endregion
31
- export { HybridClientOwner, resolveHybridClientRouteOwner };
18
+ export { type HybridClientOwner, resolveHybridClientRouteOwner };
@@ -1,8 +1,5 @@
1
- import { compareHybridRoutePatterns } from "../../routing/utils.js";
2
- import { stripBasePath } from "../../utils/base-path.js";
3
- import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
4
1
  import { isExternalUrl, matchRewrite, parseCookies } from "../../config/config-matchers.js";
5
- import { getLocalePathPrefix } from "../../utils/domain-locale.js";
2
+ import { matchDirectHybridClientRoutes, resolveMatchedHybridClientRouteOwner, resolveSameOriginPathname } from "./hybrid-client-route-owner-direct.js";
6
3
  import { mergeRewriteQuery } from "../../utils/query.js";
7
4
  //#region src/shims/internal/hybrid-client-route-owner.ts
8
5
  /**
@@ -52,45 +49,6 @@ function resolveClientRewrite(href, basePath, rewrites, continueAfterMatch = fal
52
49
  kind: "rewrite"
53
50
  } : null;
54
51
  }
55
- const appRouteTrieCache = createRouteTrieCache();
56
- const pagesRouteTrieCache = createRouteTrieCache();
57
- /**
58
- * Build a `/`-joined pattern from a manifest's `patternParts`. Mirrors the
59
- * server-side route-graph shape (`{ pattern: string }`) so the
60
- * `compareHybridRoutePatterns` segment-rank comparator can score both Pages
61
- * and App patterns. The
62
- * `patternParts` array never includes an empty string for the static `/`
63
- * route (the App catch-all handles the bare path), so the simple join is
64
- * safe for everything the route trie actually matches.
65
- */
66
- function patternFromParts(parts) {
67
- return "/" + parts.join("/");
68
- }
69
- function resolveSameOriginPathname(href, basePath) {
70
- if (typeof window === "undefined") return null;
71
- let url;
72
- try {
73
- url = new URL(href, window.location.href);
74
- } catch {
75
- return null;
76
- }
77
- if (url.origin !== window.location.origin) return null;
78
- const pathname = stripBasePath(url.pathname, basePath);
79
- const locale = getLocalePathPrefix(pathname, window.__VINEXT_LOCALES__);
80
- if (!locale) return pathname;
81
- const localePrefixLength = locale.length + 1;
82
- return pathname.length === localePrefixLength ? "/" : pathname.slice(localePrefixLength);
83
- }
84
- function matchAppRoute(href, basePath, routes) {
85
- const pathname = resolveSameOriginPathname(href, basePath);
86
- if (pathname === null) return null;
87
- return matchRouteWithTrie(pathname, routes, appRouteTrieCache)?.route ?? null;
88
- }
89
- function matchPagesRoute(href, basePath, routes) {
90
- const pathname = resolveSameOriginPathname(href, basePath);
91
- if (pathname === null) return null;
92
- return matchRouteWithTrie(pathname, routes, pagesRouteTrieCache)?.route ?? null;
93
- }
94
52
  /**
95
53
  * Decide which router should own a soft-navigated URL. Returns:
96
54
  * - "app" → the App Router runtime handles the navigation (RSC fetch).
@@ -105,39 +63,30 @@ function matchPagesRoute(href, basePath, routes) {
105
63
  */
106
64
  function resolveHybridClientRouteOwner(href, basePath) {
107
65
  if (typeof window === "undefined") return null;
108
- const appRoutes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
109
- const pagesRoutes = window.__VINEXT_PAGES_LINK_PREFETCH_ROUTES__;
110
66
  const rewrites = window.__VINEXT_CLIENT_REWRITES__;
111
67
  if (rewrites) {
112
68
  const beforeFilesRewrite = resolveClientRewrite(href, basePath, rewrites.beforeFiles, true);
113
69
  if (beforeFilesRewrite?.kind === "document") return "document";
114
70
  if (beforeFilesRewrite?.kind === "rewrite") href = beforeFilesRewrite.href;
115
71
  }
116
- let appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
117
- let pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
118
- if (rewrites && (appMatch === null || appMatch.isDynamic) && (pagesMatch === null || pagesMatch.isDynamic)) for (const rewrite of rewrites.afterFiles) {
72
+ let matches = matchDirectHybridClientRoutes(href, basePath);
73
+ if (rewrites && (matches.appMatch === null || matches.appMatch.isDynamic) && (matches.pagesMatch === null || matches.pagesMatch.isDynamic)) for (const rewrite of rewrites.afterFiles) {
119
74
  const afterFilesRewrite = resolveClientRewrite(href, basePath, [rewrite]);
120
75
  if (afterFilesRewrite?.kind === "document") return "document";
121
76
  if (afterFilesRewrite?.kind !== "rewrite") continue;
122
77
  href = afterFilesRewrite.href;
123
- appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
124
- pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
125
- if (appMatch || pagesMatch) break;
78
+ matches = matchDirectHybridClientRoutes(href, basePath);
79
+ if (matches.appMatch || matches.pagesMatch) break;
126
80
  }
127
- if (rewrites && appMatch === null && pagesMatch === null) for (const rewrite of rewrites.fallback) {
81
+ if (rewrites && matches.appMatch === null && matches.pagesMatch === null) for (const rewrite of rewrites.fallback) {
128
82
  const fallbackRewrite = resolveClientRewrite(href, basePath, [rewrite]);
129
83
  if (fallbackRewrite?.kind === "document") return "document";
130
84
  if (fallbackRewrite?.kind !== "rewrite") continue;
131
85
  href = fallbackRewrite.href;
132
- appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
133
- pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
134
- if (appMatch || pagesMatch) break;
86
+ matches = matchDirectHybridClientRoutes(href, basePath);
87
+ if (matches.appMatch || matches.pagesMatch) break;
135
88
  }
136
- if (appMatch === null && pagesMatch === null) return null;
137
- if (pagesMatch === null) return appMatch.documentOnly ? "document" : "app";
138
- if (appMatch === null) return pagesMatch.documentOnly ? "document" : "pages";
139
- const owner = compareHybridRoutePatterns(patternFromParts(pagesMatch.patternParts), pagesMatch.isDynamic, patternFromParts(appMatch.patternParts), appMatch.isDynamic);
140
- return (owner === "app" ? appMatch : pagesMatch).documentOnly ? "document" : owner;
89
+ return resolveMatchedHybridClientRouteOwner(matches);
141
90
  }
142
91
  //#endregion
143
92
  export { resolveHybridClientRouteOwner };
@@ -24,14 +24,18 @@
24
24
  * directly by anyone, which keeps subsequent clones legal even after one
25
25
  * caller has consumed its copy.
26
26
  *
27
- * - Each caller owns one waiter. Cancelling a waiter leaves the shared request
28
- * alive while another waiter remains; cancelling the final waiter aborts the
29
- * underlying fetch and evicts the entry immediately so a replacement caller
30
- * can retry without joining a doomed request.
27
+ * - Each caller owns one waiter. Cancelling a waiter rejects only that caller;
28
+ * the shared request continues and self-evicts when it settles. This mirrors
29
+ * Next.js: a superseded data request may still reach the server, but its
30
+ * result is ignored by the cancelled navigation.
31
31
  *
32
32
  * - The map is module-scoped (one per realm). The Pages Router runs in the
33
33
  * browser only, so a single `Map` is sufficient.
34
34
  */
35
+ declare function getPagesStaticDataCache(): Record<string, Promise<Response>>;
36
+ declare function fetchCachedPagesData(dataHref: string, init?: RequestInit): Promise<Response>;
37
+ declare function fetchStaticPagesData(dataHref: string, init?: RequestInit): Promise<Response>;
38
+ declare function evictPagesDataCache(dataHref: string): void;
35
39
  /**
36
40
  * Dedupe a `fetch()` against the `_next/data` endpoint. Multiple concurrent
37
41
  * callers for the same resolved URL and deployment ID share one underlying
@@ -51,4 +55,4 @@ declare function dedupedPagesDataFetch(dataHref: string, init?: RequestInit): Pr
51
55
  */
52
56
  declare function clearPagesDataInflight(): void;
53
57
  //#endregion
54
- export { clearPagesDataInflight, dedupedPagesDataFetch };
58
+ export { clearPagesDataInflight, dedupedPagesDataFetch, evictPagesDataCache, fetchCachedPagesData, fetchStaticPagesData, getPagesStaticDataCache };
@@ -1,4 +1,4 @@
1
- import "../../utils/deployment-id.js";
1
+ import { getDeploymentId } from "../../utils/deployment-id.js";
2
2
  //#region src/shims/internal/pages-data-fetch-dedup.ts
3
3
  /**
4
4
  * In-flight request dedup for the Pages Router `/_next/data/<id>/<page>.json`
@@ -25,16 +25,77 @@ import "../../utils/deployment-id.js";
25
25
  * directly by anyone, which keeps subsequent clones legal even after one
26
26
  * caller has consumed its copy.
27
27
  *
28
- * - Each caller owns one waiter. Cancelling a waiter leaves the shared request
29
- * alive while another waiter remains; cancelling the final waiter aborts the
30
- * underlying fetch and evicts the entry immediately so a replacement caller
31
- * can retry without joining a doomed request.
28
+ * - Each caller owns one waiter. Cancelling a waiter rejects only that caller;
29
+ * the shared request continues and self-evicts when it settles. This mirrors
30
+ * Next.js: a superseded data request may still reach the server, but its
31
+ * result is ignored by the cancelled navigation.
32
32
  *
33
33
  * - The map is module-scoped (one per realm). The Pages Router runs in the
34
34
  * browser only, so a single `Map` is sufficient.
35
35
  */
36
36
  /** Inflight fetch entries keyed by the resolved data request identity. */
37
37
  const inflight = /* @__PURE__ */ new Map();
38
+ const staticDataCache = Object.create(null);
39
+ const staticDataSources = /* @__PURE__ */ new Map();
40
+ function getStaticDataKey(dataHref) {
41
+ if (typeof window === "undefined") return dataHref;
42
+ try {
43
+ return new URL(dataHref, window.location.href).href;
44
+ } catch {
45
+ return dataHref;
46
+ }
47
+ }
48
+ function cloneStaticResponse(cached, signal) {
49
+ if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
50
+ if (!signal) return cached.then((response) => response.clone());
51
+ return new Promise((resolve, reject) => {
52
+ const abort = () => reject(new DOMException("Aborted", "AbortError"));
53
+ signal.addEventListener("abort", abort, { once: true });
54
+ cached.then((response) => {
55
+ signal.removeEventListener("abort", abort);
56
+ resolve(response.clone());
57
+ }, (error) => {
58
+ signal.removeEventListener("abort", abort);
59
+ reject(error);
60
+ });
61
+ });
62
+ }
63
+ function getPagesStaticDataCache() {
64
+ return staticDataCache;
65
+ }
66
+ function fetchCachedPagesData(dataHref, init) {
67
+ const key = getStaticDataKey(dataHref);
68
+ let cached = staticDataSources.get(key);
69
+ if (cached === void 0) {
70
+ const { signal: _signal, ...sharedInit } = init ?? {};
71
+ cached = dedupedPagesDataFetch(dataHref, sharedInit).then((response) => {
72
+ const expectedDeploymentId = getDeploymentId() ?? null;
73
+ const responseDeploymentId = response.headers.get("x-nextjs-deployment-id");
74
+ if (!response.ok || response.headers.get("x-middleware-cache") === "no-cache" || responseDeploymentId !== null && responseDeploymentId !== expectedDeploymentId) {
75
+ delete staticDataCache[key];
76
+ staticDataSources.delete(key);
77
+ }
78
+ return response;
79
+ }).catch((error) => {
80
+ delete staticDataCache[key];
81
+ staticDataSources.delete(key);
82
+ throw error;
83
+ });
84
+ staticDataSources.set(key, cached);
85
+ const publicCached = cached.then((response) => response.clone());
86
+ publicCached.catch(() => {});
87
+ staticDataCache[key] = publicCached;
88
+ }
89
+ return cloneStaticResponse(cached, init?.signal ?? void 0);
90
+ }
91
+ function fetchStaticPagesData(dataHref, init) {
92
+ return fetchCachedPagesData(dataHref, init);
93
+ }
94
+ function evictPagesDataCache(dataHref) {
95
+ const key = getStaticDataKey(dataHref);
96
+ delete staticDataCache[key];
97
+ staticDataSources.delete(key);
98
+ }
38
99
  function getInflightKey(dataHref, init) {
39
100
  let resolvedHref = dataHref;
40
101
  if (typeof window !== "undefined") try {
@@ -47,27 +108,23 @@ function cloneSharedResponse(key, entry, signal) {
47
108
  entry.waiters += 1;
48
109
  return new Promise((resolve, reject) => {
49
110
  let released = false;
50
- const release = (cancelled) => {
111
+ const release = () => {
51
112
  if (released) return;
52
113
  released = true;
53
114
  entry.waiters -= 1;
54
- if (cancelled && entry.waiters === 0 && !entry.settled) {
55
- if (inflight.get(key) === entry) inflight.delete(key);
56
- entry.controller.abort();
57
- }
58
115
  };
59
116
  const abort = () => {
60
- release(true);
117
+ release();
61
118
  reject(new DOMException("Aborted", "AbortError"));
62
119
  };
63
120
  signal?.addEventListener("abort", abort, { once: true });
64
121
  entry.promise.then((response) => {
65
122
  signal?.removeEventListener("abort", abort);
66
- release(false);
123
+ release();
67
124
  resolve(response.clone());
68
125
  }, (error) => {
69
126
  signal?.removeEventListener("abort", abort);
70
- release(false);
127
+ release();
71
128
  reject(error);
72
129
  });
73
130
  });
@@ -116,6 +173,8 @@ function dedupedPagesDataFetch(dataHref, init) {
116
173
  function clearPagesDataInflight() {
117
174
  for (const entry of inflight.values()) entry.controller.abort();
118
175
  inflight.clear();
176
+ staticDataSources.clear();
177
+ for (const key of Object.keys(staticDataCache)) delete staticDataCache[key];
119
178
  }
120
179
  //#endregion
121
- export { clearPagesDataInflight, dedupedPagesDataFetch };
180
+ export { clearPagesDataInflight, dedupedPagesDataFetch, evictPagesDataCache, fetchCachedPagesData, fetchStaticPagesData, getPagesStaticDataCache };
@@ -6,7 +6,9 @@ type PagesDataTarget = {
6
6
  loader: () => Promise<{
7
7
  default?: unknown;
8
8
  [key: string]: unknown;
9
- }>; /** Current buildId snapshot, used by the data URL and consistency checks. */
9
+ }>; /** Next.js data-fetch mode for this route. Plain pages are component-only. */
10
+ dataKind: "none" | "server" | "static"; /** Middleware-effect data URL to prefetch when the static matcher includes this route. */
11
+ middlewareDataHref?: string; /** Current buildId snapshot, used by the data URL and consistency checks. */
10
12
  buildId: string; /** Locale-prefixed (server-routable) page path. */
11
13
  pagePath: string; /** URL search string including the leading `?`. */
12
14
  search: string;
@@ -18,6 +20,7 @@ type PagesDataTarget = {
18
20
  */
19
21
  locale: string | undefined;
20
22
  };
23
+ declare function getPagesMiddlewareDataHref(browserUrl: string, basePath: string): string | null;
21
24
  /**
22
25
  * Decide whether the JSON data-endpoint navigation path is usable for this
23
26
  * browser URL. We require:
@@ -43,14 +46,12 @@ type PagesDataTarget = {
43
46
  */
44
47
  declare function resolvePagesDataNavigationTarget(browserUrl: string, basePath: string): PagesDataTarget | null;
45
48
  /**
46
- * Prefetch the data JSON and kick off the code-split loader so the chunk is
47
- * warm by the time the user clicks.
49
+ * Kick off the code-split loader and, for SSG pages, prefetch the data JSON so
50
+ * the chunk and payload are warm by the time the user clicks.
48
51
  *
49
- * Used by both `Router.prefetch()` and `<Link>` hover/viewport prefetch. The
50
- * JSON request uses `fetch()` rather than `<link rel="prefetch">` so it can
51
- * carry Next.js's `x-deployment-id` skew-protection header. The in-flight
52
- * request is shared with a racing navigation; after it settles, the browser's
53
- * normal HTTP cache remains responsible for reuse.
52
+ * Used by both `Router.prefetch()` and `<Link>` hover/viewport prefetch.
53
+ * Matches Next.js Pages Router prefetch: non-SSG routes only warm the page
54
+ * chunk, while `getStaticProps` routes also fetch `/_next/data`.
54
55
  *
55
56
  * loader's returned Promise is intentionally discarded — `import()` caches the
56
57
  * result, so a subsequent navigation re-invocation hits the cache without
@@ -59,4 +60,4 @@ declare function resolvePagesDataNavigationTarget(browserUrl: string, basePath:
59
60
  */
60
61
  declare function prefetchPagesData(target: PagesDataTarget): void;
61
62
  //#endregion
62
- export { PagesDataTarget, prefetchPagesData, resolvePagesDataNavigationTarget };
63
+ export { PagesDataTarget, getPagesMiddlewareDataHref, prefetchPagesData, resolvePagesDataNavigationTarget };