vinext 0.1.2 → 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 (199) hide show
  1. package/dist/build/prerender.d.ts +9 -1
  2. package/dist/build/prerender.js +41 -12
  3. package/dist/build/run-prerender.d.ts +10 -2
  4. package/dist/build/run-prerender.js +15 -1
  5. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  6. package/dist/client/app-nav-failure-handler.js +44 -0
  7. package/dist/client/vinext-next-data.d.ts +18 -1
  8. package/dist/client/window-next.d.ts +2 -1
  9. package/dist/client/window-next.js +12 -1
  10. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  11. package/dist/config/config-matchers.js +73 -14
  12. package/dist/config/next-config.d.ts +46 -4
  13. package/dist/config/next-config.js +147 -48
  14. package/dist/deploy.d.ts +30 -11
  15. package/dist/deploy.js +180 -99
  16. package/dist/entries/app-browser-entry.d.ts +9 -3
  17. package/dist/entries/app-browser-entry.js +21 -3
  18. package/dist/entries/app-rsc-entry.d.ts +2 -0
  19. package/dist/entries/app-rsc-entry.js +64 -5
  20. package/dist/entries/app-rsc-manifest.js +2 -0
  21. package/dist/entries/app-ssr-entry.js +1 -1
  22. package/dist/entries/pages-client-entry.js +53 -8
  23. package/dist/entries/pages-server-entry.js +41 -5
  24. package/dist/index.js +200 -62
  25. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  26. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  27. package/dist/plugins/optimize-imports.d.ts +2 -1
  28. package/dist/plugins/optimize-imports.js +11 -9
  29. package/dist/plugins/postcss.js +7 -7
  30. package/dist/plugins/typeof-window.d.ts +14 -0
  31. package/dist/plugins/typeof-window.js +150 -0
  32. package/dist/routing/app-route-graph.d.ts +2 -1
  33. package/dist/routing/app-route-graph.js +44 -14
  34. package/dist/routing/file-matcher.d.ts +10 -1
  35. package/dist/routing/file-matcher.js +22 -1
  36. package/dist/routing/pages-router.js +3 -3
  37. package/dist/routing/utils.d.ts +35 -6
  38. package/dist/routing/utils.js +59 -7
  39. package/dist/server/api-handler.d.ts +6 -1
  40. package/dist/server/api-handler.js +21 -15
  41. package/dist/server/app-browser-action-result.d.ts +19 -6
  42. package/dist/server/app-browser-action-result.js +19 -10
  43. package/dist/server/app-browser-entry.js +167 -90
  44. package/dist/server/app-browser-error.d.ts +10 -6
  45. package/dist/server/app-browser-error.js +43 -8
  46. package/dist/server/app-browser-hydration.d.ts +2 -0
  47. package/dist/server/app-browser-hydration.js +1 -0
  48. package/dist/server/app-browser-navigation-controller.d.ts +4 -2
  49. package/dist/server/app-browser-navigation-controller.js +23 -2
  50. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  51. package/dist/server/app-browser-server-action-navigation.js +9 -0
  52. package/dist/server/app-browser-stream.js +86 -43
  53. package/dist/server/app-elements-wire.d.ts +6 -1
  54. package/dist/server/app-elements-wire.js +14 -4
  55. package/dist/server/app-elements.d.ts +2 -2
  56. package/dist/server/app-elements.js +2 -2
  57. package/dist/server/app-fallback-renderer.d.ts +1 -0
  58. package/dist/server/app-fallback-renderer.js +3 -1
  59. package/dist/server/app-optimistic-routing.js +2 -2
  60. package/dist/server/app-page-boundary-render.d.ts +1 -0
  61. package/dist/server/app-page-boundary-render.js +27 -14
  62. package/dist/server/app-page-cache-render.d.ts +53 -0
  63. package/dist/server/app-page-cache-render.js +91 -0
  64. package/dist/server/app-page-cache.d.ts +16 -2
  65. package/dist/server/app-page-cache.js +62 -1
  66. package/dist/server/app-page-dispatch.d.ts +26 -0
  67. package/dist/server/app-page-dispatch.js +149 -92
  68. package/dist/server/app-page-element-builder.d.ts +1 -0
  69. package/dist/server/app-page-element-builder.js +5 -2
  70. package/dist/server/app-page-execution.d.ts +6 -1
  71. package/dist/server/app-page-execution.js +21 -1
  72. package/dist/server/app-page-probe.d.ts +1 -0
  73. package/dist/server/app-page-probe.js +4 -0
  74. package/dist/server/app-page-render-observation.d.ts +3 -1
  75. package/dist/server/app-page-render-observation.js +17 -1
  76. package/dist/server/app-page-render.d.ts +12 -1
  77. package/dist/server/app-page-render.js +42 -4
  78. package/dist/server/app-page-request.d.ts +2 -0
  79. package/dist/server/app-page-request.js +2 -1
  80. package/dist/server/app-page-route-wiring.d.ts +3 -1
  81. package/dist/server/app-page-route-wiring.js +14 -5
  82. package/dist/server/app-page-stream.d.ts +15 -3
  83. package/dist/server/app-page-stream.js +11 -5
  84. package/dist/server/app-pages-bridge.d.ts +18 -0
  85. package/dist/server/app-pages-bridge.js +22 -5
  86. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  87. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  88. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  89. package/dist/server/app-ppr-fallback-shell.js +8 -1
  90. package/dist/server/app-route-handler-dispatch.js +9 -2
  91. package/dist/server/app-route-handler-policy.d.ts +1 -0
  92. package/dist/server/app-router-entry.js +5 -0
  93. package/dist/server/app-rsc-cache-busting.js +2 -0
  94. package/dist/server/app-rsc-handler.d.ts +25 -0
  95. package/dist/server/app-rsc-handler.js +154 -54
  96. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  97. package/dist/server/app-rsc-route-matching.js +2 -0
  98. package/dist/server/app-segment-config.d.ts +9 -1
  99. package/dist/server/app-segment-config.js +12 -3
  100. package/dist/server/app-server-action-execution.d.ts +1 -0
  101. package/dist/server/app-server-action-execution.js +42 -13
  102. package/dist/server/app-ssr-entry.d.ts +2 -0
  103. package/dist/server/app-ssr-entry.js +83 -10
  104. package/dist/server/cache-control.js +4 -0
  105. package/dist/server/dev-server.d.ts +2 -2
  106. package/dist/server/dev-server.js +244 -51
  107. package/dist/server/hybrid-route-priority.d.ts +22 -0
  108. package/dist/server/hybrid-route-priority.js +33 -0
  109. package/dist/server/image-optimization.d.ts +18 -9
  110. package/dist/server/image-optimization.js +37 -23
  111. package/dist/server/implicit-tags.d.ts +2 -1
  112. package/dist/server/implicit-tags.js +4 -1
  113. package/dist/server/navigation-planner.d.ts +133 -30
  114. package/dist/server/navigation-planner.js +114 -0
  115. package/dist/server/navigation-trace.d.ts +8 -1
  116. package/dist/server/navigation-trace.js +8 -1
  117. package/dist/server/pages-api-route.d.ts +6 -0
  118. package/dist/server/pages-api-route.js +13 -2
  119. package/dist/server/pages-asset-tags.d.ts +2 -1
  120. package/dist/server/pages-asset-tags.js +6 -2
  121. package/dist/server/pages-data-route.d.ts +8 -1
  122. package/dist/server/pages-data-route.js +11 -2
  123. package/dist/server/pages-get-initial-props.d.ts +54 -4
  124. package/dist/server/pages-get-initial-props.js +43 -1
  125. package/dist/server/pages-node-compat.js +2 -2
  126. package/dist/server/pages-page-data.d.ts +11 -2
  127. package/dist/server/pages-page-data.js +204 -33
  128. package/dist/server/pages-page-handler.d.ts +4 -2
  129. package/dist/server/pages-page-handler.js +59 -22
  130. package/dist/server/pages-page-response.d.ts +2 -1
  131. package/dist/server/pages-page-response.js +7 -4
  132. package/dist/server/pages-request-pipeline.d.ts +1 -0
  133. package/dist/server/pages-request-pipeline.js +73 -36
  134. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  135. package/dist/server/pregenerated-concrete-paths.js +2 -19
  136. package/dist/server/prerender-manifest.d.ts +33 -0
  137. package/dist/server/prerender-manifest.js +54 -0
  138. package/dist/server/prerender-route-params.d.ts +1 -2
  139. package/dist/server/prod-server.js +9 -3
  140. package/dist/server/request-pipeline.d.ts +3 -15
  141. package/dist/server/request-pipeline.js +58 -47
  142. package/dist/server/rsc-stream-hints.d.ts +5 -1
  143. package/dist/server/rsc-stream-hints.js +6 -1
  144. package/dist/server/seed-cache.js +10 -18
  145. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  146. package/dist/shims/app-router-scroll-state.js +14 -2
  147. package/dist/shims/app-router-scroll.d.ts +3 -0
  148. package/dist/shims/app-router-scroll.js +28 -18
  149. package/dist/shims/cache-runtime.js +3 -2
  150. package/dist/shims/cache.d.ts +1 -0
  151. package/dist/shims/cache.js +1 -1
  152. package/dist/shims/cdn-cache.d.ts +5 -5
  153. package/dist/shims/dynamic-preload-chunks.js +6 -4
  154. package/dist/shims/error-boundary.d.ts +2 -0
  155. package/dist/shims/error-boundary.js +7 -0
  156. package/dist/shims/error.js +3 -2
  157. package/dist/shims/error.react-server.d.ts +9 -0
  158. package/dist/shims/error.react-server.js +6 -0
  159. package/dist/shims/fetch-cache.d.ts +3 -1
  160. package/dist/shims/fetch-cache.js +45 -20
  161. package/dist/shims/hash-scroll.js +6 -1
  162. package/dist/shims/headers.js +29 -4
  163. package/dist/shims/internal/als-registry.js +28 -1
  164. package/dist/shims/internal/app-route-detection.js +8 -17
  165. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  166. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  167. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  168. package/dist/shims/internal/navigation-untracked.js +55 -0
  169. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  170. package/dist/shims/internal/pages-data-target.js +17 -8
  171. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  172. package/dist/shims/internal/pages-router-accessor.js +13 -0
  173. package/dist/shims/internal/router-context.d.ts +2 -1
  174. package/dist/shims/internal/router-context.js +3 -1
  175. package/dist/shims/link.js +12 -5
  176. package/dist/shims/navigation.d.ts +8 -2
  177. package/dist/shims/navigation.js +61 -31
  178. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  179. package/dist/shims/ppr-fallback-shell.js +28 -7
  180. package/dist/shims/router.d.ts +13 -2
  181. package/dist/shims/router.js +419 -128
  182. package/dist/shims/server.d.ts +16 -1
  183. package/dist/shims/server.js +44 -12
  184. package/dist/shims/unified-request-context.js +1 -0
  185. package/dist/utils/built-asset-url.d.ts +4 -0
  186. package/dist/utils/built-asset-url.js +11 -0
  187. package/dist/utils/commonjs-loader.d.ts +16 -0
  188. package/dist/utils/commonjs-loader.js +100 -0
  189. package/dist/utils/deployment-id.d.ts +8 -0
  190. package/dist/utils/deployment-id.js +22 -0
  191. package/dist/utils/html-limited-bots.d.ts +18 -1
  192. package/dist/utils/html-limited-bots.js +23 -1
  193. package/dist/utils/parse-cookie.d.ts +13 -0
  194. package/dist/utils/parse-cookie.js +52 -0
  195. package/dist/utils/path.d.ts +7 -1
  196. package/dist/utils/path.js +9 -1
  197. package/package.json +2 -2
  198. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  199. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -0,0 +1,9 @@
