vinext 0.1.1 → 0.1.3

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 (266) hide show
  1. package/README.md +2 -5
  2. package/dist/build/client-build-config.d.ts +7 -1
  3. package/dist/build/client-build-config.js +9 -1
  4. package/dist/build/prerender.d.ts +9 -1
  5. package/dist/build/prerender.js +41 -12
  6. package/dist/build/run-prerender.d.ts +10 -2
  7. package/dist/build/run-prerender.js +15 -1
  8. package/dist/check.js +4 -3
  9. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  10. package/dist/client/app-nav-failure-handler.js +44 -0
  11. package/dist/client/navigation-runtime.d.ts +3 -2
  12. package/dist/client/vinext-next-data.d.ts +18 -1
  13. package/dist/client/window-next.d.ts +8 -5
  14. package/dist/client/window-next.js +12 -1
  15. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  16. package/dist/config/config-matchers.d.ts +11 -4
  17. package/dist/config/config-matchers.js +88 -16
  18. package/dist/config/next-config.d.ts +59 -4
  19. package/dist/config/next-config.js +149 -48
  20. package/dist/deploy.d.ts +30 -11
  21. package/dist/deploy.js +189 -101
  22. package/dist/entries/app-browser-entry.d.ts +9 -3
  23. package/dist/entries/app-browser-entry.js +21 -3
  24. package/dist/entries/app-rsc-entry.d.ts +2 -0
  25. package/dist/entries/app-rsc-entry.js +71 -6
  26. package/dist/entries/app-rsc-manifest.js +2 -0
  27. package/dist/entries/app-ssr-entry.js +1 -1
  28. package/dist/entries/pages-client-entry.js +54 -9
  29. package/dist/entries/pages-server-entry.js +48 -11
  30. package/dist/index.d.ts +0 -2
  31. package/dist/index.js +285 -139
  32. package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
  33. package/dist/plugins/dynamic-preload-metadata.js +415 -0
  34. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  35. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  36. package/dist/plugins/og-assets.js +2 -2
  37. package/dist/plugins/optimize-imports.d.ts +10 -5
  38. package/dist/plugins/optimize-imports.js +27 -21
  39. package/dist/plugins/postcss.js +7 -7
  40. package/dist/plugins/sass.d.ts +53 -24
  41. package/dist/plugins/sass.js +249 -1
  42. package/dist/plugins/typeof-window.d.ts +14 -0
  43. package/dist/plugins/typeof-window.js +150 -0
  44. package/dist/plugins/wasm-module-import.d.ts +15 -0
  45. package/dist/plugins/wasm-module-import.js +50 -0
  46. package/dist/routing/app-route-graph.d.ts +25 -2
  47. package/dist/routing/app-route-graph.js +91 -22
  48. package/dist/routing/file-matcher.d.ts +10 -1
  49. package/dist/routing/file-matcher.js +23 -2
  50. package/dist/routing/pages-router.js +3 -3
  51. package/dist/routing/utils.d.ts +35 -6
  52. package/dist/routing/utils.js +59 -7
  53. package/dist/server/api-handler.d.ts +6 -1
  54. package/dist/server/api-handler.js +21 -15
  55. package/dist/server/app-browser-action-result.d.ts +19 -6
  56. package/dist/server/app-browser-action-result.js +19 -10
  57. package/dist/server/app-browser-entry.js +269 -297
  58. package/dist/server/app-browser-error.d.ts +10 -3
  59. package/dist/server/app-browser-error.js +47 -6
  60. package/dist/server/app-browser-history-controller.d.ts +104 -0
  61. package/dist/server/app-browser-history-controller.js +210 -0
  62. package/dist/server/app-browser-hydration.d.ts +2 -0
  63. package/dist/server/app-browser-hydration.js +1 -0
  64. package/dist/server/app-browser-navigation-controller.d.ts +7 -4
  65. package/dist/server/app-browser-navigation-controller.js +33 -9
  66. package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
  67. package/dist/server/app-browser-rsc-redirect.js +30 -8
  68. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  69. package/dist/server/app-browser-server-action-navigation.js +9 -0
  70. package/dist/server/app-browser-state.js +4 -7
  71. package/dist/server/app-browser-stream.js +86 -43
  72. package/dist/server/app-browser-visible-commit.js +1 -1
  73. package/dist/server/app-elements-wire.d.ts +6 -1
  74. package/dist/server/app-elements-wire.js +14 -4
  75. package/dist/server/app-elements.d.ts +2 -2
  76. package/dist/server/app-elements.js +2 -2
  77. package/dist/server/app-fallback-renderer.d.ts +3 -1
  78. package/dist/server/app-fallback-renderer.js +6 -2
  79. package/dist/server/app-middleware.js +1 -0
  80. package/dist/server/app-optimistic-routing.js +24 -3
  81. package/dist/server/app-page-boundary-render.d.ts +3 -1
  82. package/dist/server/app-page-boundary-render.js +31 -16
  83. package/dist/server/app-page-cache-render.d.ts +53 -0
  84. package/dist/server/app-page-cache-render.js +91 -0
  85. package/dist/server/app-page-cache.d.ts +16 -2
  86. package/dist/server/app-page-cache.js +71 -8
  87. package/dist/server/app-page-dispatch.d.ts +34 -0
  88. package/dist/server/app-page-dispatch.js +167 -97
  89. package/dist/server/app-page-element-builder.d.ts +23 -2
  90. package/dist/server/app-page-element-builder.js +42 -10
  91. package/dist/server/app-page-execution.d.ts +7 -2
  92. package/dist/server/app-page-execution.js +53 -18
  93. package/dist/server/app-page-probe.d.ts +1 -0
  94. package/dist/server/app-page-probe.js +4 -0
  95. package/dist/server/app-page-render-observation.d.ts +3 -1
  96. package/dist/server/app-page-render-observation.js +17 -1
  97. package/dist/server/app-page-render.d.ts +13 -2
  98. package/dist/server/app-page-render.js +48 -17
  99. package/dist/server/app-page-request.d.ts +3 -0
  100. package/dist/server/app-page-request.js +5 -3
  101. package/dist/server/app-page-response.js +1 -1
  102. package/dist/server/app-page-route-wiring.d.ts +5 -1
  103. package/dist/server/app-page-route-wiring.js +21 -11
  104. package/dist/server/app-page-stream.d.ts +16 -9
  105. package/dist/server/app-page-stream.js +12 -9
  106. package/dist/server/app-pages-bridge.d.ts +18 -0
  107. package/dist/server/app-pages-bridge.js +22 -5
  108. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  109. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  110. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  111. package/dist/server/app-ppr-fallback-shell.js +8 -1
  112. package/dist/server/app-route-handler-dispatch.js +9 -2
  113. package/dist/server/app-route-handler-policy.d.ts +1 -0
  114. package/dist/server/app-route-handler-response.js +11 -10
  115. package/dist/server/app-route-handler-runtime.js +12 -1
  116. package/dist/server/app-router-entry.js +5 -0
  117. package/dist/server/app-rsc-cache-busting.js +2 -0
  118. package/dist/server/app-rsc-handler.d.ts +25 -0
  119. package/dist/server/app-rsc-handler.js +153 -53
  120. package/dist/server/app-rsc-response-finalizer.js +1 -1
  121. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  122. package/dist/server/app-rsc-route-matching.js +2 -0
  123. package/dist/server/app-segment-config.d.ts +9 -1
  124. package/dist/server/app-segment-config.js +12 -3
  125. package/dist/server/app-server-action-execution.d.ts +12 -0
  126. package/dist/server/app-server-action-execution.js +47 -15
  127. package/dist/server/app-ssr-entry.d.ts +2 -0
  128. package/dist/server/app-ssr-entry.js +81 -8
  129. package/dist/server/app-ssr-stream.js +9 -1
  130. package/dist/server/cache-control.js +4 -0
  131. package/dist/server/dev-lockfile.js +2 -1
  132. package/dist/server/dev-server.d.ts +2 -2
  133. package/dist/server/dev-server.js +287 -63
  134. package/dist/server/headers.d.ts +8 -1
  135. package/dist/server/headers.js +8 -1
  136. package/dist/server/hybrid-route-priority.d.ts +22 -0
  137. package/dist/server/hybrid-route-priority.js +33 -0
  138. package/dist/server/image-optimization.d.ts +18 -9
  139. package/dist/server/image-optimization.js +37 -23
  140. package/dist/server/implicit-tags.d.ts +2 -1
  141. package/dist/server/implicit-tags.js +4 -1
  142. package/dist/server/instrumentation-runtime.d.ts +6 -0
  143. package/dist/server/instrumentation-runtime.js +8 -0
  144. package/dist/server/isr-decision.d.ts +79 -0
  145. package/dist/server/isr-decision.js +70 -0
  146. package/dist/server/metadata-route-response.js +5 -3
  147. package/dist/server/middleware-runtime.d.ts +13 -0
  148. package/dist/server/middleware-runtime.js +11 -7
  149. package/dist/server/middleware.js +1 -0
  150. package/dist/server/navigation-planner.d.ts +186 -22
  151. package/dist/server/navigation-planner.js +302 -0
  152. package/dist/server/navigation-trace.d.ts +18 -1
  153. package/dist/server/navigation-trace.js +18 -1
  154. package/dist/server/normalize-path.d.ts +0 -8
  155. package/dist/server/normalize-path.js +3 -1
  156. package/dist/server/otel-tracer-extension.d.ts +45 -0
  157. package/dist/server/otel-tracer-extension.js +89 -0
  158. package/dist/server/pages-api-route.d.ts +20 -3
  159. package/dist/server/pages-api-route.js +19 -3
  160. package/dist/server/pages-asset-tags.d.ts +16 -4
  161. package/dist/server/pages-asset-tags.js +22 -12
  162. package/dist/server/pages-data-route.d.ts +8 -1
  163. package/dist/server/pages-data-route.js +16 -3
  164. package/dist/server/pages-get-initial-props.d.ts +54 -4
  165. package/dist/server/pages-get-initial-props.js +43 -1
  166. package/dist/server/pages-node-compat.d.ts +3 -11
  167. package/dist/server/pages-node-compat.js +175 -122
  168. package/dist/server/pages-page-data.d.ts +39 -2
  169. package/dist/server/pages-page-data.js +261 -46
  170. package/dist/server/pages-page-handler.d.ts +5 -2
  171. package/dist/server/pages-page-handler.js +78 -25
  172. package/dist/server/pages-page-response.d.ts +47 -2
  173. package/dist/server/pages-page-response.js +73 -9
  174. package/dist/server/pages-readiness.d.ts +1 -1
  175. package/dist/server/pages-request-pipeline.d.ts +16 -1
  176. package/dist/server/pages-request-pipeline.js +96 -38
  177. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  178. package/dist/server/pregenerated-concrete-paths.js +2 -19
  179. package/dist/server/prerender-manifest.d.ts +33 -0
  180. package/dist/server/prerender-manifest.js +54 -0
  181. package/dist/server/prerender-route-params.d.ts +1 -2
  182. package/dist/server/prod-server.d.ts +39 -1
  183. package/dist/server/prod-server.js +107 -37
  184. package/dist/server/request-pipeline.d.ts +3 -15
  185. package/dist/server/request-pipeline.js +58 -47
  186. package/dist/server/rsc-stream-hints.d.ts +5 -1
  187. package/dist/server/rsc-stream-hints.js +6 -1
  188. package/dist/server/seed-cache.js +10 -18
  189. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  190. package/dist/shims/app-router-scroll-state.js +14 -2
  191. package/dist/shims/app-router-scroll.d.ts +3 -0
  192. package/dist/shims/app-router-scroll.js +28 -18
  193. package/dist/shims/cache-runtime.js +12 -4
  194. package/dist/shims/cache.d.ts +1 -0
  195. package/dist/shims/cache.js +1 -1
  196. package/dist/shims/cdn-cache.d.ts +5 -5
  197. package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
  198. package/dist/shims/dynamic-preload-chunks.js +79 -0
  199. package/dist/shims/dynamic.d.ts +4 -0
  200. package/dist/shims/dynamic.js +4 -2
  201. package/dist/shims/error-boundary.d.ts +6 -4
  202. package/dist/shims/error-boundary.js +7 -0
  203. package/dist/shims/error.js +38 -11
  204. package/dist/shims/error.react-server.d.ts +9 -0
  205. package/dist/shims/error.react-server.js +6 -0
  206. package/dist/shims/fetch-cache.d.ts +11 -1
  207. package/dist/shims/fetch-cache.js +55 -20
  208. package/dist/shims/hash-scroll.js +6 -1
  209. package/dist/shims/head.js +6 -1
  210. package/dist/shims/headers.d.ts +16 -2
  211. package/dist/shims/headers.js +66 -5
  212. package/dist/shims/image-config.js +7 -1
  213. package/dist/shims/internal/als-registry.js +28 -1
  214. package/dist/shims/internal/app-route-detection.d.ts +6 -3
  215. package/dist/shims/internal/app-route-detection.js +18 -23
  216. package/dist/shims/internal/app-router-context.d.ts +5 -0
  217. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  218. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  219. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  220. package/dist/shims/internal/navigation-untracked.js +55 -0
  221. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  222. package/dist/shims/internal/pages-data-target.js +17 -8
  223. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  224. package/dist/shims/internal/pages-router-accessor.js +13 -0
  225. package/dist/shims/internal/router-context.d.ts +2 -1
  226. package/dist/shims/internal/router-context.js +3 -1
  227. package/dist/shims/link.js +12 -5
  228. package/dist/shims/metadata.d.ts +6 -2
  229. package/dist/shims/metadata.js +32 -14
  230. package/dist/shims/navigation.d.ts +14 -17
  231. package/dist/shims/navigation.js +93 -46
  232. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  233. package/dist/shims/ppr-fallback-shell.js +28 -7
  234. package/dist/shims/router.d.ts +13 -2
  235. package/dist/shims/router.js +434 -116
  236. package/dist/shims/script-nonce-context.d.ts +1 -1
  237. package/dist/shims/script-nonce-context.js +11 -3
  238. package/dist/shims/server.d.ts +33 -2
  239. package/dist/shims/server.js +75 -18
  240. package/dist/shims/slot.js +1 -1
  241. package/dist/shims/unified-request-context.js +2 -0
  242. package/dist/typegen.js +1 -0
  243. package/dist/utils/built-asset-url.d.ts +4 -0
  244. package/dist/utils/built-asset-url.js +11 -0
  245. package/dist/utils/client-build-manifest.js +15 -5
  246. package/dist/utils/client-runtime-metadata.d.ts +45 -0
  247. package/dist/utils/client-runtime-metadata.js +63 -0
  248. package/dist/utils/commonjs-loader.d.ts +16 -0
  249. package/dist/utils/commonjs-loader.js +100 -0
  250. package/dist/utils/deployment-id.d.ts +8 -0
  251. package/dist/utils/deployment-id.js +22 -0
  252. package/dist/utils/hash.d.ts +17 -1
  253. package/dist/utils/hash.js +36 -1
  254. package/dist/utils/html-limited-bots.d.ts +18 -1
  255. package/dist/utils/html-limited-bots.js +23 -1
  256. package/dist/utils/lazy-chunks.d.ts +27 -1
  257. package/dist/utils/lazy-chunks.js +65 -1
  258. package/dist/utils/manifest-paths.d.ts +20 -2
  259. package/dist/utils/manifest-paths.js +38 -3
  260. package/dist/utils/parse-cookie.d.ts +13 -0
  261. package/dist/utils/parse-cookie.js +52 -0
  262. package/dist/utils/path.d.ts +8 -1
  263. package/dist/utils/path.js +13 -1
  264. package/package.json +2 -2
  265. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  266. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -1,6 +1,7 @@