1
+ //#region src/shims/error.react-server.d.ts
2
+ type ErrorInfo = {
3
+ error: unknown;
4
+ reset: () => void;
5
+ unstable_retry: () => void;
6
+ };
7
+ declare function unstable_catchError(): never;
8
+ //#endregion
9
+ export { ErrorInfo, unstable_catchError };
@@ -0,0 +1,6 @@
1
+ //#region src/shims/error.react-server.ts
2
+ function unstable_catchError() {
3
+ throw new Error("`unstable_catchError` can only be used in Client Components.");
4
+ }
5
+ //#endregion
6
+ export { unstable_catchError };
@@ -40,6 +40,7 @@ type FetchCacheState = {
40
40
  currentRequestTags: string[];
41
41
  currentFetchSoftTags: string[];
42
42
  currentFetchCacheMode: FetchCacheMode | null;
43
+ currentForceDynamicFetchDefault: boolean;
43
44
  dynamicFetchUrls: Set<string>;
44
45
  isFetchDedupeActive: boolean;
45
46
  currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
@@ -84,6 +85,7 @@ declare function setCurrentFetchSoftTags(tags: string[]): void;
84
85
  */
85
86
  declare function getCurrentFetchSoftTags(): string[];
86
87
  declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
88
+ declare function setCurrentForceDynamicFetchDefault(enabled: boolean): void;
87
89
  /**
88
90
  * Install the patched fetch and reset per-request tag state.
89
91
  * Returns a cleanup function that clears tags.
@@ -131,4 +133,4 @@ declare function ensureFetchPatch(): void;
131
133
  */
132
134
  declare function getOriginalFetch(): typeof globalThis.fetch;
133
135
  //#endregion
134
- export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
136
+ export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
@@ -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
  }
@@ -382,16 +390,23 @@ function getCurrentFetchSoftTags() {
382
390
  function setCurrentFetchCacheMode(mode) {
383
391
  _getState().currentFetchCacheMode = mode;
384
392
  }
393
+ function setCurrentForceDynamicFetchDefault(enabled) {
394
+ _getState().currentForceDynamicFetchDefault = enabled;
395
+ }
385
396
  function isNoStoreFetch(cacheDirective, nextOpts) {
386
- return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === false || nextOpts?.revalidate === 0;
397
+ return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0;
387
398
  }
388
399
  function isCacheableFetch(cacheDirective, nextOpts) {
389
- 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;
390
401
  }
391
402
  function hasExplicitRevalidateValue(nextOpts) {
392
403
  return nextOpts?.revalidate !== void 0;
393
404
  }
394
- 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";
395
410
  if (!mode || mode === "auto") return cacheDirective;
396
411
  switch (mode) {
397
412
  case "force-cache": return "force-cache";
@@ -457,6 +472,20 @@ function cloneDedupeResponse(response) {
457
472
  const [body1, body2] = response.body.tee();
458
473
  return [buildDedupeClone(body1, response), buildDedupeClone(body2, response)];
459
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
+ }
460
489
  function dedupeFetch(input, init) {
461
490
  const state = _getState();
462
491
  if (!state.isFetchDedupeActive) return originalFetch(input, init);
@@ -507,25 +536,26 @@ function dedupeFetch(input, init) {
507
536
  function createPatchedFetch() {
508
537
  return async function patchedFetch(input, init) {
509
538
  const nextOpts = init?.next;
510
- const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode);
539
+ const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode, _getState().currentForceDynamicFetchDefault);
511
540
  if (!nextOpts && !cacheDirective) {
512
541
  recordDynamicFetchObservation(input);
513
542
  return dedupeFetch(input, init);
514
543
  }
515
- if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === false || nextOpts?.revalidate === 0) {
544
+ if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0) {
516
545
  const cleanInit = stripNextFromInit(init, cacheDirective);
517
- recordDynamicFetchObservation(input);
546
+ markUncachedFetchForPageOutput(input);
518
547
  return dedupeFetch(input, cleanInit);
519
548
  }
520
- 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)) {
521
550
  const cleanInit = stripNextFromInit(init, cacheDirective);
522
551
  recordDynamicFetchObservation(input);
523
552
  return dedupeFetch(input, cleanInit);
524
553
  }
525
554
  let revalidateSeconds;
526
- 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;
527
557
  else if (typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) revalidateSeconds = nextOpts.revalidate;
528
- else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = 31536e3;
558
+ else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = ONE_YEAR_SECONDS;
529
559
  else {
530
560
  const cleanInit = stripNextFromInit(init, cacheDirective);
531
561
  recordDynamicFetchObservation(input);
@@ -560,10 +590,7 @@ function createPatchedFetch() {
560
590
  });
561
591
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState !== "stale") {
562
592
  const cachedData = cached.value.data;
563
- return new Response(cachedData.body, {
564
- status: cachedData.status ?? 200,
565
- headers: cachedData.headers
566
- });
593
+ return buildCachedFetchResponse(cachedData, input);
567
594
  }