1
1
  import { getOrCreateAls } from "./internal/als-registry.js";
2
2
  import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
3
3
  import { getRequestExecutionContext } from "./request-context.js";
4
+ import { markDynamicUsage } from "./headers.js";
4
5
  import { encodeCacheTags } from "../utils/encode-cache-tag.js";
5
6
  import { getDataCacheHandler } from "./cache.js";
6
7
  //#region src/shims/fetch-cache.ts
@@ -32,6 +33,7 @@ import { getDataCacheHandler } from "./cache.js";
32
33
  const HEADER_BLOCKLIST = ["traceparent", "tracestate"];
33
34
  const CACHE_KEY_PREFIX = "v3";
34
35
  const MAX_CACHE_KEY_BODY_BYTES = 1024 * 1024;
36
+ const ONE_YEAR_SECONDS = 31536e3;
35
37
  var BodyTooLargeForCacheKeyError = class extends Error {
36
38
  constructor() {
37
39
  super("Fetch body too large for cache key generation");
@@ -292,6 +294,7 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
292
294
  currentRequestTags: [],
293
295
  currentFetchSoftTags: [],
294
296
  currentFetchCacheMode: null,
297
+ currentForceDynamicFetchDefault: false,
295
298
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
296
299
  isFetchDedupeActive: false,
297
300
  currentFetchDedupeEntries: /* @__PURE__ */ new Map()
@@ -309,6 +312,7 @@ function _resetFallbackState(isFetchDedupeActive) {
309
312
  _fallbackState.currentRequestTags = [];
310
313
  _fallbackState.currentFetchSoftTags = [];
311
314
  _fallbackState.currentFetchCacheMode = null;
315
+ _fallbackState.currentForceDynamicFetchDefault = false;
312
316
  _fallbackState.dynamicFetchUrls = /* @__PURE__ */ new Set();
313
317
  _fallbackState.isFetchDedupeActive = isFetchDedupeActive;
314
318
  _fallbackState.currentFetchDedupeEntries = /* @__PURE__ */ new Map();
@@ -319,6 +323,10 @@ function getFetchObservationUrl(input) {
319
323
  function recordDynamicFetchObservation(input) {
320
324
  _getState().dynamicFetchUrls.add(getFetchObservationUrl(input));
321
325
  }
326
+ function markUncachedFetchForPageOutput(input) {
327
+ recordDynamicFetchObservation(input);
328
+ markDynamicUsage();
329
+ }
322
330
  function recordCacheableFetchObservation(input) {
323
331
  _getState().cacheableFetchUrls.add(getFetchObservationUrl(input));
324
332
  }
@@ -369,19 +377,36 @@ function addCollectedRequestTags(tags) {
369
377
  function setCurrentFetchSoftTags(tags) {
370
378
  _getState().currentFetchSoftTags = [...tags];
371
379
  }
380
+ /**
381
+ * Read the path-derived soft tags for the current render.
382
+ *
383
+ * Used by the "use cache" runtime to pass soft tags to the cache handler
384
+ * so that `revalidatePath()` invalidates "use cache" entries during the
385
+ * affected route's next request, even when the entry carries no hard tags.
386
+ */
387
+ function getCurrentFetchSoftTags() {
388
+ return _getState().currentFetchSoftTags;
389
+ }
372
390
  function setCurrentFetchCacheMode(mode) {
373
391
  _getState().currentFetchCacheMode = mode;
374
392
  }
393
+ function setCurrentForceDynamicFetchDefault(enabled) {
394
+ _getState().currentForceDynamicFetchDefault = enabled;
395
+ }
375
396
  function isNoStoreFetch(cacheDirective, nextOpts) {
376
- return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === false || nextOpts?.revalidate === 0;
397
+ return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0;
377
398
  }
378
399
  function isCacheableFetch(cacheDirective, nextOpts) {
379
- return cacheDirective === "force-cache" || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0;
400
+ return cacheDirective === "force-cache" || nextOpts?.revalidate === false || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0;
380
401
  }
381
402
  function hasExplicitRevalidateValue(nextOpts) {
382
403
  return nextOpts?.revalidate !== void 0;
383
404
  }
384
- function resolveSegmentCacheDirective(cacheDirective, nextOpts, mode) {
405
+ function isFalsyRevalidate(nextOpts) {
406
+ return !nextOpts?.revalidate;
407
+ }
408
+ function resolveSegmentCacheDirective(cacheDirective, nextOpts, mode, forceDynamicFetchDefault) {
409
+ if (forceDynamicFetchDefault && (!mode || mode === "auto") && (cacheDirective === void 0 || cacheDirective === "default") && isFalsyRevalidate(nextOpts)) return "no-store";
385
410
  if (!mode || mode === "auto") return cacheDirective;
386
411
  switch (mode) {
387
412
  case "force-cache": return "force-cache";
@@ -447,6 +472,20 @@ function cloneDedupeResponse(response) {
447
472
  const [body1, body2] = response.body.tee();
448
473
  return [buildDedupeClone(body1, response), buildDedupeClone(body2, response)];
449
474
  }
475
+ function buildCachedFetchResponse(data, input) {
476
+ const response = new Response(data.body, {
477
+ status: data.status ?? 200,
478
+ headers: data.headers
479
+ });
480
+ Object.defineProperty(response, "url", {
481
+ value: data.url ?? getFetchObservationUrl(input),
482
+ configurable: true,
483
+ enumerable: true,
484
+ writable: false
485
+ });
486
+ if (_responseBodyRegistry && response.body) _responseBodyRegistry.register(response, new WeakRef(response.body));
487
+ return response;
488
+ }
450
489
  function dedupeFetch(input, init) {
451
490
  const state = _getState();
452
491
  if (!state.isFetchDedupeActive) return originalFetch(input, init);
@@ -497,25 +536,26 @@ function dedupeFetch(input, init) {
497
536
  function createPatchedFetch() {
498
537
  return async function patchedFetch(input, init) {
499
538
  const nextOpts = init?.next;
500
- const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode);
539
+ const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode, _getState().currentForceDynamicFetchDefault);
501
540
  if (!nextOpts && !cacheDirective) {
502
541
  recordDynamicFetchObservation(input);
503
542
  return dedupeFetch(input, init);
504
543
  }
505
- if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === false || nextOpts?.revalidate === 0) {
544
+ if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0) {
506
545
  const cleanInit = stripNextFromInit(init, cacheDirective);
507
- recordDynamicFetchObservation(input);
546
+ markUncachedFetchForPageOutput(input);
508
547
  return dedupeFetch(input, cleanInit);
509
548
  }
510
- if (!(cacheDirective === "force-cache" || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) && hasAuthHeaders(input, init)) {
549
+ if (!(cacheDirective === "force-cache" || nextOpts?.revalidate === false || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) && hasAuthHeaders(input, init)) {
511
550
  const cleanInit = stripNextFromInit(init, cacheDirective);
512
551
  recordDynamicFetchObservation(input);
513
552
  return dedupeFetch(input, cleanInit);
514
553
  }
515
554
  let revalidateSeconds;
516
- if (cacheDirective === "force-cache") revalidateSeconds = nextOpts?.revalidate && typeof nextOpts.revalidate === "number" ? nextOpts.revalidate : 31536e3;
555
+ if (cacheDirective === "force-cache") revalidateSeconds = nextOpts?.revalidate && typeof nextOpts.revalidate === "number" ? nextOpts.revalidate : ONE_YEAR_SECONDS;
556
+ else if (nextOpts?.revalidate === false) revalidateSeconds = ONE_YEAR_SECONDS;
517
557
  else if (typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) revalidateSeconds = nextOpts.revalidate;
518
- else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = 31536e3;
558
+ else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = ONE_YEAR_SECONDS;
519
559
  else {
520
560
  const cleanInit = stripNextFromInit(init, cacheDirective);
521
561
  recordDynamicFetchObservation(input);
@@ -550,10 +590,7 @@ function createPatchedFetch() {
550
590
  });
551
591
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState !== "stale") {
552
592
  const cachedData = cached.value.data;
553
- return new Response(cachedData.body, {
554
- status: cachedData.status ?? 200,
555
- headers: cachedData.headers
556
- });
593
+ return buildCachedFetchResponse(cachedData, input);
557
594
  }
558
595
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState === "stale") {
559
596
  const staleData = cached.value.data;
@@ -571,7 +608,7 @@ function createPatchedFetch() {
571
608
  data: {
572
609
  headers: freshHeaders,
573
610
  body: freshBody,
574
- url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
611
+ url: freshResp.url,
575
612
  status: freshResp.status
576
613
  },
577
614
  tags,
@@ -595,10 +632,7 @@ function createPatchedFetch() {
595
632
  }, DEDUP_TIMEOUT_MS);
596
633
  getRequestExecutionContext()?.waitUntil(refetchPromise);
597
634
  }
598
- return new Response(staleData.body, {
599
- status: staleData.status ?? 200,
600
- headers: staleData.headers
601
- });
635
+ return buildCachedFetchResponse(staleData, input);
602
636
  }
603
637
  } catch (cacheErr) {
604
638
  console.error("[vinext] fetch cache read error:", cacheErr);
@@ -617,7 +651,7 @@ function createPatchedFetch() {
617
651
  data: {
618
652
  headers,
619
653
  body,
620
- url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
654
+ url: response.url,
621
655
  status: cloned.status
622
656
  },
623
657
  tags,
@@ -690,6 +724,7 @@ async function runWithFetchCache(fn) {
690
724
  currentRequestTags: [],
691
725
  currentFetchSoftTags: [],
692
726
  currentFetchCacheMode: null,
727
+ currentForceDynamicFetchDefault: false,
693
728
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
694
729
  isFetchDedupeActive: true,
695
730
  currentFetchDedupeEntries: /* @__PURE__ */ new Map()
@@ -728,4 +763,4 @@ function getOriginalFetch() {
728
763
  return originalFetch;
729
764
  }
730
765
  //#endregion
731
- export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
766
+ export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
@@ -17,7 +17,12 @@ function scrollToHashTarget(hash) {
17
17
  idElement.scrollIntoView({ behavior: "auto" });
18
18
  return;
19
19
  }
20
- document.getElementsByName(fragment)[0]?.scrollIntoView({ behavior: "auto" });
20
+ const namedElement = document.getElementsByName(fragment)[0];
21
+ if (namedElement) {
22
+ namedElement.scrollIntoView({ behavior: "auto" });
23
+ return;
24
+ }
25
+ window.scrollTo(0, 0);
21
26
  }
22
27
  function scrollToHashTargetOnNextFrame(hash) {
23
28
  requestAnimationFrame(() => {
@@ -104,6 +104,10 @@ const SELF_CLOSING_HEAD_TAGS = new Set([
104
104
  ]);
105
105
  /** Tags whose content is raw text — closing-tag sequences must be escaped during SSR. */
106
106
  const RAW_CONTENT_TAGS = new Set(["script", "style"]);
107
+ const INLINE_CLOSE_TAG_RES = {
108
+ script: /<\/(script)/gi,
109
+ style: /<\/(style)/gi
110
+ };
107
111
  function warnDisallowedHeadTag(tag) {
108
112
  if (process.env.NODE_ENV !== "production") console.warn(`[vinext] <Head> ignoring disallowed tag <${tag}>. Only ${ALLOWED_HEAD_TAGS_LIST} are allowed.`);
109
113
  }
@@ -247,7 +251,8 @@ function escapeAttr(s) {
247
251
  * context but prevents the HTML parser from seeing a closing tag.
248
252
  */
249
253
  function escapeInlineContent(content, tag) {
250
- const pattern = new RegExp(`<\\/(${tag})`, "gi");
254
+ const pattern = INLINE_CLOSE_TAG_RES[tag];
255
+ if (!pattern) return content;
251
256
  return content.replace(pattern, "<\\/$1");
252
257
  }
253
258
  function getDangerouslySetInnerHTML(value) {
@@ -18,12 +18,24 @@ type HeadersAccessPhase = "render" | "action" | "route-handler";
18
18
  type VinextHeadersShimState = {
19
19
  headersContext: HeadersContext | null;
20
20
  dynamicUsageDetected: boolean;
21
- renderRequestApiUsage: Set<RenderRequestApiKind>; /** Error recorded by throwIfInsideCacheScope for dev diagnostics, persists even if caught by user code. */
21
+ renderRequestApiUsage: Set<RenderRequestApiKind>;
22
+ connectionProbe: ConnectionProbeState | null; /** Error recorded by throwIfInsideCacheScope for dev diagnostics, persists even if caught by user code. */
22
23
  invalidDynamicUsageError: unknown;
23
24
  pendingSetCookies: string[];
24
25
  draftModeCookieHeader: string | null;
25
26
  phase: HeadersAccessPhase;
26
27
  };
28
+ type ConnectionProbeState = {
29
+ interrupted: boolean;
30
+ interrupt: () => void;
31
+ pending: Promise<never>;
32
+ };
33
+ type ConnectionProbeResult<T> = {
34
+ completed: true;
35
+ result: T;
36
+ } | {
37
+ completed: false;
38
+ };
27
39
  /**
28
40
  * Dynamic usage flag — set when a component calls connection(), cookies(),
29
41
  * headers(), or noStore() during rendering. When true, ISR caching is
@@ -35,6 +47,8 @@ type VinextHeadersShimState = {
35
47
  */
36
48
  declare function markDynamicUsage(): void;
37
49
  declare function markRenderRequestApiUsage(kind: RenderRequestApiKind): void;
50
+ declare function runWithConnectionProbe<T>(fn: () => T | Promise<T>): Promise<ConnectionProbeResult<T>>;
51
+ declare function suspendConnectionProbe(): Promise<never> | null;
38
52
  declare function peekRenderRequestApiUsage(): RenderRequestApiKind[];
39
53
  declare function consumeRenderRequestApiUsage(): RenderRequestApiKind[];
40
54
  /**
@@ -236,4 +250,4 @@ declare class RequestCookies {
236
250
  toString(): string;
237
251
  }
238
252
  //#endregion
239
- export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, throwIfInsideCacheScope };
253
+ export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope };
@@ -3,7 +3,8 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
3
3
  import { MIDDLEWARE_SET_COOKIE_HEADER } from "../server/headers.js";
4
4
  import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
5
5
  import { serializeSetCookie, validateCookieAttributeValue, validateCookieName } from "./internal/cookie-serialize.js";
6
- import { parseCookieHeader } from "./internal/parse-cookie-header.js";
6
+ import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
7
+ import { createPprFallbackShellSuspensePromise } from "./ppr-fallback-shell.js";
7
8
  //#region src/shims/headers.ts
8
9
  /**
9
10
  * next/headers shim
@@ -21,6 +22,7 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
21
22
  headersContext: null,
22
23
  dynamicUsageDetected: false,
23
24
  renderRequestApiUsage: /* @__PURE__ */ new Set(),
25
+ connectionProbe: null,
24
26
  invalidDynamicUsageError: null,
25
27
  pendingSetCookies: [],
26
28
  draftModeCookieHeader: null,
@@ -80,7 +82,7 @@ function setCookieNameValue(setCookie) {
80
82
  function rebuildCookiesFromHeader(ctx, cookieHeader) {
81
83
  ctx.cookies.clear();
82
84
  if (cookieHeader === null) return;
83
- const nextCookies = parseCookieHeader(cookieHeader);
85
+ const nextCookies = parseEdgeRequestCookieHeader(cookieHeader);
84
86
  for (const [name, value] of nextCookies) ctx.cookies.set(name, value);
85
87
  }
86
88
  function mergeMiddlewareSetCookies(ctx, rawHeader) {
@@ -115,6 +117,39 @@ function markDynamicUsage() {
115
117
  function markRenderRequestApiUsage(kind) {
116
118
  _getState().renderRequestApiUsage.add(kind);
117
119
  }
120
+ async function runWithConnectionProbe(fn) {
121
+ const state = _getState();
122
+ const previousProbe = state.connectionProbe;
123
+ let interruptProbe = () => {};
124
+ const interrupted = new Promise((resolve) => {
125
+ interruptProbe = () => resolve({ completed: false });
126
+ });
127
+ const probe = {
128
+ interrupted: false,
129
+ interrupt() {
130
+ if (probe.interrupted) return;
131
+ probe.interrupted = true;
132
+ interruptProbe();
133
+ },
134
+ pending: new Promise(() => {})
135
+ };
136
+ state.connectionProbe = probe;
137
+ try {
138
+ const completed = Promise.resolve().then(fn).then((result) => ({
139
+ completed: true,
140
+ result
141
+ }));
142
+ return await Promise.race([completed, interrupted]);
143
+ } finally {
144
+ state.connectionProbe = previousProbe;
145
+ }
146
+ }
147
+ function suspendConnectionProbe() {
148
+ const probe = _getState().connectionProbe;
149
+ if (!probe) return null;
150
+ probe.interrupt();
151
+ return probe.pending;
152
+ }
118
153
  function peekRenderRequestApiUsage() {
119
154
  return [..._getState().renderRequestApiUsage].sort();
120
155
  }
@@ -260,6 +295,7 @@ function runWithHeadersContext(ctx, fn) {
260
295
  uCtx.headersContext = ctx;
261
296
  uCtx.dynamicUsageDetected = false;
262
297
  uCtx.renderRequestApiUsage = /* @__PURE__ */ new Set();
298
+ uCtx.connectionProbe = null;
263
299
  uCtx.pendingSetCookies = [];
264
300
  uCtx.draftModeCookieHeader = null;
265
301
  uCtx.phase = "render";
@@ -268,6 +304,7 @@ function runWithHeadersContext(ctx, fn) {
268
304
  headersContext: ctx,
269
305
  dynamicUsageDetected: false,
270
306
  renderRequestApiUsage: /* @__PURE__ */ new Set(),
307
+ connectionProbe: null,
271
308
  invalidDynamicUsageError: null,
272
309
  pendingSetCookies: [],
273
310
  draftModeCookieHeader: null,
@@ -378,6 +415,26 @@ function _decorateRejectedRequestApiPromise(error) {
378
415
  throw normalizedError;
379
416
  } }));
380
417
  }
418
+ function _decorateSuspendingRequestApiPromise(promise) {
419
+ return new Proxy(promise, {
420
+ get(promiseTarget, prop) {
421
+ if (prop === "then" || prop === "catch" || prop === "finally") {
422
+ const value = Reflect.get(promiseTarget, prop, promiseTarget);
423
+ return typeof value === "function" ? value.bind(promiseTarget) : value;
424
+ }
425
+ throw promise;
426
+ },
427
+ getOwnPropertyDescriptor() {
428
+ throw promise;
429
+ },
430
+ has() {
431
+ throw promise;
432
+ },
433
+ ownKeys() {
434
+ throw promise;
435
+ }
436
+ });
437
+ }
381
438
  function _sealHeaders(headers) {
382
439
  return new Proxy(headers, { get(target, prop) {
383
440
  if (typeof prop === "string" && _HEADERS_MUTATING_METHODS.has(prop)) throw new ReadonlyHeadersError();
@@ -449,7 +506,7 @@ function headersContextFromRequest(request, options) {
449
506
  let _cookies = null;
450
507
  function getCookies() {
451
508
  if (_cookies) return _cookies;
452
- _cookies = parseCookieHeader(headersProxy.get("cookie") || "");
509
+ _cookies = parseEdgeRequestCookieHeader(headersProxy.get("cookie") || "");
453
510
  return _cookies;
454
511
  }
455
512
  return {
@@ -476,6 +533,8 @@ function headers() {
476
533
  if (!state.headersContext) return _decorateRejectedRequestApiPromise(/* @__PURE__ */ new Error("headers() can only be called from a Server Component, Route Handler, or Server Action. Make sure you're not calling it from a Client Component."));
477
534
  if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
478
535
  markDynamicUsage();
536
+ const fallbackShellPromise = createPprFallbackShellSuspensePromise("`headers()`");
537
+ if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
479
538
  return _getOrCreateDecoratedRequestApiPromise(_decoratedHeadersPromises, _getReadonlyHeaders(state.headersContext));
480
539
  }
481
540
  /**
@@ -493,6 +552,8 @@ function cookies() {
493
552
  if (!state.headersContext) return _decorateRejectedRequestApiPromise(/* @__PURE__ */ new Error("cookies() can only be called from a Server Component, Route Handler, or Server Action."));
494
553
  if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
495
554
  markDynamicUsage();
555
+ const fallbackShellPromise = createPprFallbackShellSuspensePromise("`cookies()`");
556
+ if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
496
557
  return _getOrCreateDecoratedRequestApiPromise(_decoratedCookiesPromises, _areCookiesMutableInCurrentPhase() ? _getMutableCookies(state.headersContext) : _getReadonlyCookies(state.headersContext));
497
558
  }
498
559
  /** Accumulated Set-Cookie headers from cookies().set() / .delete() calls */
@@ -536,7 +597,7 @@ function ensureContextDraftModeSecret(ctx) {
536
597
  function isDraftModeRequest(request, draftModeSecret) {
537
598
  const cookieHeader = request.headers.get("cookie");
538
599
  if (!cookieHeader) return false;
539
- return parseCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
600
+ return parseEdgeRequestCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
540
601
  }
541
602
  function draftModeCookieAttributes() {
542
603
  if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return "Path=/; HttpOnly; SameSite=Lax";
@@ -690,4 +751,4 @@ var RequestCookies = class {
690
751
  }
691
752
  };
692
753
  //#endregion
693
- export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, throwIfInsideCacheScope };
754
+ export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope };
@@ -1,5 +1,6 @@
1
1
  import ipaddr from "ipaddr.js";
2
2
  //#region src/shims/image-config.ts
3
+ const globRegexCache = /* @__PURE__ */ new Map();
3
4
  /**
4
5
  * Convert a glob pattern (with `*` and `**`) to a RegExp.
5
6
  *
@@ -14,6 +15,9 @@ import ipaddr from "ipaddr.js";
14
15
  * Literal characters are escaped for regex safety.
15
16
  */
16
17
  function globToRegex(pattern, separator) {
18
+ const key = `${separator}\0${pattern}`;
19
+ const cached = globRegexCache.get(key);
20
+ if (cached !== void 0) return cached;
17
21
  let regexStr = "^";
18
22
  const doubleStar = separator === "." ? ".+" : ".*";
19
23
  const singleStar = separator === "." ? "[^.]+" : "[^/]+";
@@ -27,7 +31,9 @@ function globToRegex(pattern, separator) {
27
31
  }
28
32
  }
29
33
  regexStr += "$";
30
- return new RegExp(regexStr);
34
+ const re = new RegExp(regexStr);
35
+ globRegexCache.set(key, re);
36
+ return re;
31
37
  }
32
38
  /**
33
39
  * Check whether a URL matches a single remote pattern.
@@ -38,6 +38,33 @@ import { AsyncLocalStorage } from "node:async_hooks";
38
38
  */
39
39
  const _g = globalThis;
40
40
  /**
41
+ * No-op AsyncLocalStorage used when the runtime does not provide a usable
42
+ * `AsyncLocalStorage` constructor.
43
+ *
44
+ * In browser/client bundles `node:async_hooks` can resolve to a stub without a
45
+ * usable constructor (e.g. Vite's `__vite-browser-external`). Constructing such
46
+ * a value with `new` throws `TypeError: AsyncLocalStorage is not a constructor`
47
+ * at module-eval time, crashing every client-reachable shim that calls
48
+ * `getOrCreateAls` on import (request-context, headers, cache, …).
49
+ *
50
+ * Mirrors Next.js' `FakeAsyncLocalStorage` (and this repo's
51
+ * `async-hooks-stub.ts` client virtual module): `getStore()` returns
52
+ * `undefined` so shims fall back to their non-ALS code path, and the mutating
53
+ * methods are best-effort no-ops that still invoke the callback.
54
+ * See: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/async-local-storage.ts
55
+ */
56
+ var NoopAsyncLocalStorage = class {
57
+ getStore() {}
58
+ run(_store, fn, ...args) {
59
+ return fn(...args);
60
+ }
61
+ exit(fn, ...args) {
62
+ return fn(...args);
63
+ }
64
+ enterWith(_store) {}
65
+ disable() {}
66
+ };
67
+ /**
41
68
  * Get (or lazily create) the AsyncLocalStorage registered on `globalThis`
42
69
  * under `Symbol.for(key)`. Multiple callers — including callers in different
43
70
  * module instances — that pass the same `key` receive the same ALS instance.
@@ -47,7 +74,7 @@ const _g = globalThis;
47
74
  */
48
75
  function getOrCreateAls(key) {
49
76
  const sym = Symbol.for(key);
50
- return _g[sym] ??= new AsyncLocalStorage();
77
+ return _g[sym] ??= typeof AsyncLocalStorage === "function" ? new AsyncLocalStorage() : new NoopAsyncLocalStorage();
51
78
  }
52
79
  //#endregion
53
80
  export { getOrCreateAls };
@@ -27,9 +27,12 @@ declare function getPagesRouterComponentsMap(): PagesRouterComponentsMap;
27
27
  * Pages Router map when the href matches an App Router route. No-op when the
28
28
  * manifest is absent, the URL is external, or no app route matches.
29
29
  *
30
- * `pathname` is the basePath-stripped path — matching Next.js's
31
- * `router.components[urlPathname]` key (see the source link in this file's
32
- * leading comment).
30
+ * `pathname` is the basePath-stripped, trailing-slash-stripped path —
31
+ * matching Next.js's `removeTrailingSlash(removeBasePath(pathname))` key used
32
+ * at read time (router.ts:1442). Stripping here ensures the write and read
33
+ * keys agree regardless of whether the caller normalised trailing slashes
34
+ * first (e.g. `link.tsx` normalises to match `trailingSlash` config before
35
+ * calling, while `router.prefetch()` passes the raw user-supplied URL).
33
36
  */
34
37
  declare function markAppRouteDetectedOnPrefetch(href: string, basePath: string): void;
35
38
  //#endregion
@@ -1,7 +1,7 @@
1
- import { stripBasePath } from "../../utils/base-path.js";
2
- import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
1
+ import { removeTrailingSlash, stripBasePath } from "../../utils/base-path.js";
2
+ import { getLocalePathPrefix } from "../../utils/domain-locale.js";
3
+ import { resolveHybridClientRouteOwner } from "./hybrid-client-route-owner.js";
3
4
  //#region src/shims/internal/app-route-detection.ts
4
- const appRouteTrieCache = createRouteTrieCache();
5
5
  const _COMPONENTS_KEY = Symbol.for("vinext.pagesRouter.components");
6
6
  /**
7
7
  * Get-or-create the Pages Router `components` map. Returns the same object
@@ -32,35 +32,30 @@ function resolveSameOriginPathname(href, basePath) {
32
32
  return null;
33
33
  }
34
34
  if (url.origin !== window.location.origin) return null;
35
- return stripBasePath(url.pathname, basePath);
36
- }
37
- /**
38
- * Returns true when the prefetch href matches any route in the App Router
39
- * prefetch manifest (static or dynamic). Returns false when the manifest is
40
- * absent (Pages-Router-only build), the URL is external, or no route matches.
41
- */
42
- function matchesAppRoute(href, basePath) {
43
- if (typeof window === "undefined") return false;
44
- const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
45
- if (!routes || routes.length === 0) return false;
46
- const pathname = resolveSameOriginPathname(href, basePath);
47
- if (pathname === null) return false;
48
- return matchRouteWithTrie(pathname, routes, appRouteTrieCache) !== null;
35
+ const pathname = stripBasePath(url.pathname, basePath);
36
+ const locale = getLocalePathPrefix(pathname, window.__VINEXT_LOCALES__);
37
+ if (!locale) return pathname;
38
+ const localePrefixLength = locale.length + 1;
39
+ return pathname.length === localePrefixLength ? "/" : pathname.slice(localePrefixLength);
49
40
  }
50
41
  /**
51
42
  * Record `components[pathname] = { __appRouter: true }` on the shared
52
43
  * Pages Router map when the href matches an App Router route. No-op when the
53
44
  * manifest is absent, the URL is external, or no app route matches.
54
45
  *
55
- * `pathname` is the basePath-stripped path — matching Next.js's
56
- * `router.components[urlPathname]` key (see the source link in this file's
57
- * leading comment).
46
+ * `pathname` is the basePath-stripped, trailing-slash-stripped path —
47
+ * matching Next.js's `removeTrailingSlash(removeBasePath(pathname))` key used
48
+ * at read time (router.ts:1442). Stripping here ensures the write and read
49
+ * keys agree regardless of whether the caller normalised trailing slashes
50
+ * first (e.g. `link.tsx` normalises to match `trailingSlash` config before
51
+ * calling, while `router.prefetch()` passes the raw user-supplied URL).
58
52
  */
59
53
  function markAppRouteDetectedOnPrefetch(href, basePath) {
60
54
  if (typeof window === "undefined") return;
61
- if (!matchesAppRoute(href, basePath)) return;
62
- const pathname = resolveSameOriginPathname(href, basePath);
63
- if (pathname === null) return;
55
+ if (resolveHybridClientRouteOwner(href, basePath) !== "app") return;
56
+ const rawPathname = resolveSameOriginPathname(href, basePath);
57
+ if (rawPathname === null) return;
58
+ const pathname = removeTrailingSlash(rawPathname);
64
59
  getPagesRouterComponentsMap()[pathname] = { __appRouter: true };
65
60
  }
66
61
  //#endregion
@@ -16,6 +16,11 @@ type AppRouterInstance = {
16
16
  push(href: string, options?: NavigateOptions): void;
17
17
  replace(href: string, options?: NavigateOptions): void;
18
18
  prefetch(href: string, options?: PrefetchOptions): void;
19
+ /**
20
+ * Perform an experimental gesture transition navigation.
21
+ * Only available when experimental.gestureTransition is enabled.
22
+ */
23
+ experimental_gesturePush?(href: string, options?: NavigateOptions): void;
19
24
  };
20
25
  declare const AppRouterContext: React$1.Context<AppRouterInstance | null> | null;
21
26
  declare const GlobalLayoutRouterContext: React$1.Context<unknown> | null;
@@ -0,0 +1,31 @@
1
+ import { NextRewrite } from "../../config/next-config.js";
2
+ import { VinextLinkPrefetchRoute, VinextPagesLinkPrefetchRoute } from "../../client/vinext-next-data.js";
3
+
4
+ //#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
+ /**
18
+ * Decide which router should own a soft-navigated URL. Returns:
19
+ * - "app" → the App Router runtime handles the navigation (RSC fetch).
20
+ * - "pages" → Pages owns the URL; the caller must hard-navigate instead.
21
+ * - null → no router matched (preserves the existing 404 path).
22
+ *
23
+ * `basePath` must match what the page uses (typically `process.env.__NEXT_ROUTER_BASEPATH`).
24
+ *
25
+ * The lookup uses the App and Pages manifests on `window` so the same
26
+ * matcher trie produces the same result the server will see when the
27
+ * request lands.
28
+ */
29
+ declare function resolveHybridClientRouteOwner(href: string, basePath: string): HybridClientOwner | null;
30
+ //#endregion
31
+ export { HybridClientOwner, resolveHybridClientRouteOwner };