568
595
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState === "stale") {
569
596
  const staleData = cached.value.data;
@@ -581,7 +608,7 @@ function createPatchedFetch() {
581
608
  data: {
582
609
  headers: freshHeaders,
583
610
  body: freshBody,
584
- url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
611
+ url: freshResp.url,
585
612
  status: freshResp.status
586
613
  },
587
614
  tags,
@@ -605,10 +632,7 @@ function createPatchedFetch() {
605
632
  }, DEDUP_TIMEOUT_MS);
606
633
  getRequestExecutionContext()?.waitUntil(refetchPromise);
607
634
  }
608
- return new Response(staleData.body, {
609
- status: staleData.status ?? 200,
610
- headers: staleData.headers
611
- });
635
+ return buildCachedFetchResponse(staleData, input);
612
636
  }
613
637
  } catch (cacheErr) {
614
638
  console.error("[vinext] fetch cache read error:", cacheErr);
@@ -627,7 +651,7 @@ function createPatchedFetch() {
627
651
  data: {
628
652
  headers,
629
653
  body,
630
- url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
654
+ url: response.url,
631
655
  status: cloned.status
632
656
  },
633
657
  tags,
@@ -700,6 +724,7 @@ async function runWithFetchCache(fn) {
700
724
  currentRequestTags: [],
701
725
  currentFetchSoftTags: [],
702
726
  currentFetchCacheMode: null,
727
+ currentForceDynamicFetchDefault: false,
703
728
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
704
729
  isFetchDedupeActive: true,
705
730
  currentFetchDedupeEntries: /* @__PURE__ */ new Map()
@@ -738,4 +763,4 @@ function getOriginalFetch() {
738
763
  return originalFetch;
739
764
  }
740
765
  //#endregion
741
- export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, 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(() => {
@@ -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
@@ -81,7 +82,7 @@ function setCookieNameValue(setCookie) {
81
82
  function rebuildCookiesFromHeader(ctx, cookieHeader) {
82
83
  ctx.cookies.clear();
83
84
  if (cookieHeader === null) return;
84
- const nextCookies = parseCookieHeader(cookieHeader);
85
+ const nextCookies = parseEdgeRequestCookieHeader(cookieHeader);
85
86
  for (const [name, value] of nextCookies) ctx.cookies.set(name, value);
86
87
  }
87
88
  function mergeMiddlewareSetCookies(ctx, rawHeader) {
@@ -414,6 +415,26 @@ function _decorateRejectedRequestApiPromise(error) {
414
415
  throw normalizedError;
415
416
  } }));
416
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
+ }
417
438
  function _sealHeaders(headers) {
418
439
  return new Proxy(headers, { get(target, prop) {
419
440
  if (typeof prop === "string" && _HEADERS_MUTATING_METHODS.has(prop)) throw new ReadonlyHeadersError();
@@ -485,7 +506,7 @@ function headersContextFromRequest(request, options) {
485
506
  let _cookies = null;
486
507
  function getCookies() {
487
508
  if (_cookies) return _cookies;
488
- _cookies = parseCookieHeader(headersProxy.get("cookie") || "");
509
+ _cookies = parseEdgeRequestCookieHeader(headersProxy.get("cookie") || "");
489
510
  return _cookies;
490
511
  }
491
512
  return {
@@ -512,6 +533,8 @@ function headers() {
512
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."));
513
534
  if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
514
535
  markDynamicUsage();
536
+ const fallbackShellPromise = createPprFallbackShellSuspensePromise("`headers()`");
537
+ if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
515
538
  return _getOrCreateDecoratedRequestApiPromise(_decoratedHeadersPromises, _getReadonlyHeaders(state.headersContext));
516
539
  }
517
540
  /**
@@ -529,6 +552,8 @@ function cookies() {
529
552
  if (!state.headersContext) return _decorateRejectedRequestApiPromise(/* @__PURE__ */ new Error("cookies() can only be called from a Server Component, Route Handler, or Server Action."));
530
553
  if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
531
554
  markDynamicUsage();
555
+ const fallbackShellPromise = createPprFallbackShellSuspensePromise("`cookies()`");
556
+ if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
532
557
  return _getOrCreateDecoratedRequestApiPromise(_decoratedCookiesPromises, _areCookiesMutableInCurrentPhase() ? _getMutableCookies(state.headersContext) : _getReadonlyCookies(state.headersContext));
533
558
  }
534
559
  /** Accumulated Set-Cookie headers from cookies().set() / .delete() calls */
@@ -572,7 +597,7 @@ function ensureContextDraftModeSecret(ctx) {
572
597
  function isDraftModeRequest(request, draftModeSecret) {
573
598
  const cookieHeader = request.headers.get("cookie");
574
599
  if (!cookieHeader) return false;
575
- return parseCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
600
+ return parseEdgeRequestCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
576
601
  }
577
602
  function draftModeCookieAttributes() {
578
603
  if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return "Path=/; HttpOnly; SameSite=Lax";
@@ -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 };
@@ -1,7 +1,7 @@
1
1
  import { removeTrailingSlash, stripBasePath } from "../../utils/base-path.js";
2
- import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.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,20 +32,11 @@ 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
@@ -61,7 +52,7 @@ function matchesAppRoute(href, basePath) {
61
52
  */
62
53
  function markAppRouteDetectedOnPrefetch(href, basePath) {
63
54
  if (typeof window === "undefined") return;
64
- if (!matchesAppRoute(href, basePath)) return;
55
+ if (resolveHybridClientRouteOwner(href, basePath) !== "app") return;
65
56
  const rawPathname = resolveSameOriginPathname(href, basePath);
66
57
  if (rawPathname === null) return;
67
58
  const pathname = removeTrailingSlash(rawPathname);
@@ -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 };
@@ -0,0 +1,143 @@
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 { isExternalUrl, matchRewrite, parseCookies } from "../../config/config-matchers.js";
5
+ import { getLocalePathPrefix } from "../../utils/domain-locale.js";
6
+ import { mergeRewriteQuery } from "../../utils/query.js";
7
+ //#region src/shims/internal/hybrid-client-route-owner.ts
8
+ /**
9
+ * Client-side resolver that decides whether a URL should be soft-navigated
10
+ * (App Router / RSC) or hard-navigated (Pages Router / document). Delegates
11
+ * the owner decision to `compareHybridRoutePatterns` in `routing/utils.ts`
12
+ * so the server and the client reach the same answer for the same
13
+ * (pages pattern, app pattern) pair.
14
+ *
15
+ * Lives in `shims/internal/` because both `link.tsx` and the App Router
16
+ * browser entry import it without pulling in the server route graph.
17
+ *
18
+ * The App + Pages route manifests are emitted once per page load by the
19
+ * Vite plugin onto the matching `__VINEXT_*_PREFETCH_ROUTES__` window
20
+ * globals (see `entries/app-browser-entry.ts` and
21
+ * `entries/pages-client-entry.ts`). Hybrid builds expose both globals; a
22
+ * single-router build only sets its own.
23
+ */
24
+ function resolveClientRewrite(href, basePath, rewrites, continueAfterMatch = false) {
25
+ const initialUrl = new URL(href, window.location.href);
26
+ const basePathState = {
27
+ basePath,
28
+ hadBasePath: basePath ? initialUrl.pathname === basePath || initialUrl.pathname.startsWith(`${basePath}/`) : true
29
+ };
30
+ let currentHref = href;
31
+ let matched = false;
32
+ for (const rewrite of rewrites) {
33
+ const pathname = resolveSameOriginPathname(currentHref, basePath);
34
+ if (pathname === null) return null;
35
+ const url = new URL(currentHref, window.location.href);
36
+ const headers = new Headers({ "user-agent": globalThis.navigator?.userAgent ?? "" });
37
+ const context = {
38
+ cookies: parseCookies(globalThis.document?.cookie ?? ""),
39
+ headers,
40
+ host: url.hostname,
41
+ query: url.searchParams
42
+ };
43
+ const rewritten = matchRewrite(pathname, [rewrite], context, basePathState);
44
+ if (rewritten === null) continue;
45
+ if (isExternalUrl(rewritten)) return { kind: "document" };
46
+ currentHref = mergeRewriteQuery(currentHref, rewritten);
47
+ matched = true;
48
+ if (!continueAfterMatch) break;
49
+ }
50
+ return matched ? {
51
+ href: currentHref,
52
+ kind: "rewrite"
53
+ } : null;
54
+ }
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
+ /**
95
+ * Decide which router should own a soft-navigated URL. Returns:
96
+ * - "app" → the App Router runtime handles the navigation (RSC fetch).
97
+ * - "pages" → Pages owns the URL; the caller must hard-navigate instead.
98
+ * - null → no router matched (preserves the existing 404 path).
99
+ *
100
+ * `basePath` must match what the page uses (typically `process.env.__NEXT_ROUTER_BASEPATH`).
101
+ *
102
+ * The lookup uses the App and Pages manifests on `window` so the same
103
+ * matcher trie produces the same result the server will see when the
104
+ * request lands.
105
+ */
106
+ function resolveHybridClientRouteOwner(href, basePath) {
107
+ if (typeof window === "undefined") return null;
108
+ const appRoutes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
109
+ const pagesRoutes = window.__VINEXT_PAGES_LINK_PREFETCH_ROUTES__;
110
+ const rewrites = window.__VINEXT_CLIENT_REWRITES__;
111
+ if (rewrites) {
112
+ const beforeFilesRewrite = resolveClientRewrite(href, basePath, rewrites.beforeFiles, true);
113
+ if (beforeFilesRewrite?.kind === "document") return "document";
114
+ if (beforeFilesRewrite?.kind === "rewrite") href = beforeFilesRewrite.href;
115
+ }
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) {
119
+ const afterFilesRewrite = resolveClientRewrite(href, basePath, [rewrite]);
120
+ if (afterFilesRewrite?.kind === "document") return "document";
121
+ if (afterFilesRewrite?.kind !== "rewrite") continue;
122
+ href = afterFilesRewrite.href;
123
+ appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
124
+ pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
125
+ if (appMatch || pagesMatch) break;
126
+ }
127
+ if (rewrites && appMatch === null && pagesMatch === null) for (const rewrite of rewrites.fallback) {
128
+ const fallbackRewrite = resolveClientRewrite(href, basePath, [rewrite]);
129
+ if (fallbackRewrite?.kind === "document") return "document";
130
+ if (fallbackRewrite?.kind !== "rewrite") continue;
131
+ href = fallbackRewrite.href;
132
+ appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
133
+ pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
134
+ if (appMatch || pagesMatch) break;
135
+ }
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;
141
+ }
142
+ //#endregion
143
+ export { resolveHybridClientRouteOwner };
@@ -0,0 +1,35 @@
1
+ //#region src/shims/internal/navigation-untracked.d.ts
2
+ /**
3
+ * Internal navigation-untracked pathname hook.
4
+ *
5
+ * Used by `unstable_catchError` error boundaries to avoid subscribing to
6
+ * pathname changes. This is NOT part of the public `next/navigation` API.
7
+ *
8
+ * Ported from Next.js:
9
+ * https://github.com/vercel/next.js/blob/v16.2.6/packages/next/src/client/components/navigation-untracked.ts
10
+ */
11
+ /**
12
+ * Returns the current pathname without registering it as a tracked render
13
+ * dependency. Unlike `usePathname()`, this does not use `useSyncExternalStore`
14
+ * and therefore does not cause the component to re-render on navigation.
15
+ *
16
+ * Server: returns the pathname from context, or `"/"` when no navigation context
17
+ * is available (the client will hydrate with the real value). The `"/"` fallback
18
+ * deliberately matches vinext's `usePathname()` behavior rather than Next.js's
19
+ * null context default. Returns `null` only when the render is a missing-params
20
+ * shell — vinext does not yet implement fallback-route-param detection, so this
21
+ * path is not currently reachable.
22
+ *
23
+ * Client: prefers the render snapshot **only during an active navigation**
24
+ * transition (`navigationSnapshotActiveCount > 0`) so the hook returns the
25
+ * pending URL, not the stale committed one. After commit, falls back to the
26
+ * cached pathname so user `pushState`/`replaceState` calls are immediately
27
+ * reflected.
28
+ *
29
+ * Used by `unstable_catchError` error boundaries to avoid unnecessary re-renders.
30
+ *
31
+ * @internal
32
+ */
33
+ declare function useUntrackedPathname(): string | null;
34
+ //#endregion
35
+ export { useUntrackedPathname };