vinext 0.2.0 → 0.2.1

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 (128) hide show
  1. package/dist/build/css-url-assets.d.ts +3 -1
  2. package/dist/build/css-url-assets.js +18 -1
  3. package/dist/build/inject-pregenerated-paths.d.ts +3 -0
  4. package/dist/build/inject-pregenerated-paths.js +4 -1
  5. package/dist/build/prerender-server-entry.d.ts +1 -0
  6. package/dist/build/prerender-server-entry.js +49 -0
  7. package/dist/build/prerender-server-pool.d.ts +44 -0
  8. package/dist/build/prerender-server-pool.js +194 -0
  9. package/dist/build/prerender.js +86 -22
  10. package/dist/build/run-prerender.js +2 -1
  11. package/dist/check.d.ts +4 -6
  12. package/dist/check.js +8 -9
  13. package/dist/cli.js +1 -1
  14. package/dist/client/vinext-next-data.d.ts +4 -1
  15. package/dist/config/config-matchers.js +33 -11
  16. package/dist/config/next-config.d.ts +36 -6
  17. package/dist/config/next-config.js +16 -2
  18. package/dist/entries/app-browser-entry.js +5 -1
  19. package/dist/entries/app-rsc-entry.d.ts +3 -2
  20. package/dist/entries/app-rsc-entry.js +4 -0
  21. package/dist/entries/pages-client-entry.js +14 -3
  22. package/dist/entries/pages-server-entry.js +18 -4
  23. package/dist/index.js +320 -25
  24. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
  25. package/dist/packages/cloudflare/src/deploy.js +1 -5
  26. package/dist/packages/cloudflare/src/tpr.js +26 -5
  27. package/dist/plugins/fonts.js +1 -1
  28. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  29. package/dist/plugins/og-assets.js +2 -1
  30. package/dist/plugins/optimize-imports.js +1 -1
  31. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  32. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  33. package/dist/plugins/sass.d.ts +17 -1
  34. package/dist/plugins/sass.js +74 -1
  35. package/dist/plugins/styled-jsx.d.ts +16 -0
  36. package/dist/plugins/styled-jsx.js +149 -0
  37. package/dist/routing/app-route-graph.js +22 -16
  38. package/dist/routing/file-matcher.d.ts +8 -1
  39. package/dist/routing/file-matcher.js +15 -3
  40. package/dist/server/app-browser-entry.js +46 -14
  41. package/dist/server/app-browser-navigation-controller.js +1 -1
  42. package/dist/server/app-browser-server-action-client.js +5 -3
  43. package/dist/server/app-browser-state.d.ts +1 -0
  44. package/dist/server/app-browser-state.js +2 -2
  45. package/dist/server/app-browser-visible-commit.js +1 -1
  46. package/dist/server/app-page-boundary.js +2 -1
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +3 -3
  49. package/dist/server/app-page-cache.js +23 -6
  50. package/dist/server/app-page-dispatch.d.ts +1 -0
  51. package/dist/server/app-page-dispatch.js +25 -8
  52. package/dist/server/app-page-element-builder.js +1 -0
  53. package/dist/server/app-page-execution.js +2 -1
  54. package/dist/server/app-page-render-identity.d.ts +1 -0
  55. package/dist/server/app-page-render-identity.js +2 -1
  56. package/dist/server/app-page-render.d.ts +2 -0
  57. package/dist/server/app-page-render.js +67 -16
  58. package/dist/server/app-page-response.d.ts +7 -0
  59. package/dist/server/app-page-response.js +16 -4
  60. package/dist/server/app-page-stream.d.ts +2 -1
  61. package/dist/server/app-page-stream.js +1 -1
  62. package/dist/server/app-route-handler-execution.js +1 -1
  63. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  64. package/dist/server/app-route-tree-prefetch.js +187 -0
  65. package/dist/server/app-router-entry.js +1 -1
  66. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  67. package/dist/server/app-rsc-cache-busting.js +9 -4
  68. package/dist/server/app-rsc-handler.d.ts +6 -0
  69. package/dist/server/app-rsc-handler.js +89 -11
  70. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  71. package/dist/server/app-rsc-render-mode.js +4 -1
  72. package/dist/server/app-rsc-request-normalization.d.ts +3 -4
  73. package/dist/server/app-rsc-request-normalization.js +4 -5
  74. package/dist/server/app-server-action-execution.js +4 -3
  75. package/dist/server/app-ssr-entry.js +3 -3
  76. package/dist/server/cache-control.d.ts +3 -1
  77. package/dist/server/cache-control.js +13 -1
  78. package/dist/server/dev-server.d.ts +11 -1
  79. package/dist/server/dev-server.js +78 -20
  80. package/dist/server/headers.d.ts +6 -2
  81. package/dist/server/headers.js +11 -5
  82. package/dist/server/isr-cache.d.ts +2 -1
  83. package/dist/server/isr-cache.js +7 -3
  84. package/dist/server/pages-data-route.d.ts +4 -2
  85. package/dist/server/pages-data-route.js +18 -4
  86. package/dist/server/pages-dev-module-url.d.ts +2 -1
  87. package/dist/server/pages-dev-module-url.js +6 -3
  88. package/dist/server/pages-node-compat.d.ts +12 -1
  89. package/dist/server/pages-node-compat.js +50 -1
  90. package/dist/server/pages-page-data.d.ts +9 -0
  91. package/dist/server/pages-page-data.js +17 -9
  92. package/dist/server/pages-page-handler.js +19 -7
  93. package/dist/server/pages-page-response.d.ts +1 -0
  94. package/dist/server/pages-page-response.js +3 -2
  95. package/dist/server/pages-request-pipeline.d.ts +8 -6
  96. package/dist/server/pages-request-pipeline.js +30 -6
  97. package/dist/server/pages-router-entry.js +1 -1
  98. package/dist/server/prod-server.d.ts +4 -2
  99. package/dist/server/prod-server.js +38 -22
  100. package/dist/server/request-pipeline.js +1 -1
  101. package/dist/shims/cache-handler.js +8 -1
  102. package/dist/shims/cache.js +3 -0
  103. package/dist/shims/fetch-cache.d.ts +3 -1
  104. package/dist/shims/fetch-cache.js +77 -52
  105. package/dist/shims/form.d.ts +1 -1
  106. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  107. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  108. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
  109. package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
  110. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
  111. package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
  112. package/dist/shims/internal/pages-data-target.d.ts +8 -3
  113. package/dist/shims/internal/pages-data-target.js +9 -4
  114. package/dist/shims/link.d.ts +1 -1
  115. package/dist/shims/link.js +179 -42
  116. package/dist/shims/navigation.d.ts +15 -3
  117. package/dist/shims/navigation.js +202 -39
  118. package/dist/shims/navigation.react-server.js +1 -1
  119. package/dist/shims/request-context.js +18 -0
  120. package/dist/shims/router.js +31 -15
  121. package/dist/shims/unified-request-context.js +1 -0
  122. package/dist/typegen.js +1 -1
  123. package/dist/utils/middleware-request-headers.js +1 -1
  124. package/dist/utils/protocol-headers.d.ts +7 -1
  125. package/dist/utils/protocol-headers.js +7 -1
  126. package/dist/utils/vite-version.d.ts +2 -0
  127. package/dist/utils/vite-version.js +11 -1
  128. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
- import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER } from "../server/headers.js";
2
+ import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "../server/headers.js";
3
3
  import { assertSafeNavigationUrl } from "./url-safety.js";
4
4
  import { AppElementsWire } from "../server/app-elements-wire.js";
5
5
  import "../server/app-elements.js";
@@ -12,7 +12,7 @@ import { BailoutToCSRError, DynamicServerError, HTTP_ERROR_FALLBACK_ERROR_CODE,
12
12
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
13
13
  import { clearAppNavigationFailureTarget, stageAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
14
14
  import { beginAppRouterScrollIntent, clearAppRouterScrollIntent, consumeAppRouterScrollIntent, getPendingAppRouterScrollIntent } from "./app-router-scroll-state.js";
15
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createRscRequestHeaders, createRscRequestUrl, stripRscCacheBustingSearchParam } from "../server/app-rsc-cache-busting.js";
15
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createRscRequestHeaders, createRscRequestUrl, stripRscCacheBustingSearchParam, stripRscSuffix } from "../server/app-rsc-cache-busting.js";
16
16
  import { getNavigationRuntime, hasAppNavigationRuntime } from "../client/navigation-runtime.js";
17
17
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
18
18
  import { PUBLIC_INITIAL_BFCACHE_ID } from "../server/app-bfcache-id.js";
@@ -23,6 +23,7 @@ import { navigationPlanner } from "../server/navigation-planner.js";
23
23
  import { ReadonlyURLSearchParams } from "./readonly-url-search-params.js";
24
24
  import { getPagesNavigationContext } from "./internal/pages-router-accessor.js";
25
25
  import { resolveHybridClientRouteOwner } from "./internal/hybrid-client-route-owner.js";
26
+ import { releaseAppPrefetchFetchSlot, scheduleAppPrefetchFetch } from "./internal/app-prefetch-fetch-queue.js";
26
27
  import { UnrecognizedActionError, unstable_isUnrecognizedActionError } from "./unrecognized-action-error.js";
27
28
  import * as React$1 from "react";
28
29
  //#region src/shims/navigation.ts
@@ -54,8 +55,9 @@ const PAGES_NAVIGATION_NOTIFY_KEY = Symbol.for("vinext.navigation.pagesNavigatio
54
55
  const isServer = typeof window === "undefined";
55
56
  /** basePath from next.config.js, injected by the plugin at build time */
56
57
  const __basePath = process.env.__NEXT_ROUTER_BASEPATH ?? "";
57
- /** Maximum number of entries in the RSC prefetch cache. */
58
- const MAX_PREFETCH_CACHE_SIZE = 50;
58
+ /** Maximum buffered bytes in the RSC prefetch cache. Mirrors Next.js' 50 MB LRU. */
59
+ const MAX_PREFETCH_CACHE_SIZE = 50 * 1024 * 1024;
60
+ const PREFETCH_CACHE_EVICTION_TARGET_SIZE = MAX_PREFETCH_CACHE_SIZE * .9;
59
61
  /**
60
62
  * TTL for prefetch cache entries in ms.
61
63
  *
@@ -161,6 +163,13 @@ function normalizeRscCacheLookupUrl(rscUrl) {
161
163
  return null;
162
164
  }
163
165
  }
166
+ function normalizeRscCacheLookupPathname(rscUrl) {
167
+ try {
168
+ return stripRscSuffix(new URL(rscUrl, "http://vinext.local").pathname);
169
+ } catch {
170
+ return null;
171
+ }
172
+ }
164
173
  function parsePrefetchCacheKey(cacheKey) {
165
174
  const separatorIndex = cacheKey.indexOf("\0");
166
175
  if (separatorIndex === -1) return {
@@ -176,22 +185,25 @@ function isPrefetchCacheEntryCompatibleWithMountedSlots(entry, mountedSlotsHeade
176
185
  if (resolvePrefetchCacheEntryMountedSlotsHeader(entry) === mountedSlotsHeader) return true;
177
186
  return (entry.snapshot?.mountedSlotsHeader ?? null) === mountedSlotsHeader;
178
187
  }
179
- function findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader) {
180
- const exactCacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
188
+ function findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader, additionalRscUrls = []) {
181
189
  const cache = getPrefetchCache();
182
- const exactEntry = cache.get(exactCacheKey);
183
- if (exactEntry && exactEntry.cacheForNavigation !== false && isPrefetchCacheEntryCompatibleWithMountedSlots(exactEntry, mountedSlotsHeader)) return {
184
- cacheKey: exactCacheKey,
185
- entry: exactEntry
186
- };
187
- const normalizedTarget = normalizeRscCacheLookupUrl(rscUrl);
188
- if (normalizedTarget === null) return null;
190
+ const rscUrls = [rscUrl, ...additionalRscUrls];
191
+ for (const lookupRscUrl of rscUrls) {
192
+ const exactCacheKey = AppElementsWire.encodeCacheKey(lookupRscUrl, interceptionContext);
193
+ const exactEntry = cache.get(exactCacheKey);
194
+ if (exactEntry && exactEntry.cacheForNavigation !== false && isPrefetchCacheEntryCompatibleWithMountedSlots(exactEntry, mountedSlotsHeader)) return {
195
+ cacheKey: exactCacheKey,
196
+ entry: exactEntry
197
+ };
198
+ }
199
+ const normalizedTargets = new Set(rscUrls.map((lookupRscUrl) => normalizeRscCacheLookupUrl(lookupRscUrl)).filter((lookupRscUrl) => lookupRscUrl !== null));
200
+ if (normalizedTargets.size === 0) return null;
189
201
  for (const [cacheKey, entry] of cache) {
190
- if (cacheKey === exactCacheKey) continue;
191
202
  if (entry.cacheForNavigation === false) continue;
192
203
  const source = parsePrefetchCacheKey(cacheKey);
193
204
  if (source.interceptionContext !== interceptionContext) continue;
194
- if (normalizeRscCacheLookupUrl(source.rscUrl) !== normalizedTarget) continue;
205
+ const normalizedSource = normalizeRscCacheLookupUrl(source.rscUrl);
206
+ if (normalizedSource === null || !normalizedTargets.has(normalizedSource)) continue;
195
207
  if (!isPrefetchCacheEntryCompatibleWithMountedSlots(entry, mountedSlotsHeader)) continue;
196
208
  return {
197
209
  cacheKey,
@@ -201,31 +213,100 @@ function findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mounte
201
213
  return null;
202
214
  }
203
215
  function hasPrefetchCacheEntryForNavigation(rscUrl, interceptionContext = null, mountedSlotsHeader = null, options = {}) {
204
- const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader);
216
+ const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader, options.additionalRscUrls);
205
217
  if (match === null) return false;
206
- if (match.entry.pending !== void 0) return true;
207
- if (resolvePrefetchCacheEntryExpiresAt(match.entry) > Date.now()) return true;
218
+ if (match.entry.pending !== void 0) {
219
+ touchPrefetchCacheEntry(getPrefetchCache(), match.cacheKey, match.entry);
220
+ return true;
221
+ }
222
+ if (resolvePrefetchCacheEntryExpiresAt(match.entry) > Date.now()) {
223
+ touchPrefetchCacheEntry(getPrefetchCache(), match.cacheKey, match.entry);
224
+ return true;
225
+ }
208
226
  deletePrefetchCacheEntry(getPrefetchCache(), getPrefetchedUrls(), match.cacheKey, match.entry, options.notifyInvalidation ?? true);
209
227
  return false;
210
228
  }
229
+ function hasSearchAgnosticPrefetchShellForRoute(rscUrl, interceptionContext = null, mountedSlotsHeader = null) {
230
+ const normalizedTargetPathname = normalizeRscCacheLookupPathname(rscUrl);
231
+ if (normalizedTargetPathname === null) return false;
232
+ const cache = getPrefetchCache();
233
+ for (const [cacheKey, entry] of cache) {
234
+ if (entry.searchAgnosticShell !== true) continue;
235
+ const source = parsePrefetchCacheKey(cacheKey);
236
+ if (source.interceptionContext !== interceptionContext) continue;
237
+ if (normalizeRscCacheLookupPathname(source.rscUrl) !== normalizedTargetPathname) continue;
238
+ if (!isPrefetchCacheEntryCompatibleWithMountedSlots(entry, mountedSlotsHeader)) continue;
239
+ if (entry.pending !== void 0) return true;
240
+ if (resolvePrefetchCacheEntryExpiresAt(entry) > Date.now()) return true;
241
+ deletePrefetchCacheEntry(cache, getPrefetchedUrls(), cacheKey, entry, true);
242
+ }
243
+ return false;
244
+ }
245
+ function getPrefetchCacheEntrySize(entry) {
246
+ return entry.snapshot?.buffer.byteLength ?? entry.size ?? 0;
247
+ }
248
+ let trackedPrefetchCache = null;
249
+ let trackedPrefetchCacheByteSize = 0;
250
+ function getPrefetchCacheByteSize(cache) {
251
+ if (trackedPrefetchCache === cache) return trackedPrefetchCacheByteSize;
252
+ let total = 0;
253
+ const seen = /* @__PURE__ */ new Set();
254
+ for (const entry of cache.values()) {
255
+ if (seen.has(entry)) continue;
256
+ seen.add(entry);
257
+ total += getPrefetchCacheEntrySize(entry);
258
+ }
259
+ trackedPrefetchCache = cache;
260
+ trackedPrefetchCacheByteSize = total;
261
+ return total;
262
+ }
263
+ function adjustPrefetchCacheByteSize(cache, delta) {
264
+ if (trackedPrefetchCache !== cache) return;
265
+ trackedPrefetchCacheByteSize = Math.max(0, trackedPrefetchCacheByteSize + delta);
266
+ }
267
+ function touchPrefetchCacheEntry(cache, cacheKey, entry) {
268
+ if (cache.get(cacheKey) !== entry) return;
269
+ cache.delete(cacheKey);
270
+ cache.set(cacheKey, entry);
271
+ for (const key of entry.cacheKeys ?? []) {
272
+ if (key === cacheKey || cache.get(key) !== entry) continue;
273
+ cache.delete(key);
274
+ cache.set(key, entry);
275
+ }
276
+ }
211
277
  /**
212
- * Evict prefetch cache entries if at capacity.
213
- * First sweeps expired entries, then falls back to FIFO eviction.
278
+ * Evict prefetch cache entries if buffered payloads exceed the byte budget.
279
+ * Sweeps expired entries only after the cheap byte-budget check says cleanup is
280
+ * needed, then evicts least-recently-used entries down to the target size.
214
281
  */
215
282
  function evictPrefetchCacheIfNeeded() {
216
283
  const cache = getPrefetchCache();
217
- if (cache.size < 50) return;
284
+ let totalSize = getPrefetchCacheByteSize(cache);
285
+ if (totalSize <= 52428800) return;
218
286
  const now = Date.now();
219
287
  const prefetched = getPrefetchedUrls();
220
288
  for (const [key, entry] of cache) if (resolvePrefetchCacheEntryExpiresAt(entry) <= now) deletePrefetchCacheEntry(cache, prefetched, key, entry, true);
221
- while (cache.size >= 50) {
289
+ totalSize = getPrefetchCacheByteSize(cache);
290
+ if (totalSize <= 52428800) return;
291
+ let inspectedEntries = 0;
292
+ while (totalSize > PREFETCH_CACHE_EVICTION_TARGET_SIZE && inspectedEntries < cache.size) {
222
293
  const oldest = cache.keys().next().value;
223
294
  if (oldest !== void 0) {
224
295
  const entry = cache.get(oldest);
225
- if (entry) deletePrefetchCacheEntry(cache, prefetched, oldest, entry, true);
226
- else {
296
+ if (entry) {
297
+ const entrySize = getPrefetchCacheEntrySize(entry);
298
+ if (entry.pending !== void 0 && entrySize === 0) {
299
+ touchPrefetchCacheEntry(cache, oldest, entry);
300
+ inspectedEntries += 1;
301
+ continue;
302
+ }
303
+ totalSize -= entrySize;
304
+ deletePrefetchCacheEntry(cache, prefetched, oldest, entry, true);
305
+ inspectedEntries = 0;
306
+ } else {
227
307
  cache.delete(oldest);
228
308
  prefetched.delete(oldest);
309
+ inspectedEntries += 1;
229
310
  }
230
311
  } else break;
231
312
  }
@@ -249,8 +330,13 @@ function notifyPrefetchInvalidated(entry) {
249
330
  }
250
331
  }
251
332
  function deletePrefetchCacheEntry(cache, prefetched, cacheKey, entry, notify) {
252
- cache.delete(cacheKey);
253
- prefetched.delete(cacheKey);
333
+ adjustPrefetchCacheByteSize(cache, -getPrefetchCacheEntrySize(entry));
334
+ const cacheKeys = entry.cacheKeys ?? new Set([cacheKey]);
335
+ for (const key of cacheKeys) {
336
+ if (cache.get(key) === entry) cache.delete(key);
337
+ prefetched.delete(key);
338
+ }
339
+ entry.cacheKeys = void 0;
254
340
  if (notify) notifyPrefetchInvalidated(entry);
255
341
  else {
256
342
  clearPrefetchInvalidation(entry);
@@ -295,19 +381,22 @@ function seedPrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext = nu
295
381
  const cache = getPrefetchCache();
296
382
  const existing = cache.get(cacheKey);
297
383
  if (existing) deletePrefetchCacheEntry(cache, getPrefetchedUrls(), cacheKey, existing, false);
298
- evictPrefetchCacheIfNeeded();
299
384
  const timestamp = Date.now();
300
385
  const entry = {
301
386
  cacheForNavigation: true,
387
+ cacheKeys: new Set([cacheKey]),
302
388
  expiresAt: resolveCachedRscResponseExpiresAt(timestamp, snapshot, fallbackTtlMs),
303
389
  mountedSlotsHeader,
304
390
  outcome: "cache-seeded",
391
+ size: snapshot.buffer.byteLength,
305
392
  snapshot,
306
393
  timestamp
307
394
  };
308
395
  cache.set(cacheKey, entry);
396
+ adjustPrefetchCacheByteSize(cache, snapshot.buffer.byteLength);
309
397
  getPrefetchedUrls().add(cacheKey);
310
398
  schedulePrefetchInvalidation(cacheKey, entry);
399
+ evictPrefetchCacheIfNeeded();
311
400
  }
312
401
  function deletePrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext = null) {
313
402
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
@@ -334,27 +423,37 @@ function deletePrefetchResponseSnapshot(rscUrl, snapshot, interceptionContext =
334
423
  */
335
424
  function storePrefetchResponse(rscUrl, response, interceptionContext = null, options) {
336
425
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
337
- evictPrefetchCacheIfNeeded();
426
+ const cache = getPrefetchCache();
427
+ const prefetched = getPrefetchedUrls();
428
+ const existing = cache.get(cacheKey);
429
+ if (existing) deletePrefetchCacheEntry(cache, prefetched, cacheKey, existing, false);
338
430
  const entry = {
431
+ cacheKeys: new Set([cacheKey]),
339
432
  mountedSlotsHeader: null,
340
433
  outcome: "pending",
341
434
  timestamp: Date.now()
342
435
  };
343
436
  addPrefetchInvalidationCallback(entry, options?.onInvalidate);
344
437
  entry.pending = snapshotRscResponse(response).then((snapshot) => {
438
+ if (cache.get(cacheKey) !== entry) return;
439
+ const previousSize = getPrefetchCacheEntrySize(entry);
345
440
  entry.mountedSlotsHeader = snapshot.mountedSlotsHeader ?? null;
346
441
  entry.snapshot = snapshot;
442
+ entry.size = snapshot.buffer.byteLength;
443
+ adjustPrefetchCacheByteSize(cache, entry.size - previousSize);
347
444
  entry.expiresAt = resolveCachedRscResponseExpiresAt(entry.timestamp, snapshot, PREFETCH_CACHE_TTL);
445
+ evictPrefetchCacheIfNeeded();
348
446
  }).catch(() => {
349
- deletePrefetchCacheEntry(getPrefetchCache(), getPrefetchedUrls(), cacheKey, entry, false);
447
+ deletePrefetchCacheEntry(cache, prefetched, cacheKey, entry, false);
350
448
  }).finally(() => {
449
+ if (cache.get(cacheKey) !== entry) return;
351
450
  entry.pending = void 0;
352
451
  if (entry.snapshot) {
353
452
  entry.outcome = "cache-seeded";
354
453
  schedulePrefetchInvalidation(cacheKey, entry);
355
454
  }
356
455
  });
357
- getPrefetchCache().set(cacheKey, entry);
456
+ cache.set(cacheKey, entry);
358
457
  }
359
458
  function createCachedRscResponseSnapshot(response, buffer, responseUrl = null) {
360
459
  const dynamicStaleTimeSeconds = parseDynamicStaleTimeSeconds(response.headers.get(VINEXT_DYNAMIC_STALE_TIME_HEADER));
@@ -365,15 +464,29 @@ function createCachedRscResponseSnapshot(response, buffer, responseUrl = null) {
365
464
  ...dynamicStaleTimeSeconds !== void 0 ? { dynamicStaleTimeSeconds } : {},
366
465
  mountedSlotsHeader: response.headers.get(VINEXT_MOUNTED_SLOTS_HEADER),
367
466
  paramsHeader: response.headers.get(VINEXT_PARAMS_HEADER),
467
+ renderedPathAndSearch: parseRenderedPathAndSearchHeader(response.headers.get(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER)),
368
468
  url: responseUrl ?? response.url
369
469
  };
370
470
  }
471
+ function parseRenderedPathAndSearchHeader(value) {
472
+ if (value === null || value === "") return null;
473
+ try {
474
+ const decoded = decodeURIComponent(value);
475
+ return decoded.startsWith("/") ? decoded : null;
476
+ } catch {
477
+ return null;
478
+ }
479
+ }
371
480
  /**
372
481
  * Snapshot an RSC response to an ArrayBuffer for caching and replay.
373
482
  * Consumes the response body and stores it with content-type and URL metadata.
374
483
  */
375
484
  async function snapshotRscResponse(response) {
376
- return createCachedRscResponseSnapshot(response, await response.arrayBuffer());
485
+ try {
486
+ return createCachedRscResponseSnapshot(response, await response.arrayBuffer());
487
+ } finally {
488
+ releaseAppPrefetchFetchSlot(response);
489
+ }
377
490
  }
378
491
  /**
379
492
  * Reconstruct a Response from a cached RSC snapshot.
@@ -396,6 +509,7 @@ function restoreRscResponse(cached, copy = true) {
396
509
  if (cached.compatibilityIdHeader != null) headers.set(VINEXT_RSC_COMPATIBILITY_ID_HEADER, cached.compatibilityIdHeader);
397
510
  if (isDynamicStaleTimeSeconds(cached.dynamicStaleTimeSeconds)) headers.set(VINEXT_DYNAMIC_STALE_TIME_HEADER, String(cached.dynamicStaleTimeSeconds));
398
511
  if (cached.paramsHeader != null) headers.set(VINEXT_PARAMS_HEADER, cached.paramsHeader);
512
+ if (cached.renderedPathAndSearch != null) headers.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(cached.renderedPathAndSearch));
399
513
  return new Response(copy ? cached.buffer.slice(0) : cached.buffer, {
400
514
  status: 200,
401
515
  headers
@@ -413,22 +527,38 @@ function prefetchRscResponse(rscUrl, fetchPromise, interceptionContext = null, m
413
527
  const cache = getPrefetchCache();
414
528
  const prefetched = getPrefetchedUrls();
415
529
  const now = Date.now();
530
+ const existing = cache.get(cacheKey);
531
+ if (existing) deletePrefetchCacheEntry(cache, prefetched, cacheKey, existing, false);
416
532
  const entry = {
417
533
  cacheForNavigation: behavior.cacheForNavigation ?? true,
534
+ cacheKeys: new Set([cacheKey]),
418
535
  mountedSlotsHeader,
419
536
  optimisticRouteShell: behavior.optimisticRouteShell === true,
420
537
  outcome: "pending",
538
+ prefetchKind: behavior.prefetchKind ?? (behavior.optimisticRouteShell === true ? "loading-shell" : "navigation"),
539
+ searchAgnosticShell: behavior.searchAgnosticShell === true,
421
540
  timestamp: now
422
541
  };
423
542
  addPrefetchInvalidationCallback(entry, options?.onInvalidate);
424
543
  entry.pending = fetchPromise.then(async (response) => {
425
544
  if (response.ok) {
426
- entry.snapshot = await snapshotRscResponse(response);
545
+ const snapshot = await snapshotRscResponse(response);
546
+ if (cache.get(cacheKey) !== entry) return;
547
+ const previousSize = getPrefetchCacheEntrySize(entry);
548
+ entry.snapshot = snapshot;
549
+ entry.size = snapshot.buffer.byteLength;
550
+ adjustPrefetchCacheByteSize(cache, entry.size - previousSize);
427
551
  entry.expiresAt = resolvePrefetchedRscResponseExpiresAt(entry.timestamp, entry.snapshot, behavior.fallbackTtlMs ?? PREFETCH_CACHE_TTL);
428
- } else deletePrefetchCacheEntry(cache, prefetched, cacheKey, entry, false);
552
+ addRenderedPathAndSearchPrefetchAlias(cache, prefetched, cacheKey, entry);
553
+ evictPrefetchCacheIfNeeded();
554
+ } else {
555
+ releaseAppPrefetchFetchSlot(response);
556
+ deletePrefetchCacheEntry(cache, prefetched, cacheKey, entry, false);
557
+ }
429
558
  }).catch(() => {
430
559
  deletePrefetchCacheEntry(cache, prefetched, cacheKey, entry, false);
431
560
  }).finally(() => {
561
+ if (cache.get(cacheKey) !== entry) return;
432
562
  entry.pending = void 0;
433
563
  if (entry.snapshot) {
434
564
  entry.outcome = "cache-seeded";
@@ -438,6 +568,36 @@ function prefetchRscResponse(rscUrl, fetchPromise, interceptionContext = null, m
438
568
  cache.set(cacheKey, entry);
439
569
  evictPrefetchCacheIfNeeded();
440
570
  }
571
+ function addRenderedPathAndSearchPrefetchAlias(cache, prefetched, primaryCacheKey, entry) {
572
+ if (entry.cacheForNavigation === false) return;
573
+ const renderedPathAndSearch = entry.snapshot?.renderedPathAndSearch;
574
+ if (!renderedPathAndSearch) return;
575
+ const source = parsePrefetchCacheKey(primaryCacheKey);
576
+ const aliasCacheKey = AppElementsWire.encodeCacheKey(renderedPathAndSearch, source.interceptionContext);
577
+ if (aliasCacheKey === primaryCacheKey) return;
578
+ const existing = cache.get(aliasCacheKey);
579
+ if (existing && existing !== entry) deletePrefetchCacheEntry(cache, prefetched, aliasCacheKey, existing, false);
580
+ entry.cacheKeys ??= new Set([primaryCacheKey]);
581
+ entry.cacheKeys.add(aliasCacheKey);
582
+ cache.set(aliasCacheKey, entry);
583
+ prefetched.add(aliasCacheKey);
584
+ }
585
+ function peekPrefetchResponseForNavigation(rscUrl, interceptionContext = null, mountedSlotsHeader = null) {
586
+ const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader);
587
+ if (!match) return null;
588
+ const { cacheKey, entry } = match;
589
+ if (entry.pending || entry.outcome !== "cache-seeded") return null;
590
+ if (entry.cacheForNavigation === false || !entry.snapshot) return null;
591
+ if (resolvePrefetchCacheEntryExpiresAt(entry) <= Date.now()) {
592
+ deletePrefetchCacheEntry(getPrefetchCache(), getPrefetchedUrls(), cacheKey, entry, true);
593
+ return null;
594
+ }
595
+ if (entry.expiresAt !== void 0 || entry.snapshot.expiresAt !== void 0) return {
596
+ ...entry.snapshot,
597
+ expiresAt: resolvePrefetchCacheEntryExpiresAt(entry)
598
+ };
599
+ return entry.snapshot;
600
+ }
441
601
  /**
442
602
  * Consume a prefetched response for a given rscUrl.
443
603
  * Only returns settled (non-pending) snapshots synchronously.
@@ -451,9 +611,12 @@ function consumePrefetchResponse(rscUrl, interceptionContext = null, mountedSlot
451
611
  const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader);
452
612
  if (!match) return null;
453
613
  const { cacheKey, entry } = match;
614
+ return consumeMatchedPrefetchResponse(cacheKey, entry, mountedSlotsHeader);
615
+ }
616
+ function consumeMatchedPrefetchResponse(cacheKey, entry, mountedSlotsHeader) {
454
617
  if (entry.pending || entry.outcome !== "cache-seeded") return null;
455
618
  if (entry.cacheForNavigation === false) return null;
456
- deletePrefetchCacheEntry(cache, getPrefetchedUrls(), cacheKey, entry, false);
619
+ deletePrefetchCacheEntry(getPrefetchCache(), getPrefetchedUrls(), cacheKey, entry, false);
457
620
  if (entry.snapshot) {
458
621
  if (!isPrefetchCacheEntryCompatibleWithMountedSlots(entry, mountedSlotsHeader)) return null;
459
622
  if (resolvePrefetchCacheEntryExpiresAt(entry) <= Date.now()) return null;
@@ -467,7 +630,7 @@ function consumePrefetchResponse(rscUrl, interceptionContext = null, mountedSlot
467
630
  }
468
631
  async function consumePrefetchResponseForNavigation(rscUrl, interceptionContext = null, mountedSlotsHeader = null, options) {
469
632
  const cache = getPrefetchCache();
470
- const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader);
633
+ const match = findPrefetchCacheEntryForNavigation(rscUrl, interceptionContext, mountedSlotsHeader, options?.additionalRscUrls);
471
634
  if (!match) return null;
472
635
  const { cacheKey, entry } = match;
473
636
  if (entry.pending !== void 0) {
@@ -475,7 +638,7 @@ async function consumePrefetchResponseForNavigation(rscUrl, interceptionContext
475
638
  if (cache.get(cacheKey) !== entry) return null;
476
639
  }
477
640
  if (options?.shouldConsume?.() === false) return null;
478
- return consumePrefetchResponse(rscUrl, interceptionContext, mountedSlotsHeader);
641
+ return consumeMatchedPrefetchResponse(cacheKey, entry, mountedSlotsHeader);
479
642
  }
480
643
  const _CLIENT_NAV_STATE_KEY = Symbol.for("vinext.clientNavigationState");
481
644
  const _MOUNTED_SLOTS_HEADER_KEY = Symbol.for("vinext.mountedSlotsHeader");
@@ -1095,11 +1258,11 @@ const _appRouter = {
1095
1258
  return;
1096
1259
  }
1097
1260
  prefetched.add(cacheKey);
1098
- prefetchRscResponse(rscUrl, fetch(rscUrl, {
1261
+ prefetchRscResponse(rscUrl, scheduleAppPrefetchFetch(() => fetch(rscUrl, {
1099
1262
  headers,
1100
1263
  credentials: "include",
1101
1264
  priority: "low"
1102
- }), interceptionContext, mountedSlotsHeader, options);
1265
+ }), "low"), interceptionContext, mountedSlotsHeader, options);
1103
1266
  })().catch((error) => {
1104
1267
  console.error("[vinext] RSC prefetch setup error:", error);
1105
1268
  });
@@ -1238,4 +1401,4 @@ if (!isServer) {
1238
1401
  }
1239
1402
  }
1240
1403
  //#endregion
1241
- export { BailoutToCSRError, DYNAMIC_NAVIGATION_CACHE_TTL, DynamicServerError, GLOBAL_ACCESSORS_KEY, HTTP_ERROR_FALLBACK_ERROR_CODE, MAX_PREFETCH_CACHE_SIZE, PREFETCH_CACHE_TTL, ReadonlyURLSearchParams, RedirectType, ServerInsertedHTMLContext, UnrecognizedActionError, __basePath, _registerStateAccessors, activateNavigationSnapshot, appRouterInstance, applyAppRouterScrollFallback, clearPendingPathname, clearServerInsertedHTML, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, deletePrefetchResponseSnapshot, flushServerInsertedHTML, forbidden, getAccessFallbackHTTPStatus, getBfcacheIdMapContext, getBfcacheSegmentIdContext, getClientNavigationRenderContext, getClientNavigationState, getClientParams, getCurrentInterceptionContext, getCurrentNextUrl, getLayoutSegmentContext, getMountedSlotsHeader, getNavigationContext, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, isBailoutToCSRError, isDynamicServerError, isHTTPAccessFallbackError, isNextRouterError, isRedirectError, navigateClientSide, notFound, permanentRedirect, prefetchRscResponse, pushHistoryStateWithoutNotify, redirect, renderServerInsertedHTML, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveCachedRscResponseExpiresAt, resolveCachedRscResponseTtlMs, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, snapshotRscResponse, storePrefetchResponse, unauthorized, unstable_isUnrecognizedActionError, unstable_rethrow, useClientNavigationRenderSnapshot, useParams, usePathname, useRouter, useSearchParams, useSelectedLayoutSegment, useSelectedLayoutSegments, useServerInsertedHTML };
1404
+ export { BailoutToCSRError, DYNAMIC_NAVIGATION_CACHE_TTL, DynamicServerError, GLOBAL_ACCESSORS_KEY, HTTP_ERROR_FALLBACK_ERROR_CODE, MAX_PREFETCH_CACHE_SIZE, PREFETCH_CACHE_TTL, ReadonlyURLSearchParams, RedirectType, ServerInsertedHTMLContext, UnrecognizedActionError, __basePath, _registerStateAccessors, activateNavigationSnapshot, appRouterInstance, applyAppRouterScrollFallback, clearPendingPathname, clearServerInsertedHTML, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, deletePrefetchResponseSnapshot, flushServerInsertedHTML, forbidden, getAccessFallbackHTTPStatus, getBfcacheIdMapContext, getBfcacheSegmentIdContext, getClientNavigationRenderContext, getClientNavigationState, getClientParams, getCurrentInterceptionContext, getCurrentNextUrl, getLayoutSegmentContext, getMountedSlotsHeader, getNavigationContext, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, hasSearchAgnosticPrefetchShellForRoute, invalidatePrefetchCache, isBailoutToCSRError, isDynamicServerError, isHTTPAccessFallbackError, isNextRouterError, isRedirectError, navigateClientSide, notFound, peekPrefetchResponseForNavigation, permanentRedirect, prefetchRscResponse, pushHistoryStateWithoutNotify, redirect, renderServerInsertedHTML, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveCachedRscResponseExpiresAt, resolveCachedRscResponseTtlMs, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, snapshotRscResponse, storePrefetchResponse, unauthorized, unstable_isUnrecognizedActionError, unstable_rethrow, useClientNavigationRenderSnapshot, useParams, usePathname, useRouter, useSearchParams, useSelectedLayoutSegment, useSelectedLayoutSegments, useServerInsertedHTML };
@@ -1,8 +1,8 @@
1
1
  import { GLOBAL_ACCESSORS_KEY, ServerInsertedHTMLContext, _registerStateAccessors, clearServerInsertedHTML, flushServerInsertedHTML, getLayoutSegmentContext, getNavigationContext, renderServerInsertedHTML, setNavigationContext } from "./navigation-context-state.js";
2
2
  import { BailoutToCSRError, DynamicServerError, HTTP_ERROR_FALLBACK_ERROR_CODE, RedirectType, forbidden, getAccessFallbackHTTPStatus, isBailoutToCSRError, isDynamicServerError, isHTTPAccessFallbackError, isNextRouterError, isRedirectError, notFound, permanentRedirect, redirect, unauthorized, unstable_rethrow } from "./navigation-errors.js";
3
3
  import "./navigation-server.js";
4
- import { ReadonlyURLSearchParams } from "./readonly-url-search-params.js";
5
4
  import { throwClientHookError } from "./client-hook-error.js";
5
+ import { ReadonlyURLSearchParams } from "./readonly-url-search-params.js";
6
6
  //#region src/shims/navigation.react-server.ts
7
7
  function usePathname() {
8
8
  throwClientHookError("usePathname()");
@@ -24,6 +24,24 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
24
24
  * ctx?.waitUntil(somePromise);
25
25
  */
26
26
  const _als = getOrCreateAls("vinext.requestContext.als");
27
+ const OPEN_NEXT_CLOUDFLARE_CONTEXT_SYMBOL = Symbol.for("__cloudflare-context__");
28
+ let openNextCloudflareContextFallback;
29
+ function installOpenNextCloudflareContextBridge() {
30
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, OPEN_NEXT_CLOUDFLARE_CONTEXT_SYMBOL);
31
+ if (descriptor && !descriptor.configurable) return;
32
+ openNextCloudflareContextFallback = descriptor && "value" in descriptor ? descriptor.value : descriptor?.get?.call(globalThis);
33
+ Object.defineProperty(globalThis, OPEN_NEXT_CLOUDFLARE_CONTEXT_SYMBOL, {
34
+ configurable: true,
35
+ get() {
36
+ const ctx = getRequestExecutionContext();
37
+ return ctx ? { ctx } : openNextCloudflareContextFallback;
38
+ },
39
+ set(value) {
40
+ openNextCloudflareContextFallback = value;
41
+ }
42
+ });
43
+ }
44
+ installOpenNextCloudflareContextBridge();
27
45
  function runWithExecutionContext(ctx, fn) {
28
46
  if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((uCtx) => {
29
47
  uCtx.executionContext = ctx;
@@ -22,7 +22,7 @@ import { scrollToHashTarget } from "./hash-scroll.js";
22
22
  import { installPagesRouterRuntime, setPagesRouterPopStateHandler, setStampInitialHistoryState } from "./pages-router-runtime.js";
23
23
  import { interpolateDynamicRouteHref } from "./internal/interpolate-as.js";
24
24
  import { getCurrentBrowserLocale } from "./client-locale.js";
25
- import { Component, Fragment, createElement, useContext, useEffect, useLayoutEffect, useMemo, useState } from "react";
25
+ import { Component, Fragment, StrictMode, createElement, useContext, useEffect, useLayoutEffect, useMemo, useState } from "react";
26
26
  //#region src/shims/router.ts
27
27
  /**
28
28
  * next/router shim
@@ -1002,8 +1002,11 @@ async function resolveClientConfigRewrite(href) {
1002
1002
  kind: "rewrite"
1003
1003
  } : null;
1004
1004
  }
1005
- function getMiddlewarePagesDataFetchUrl(browserUrl) {
1006
- return getPagesMiddlewareDataHref(browserUrl, __basePath);
1005
+ function getMiddlewarePagesDataFetchUrl(browserUrl, dataTarget) {
1006
+ const middlewareDataHref = getPagesMiddlewareDataHref(browserUrl, __basePath);
1007
+ if (!middlewareDataHref) return null;
1008
+ if (dataTarget?.dataKind === "static" && dataTarget.middlewareDataHref === middlewareDataHref && dataTarget.prefetchDataHref) return dataTarget.prefetchDataHref;
1009
+ return middlewareDataHref;
1007
1010
  }
1008
1011
  function getPagesDataCacheHref(dataHref) {
1009
1012
  try {
@@ -1015,8 +1018,8 @@ function getPagesDataCacheHref(dataHref) {
1015
1018
  function shouldEvictMiddlewareDataCache(middlewareEffect, dataTarget) {
1016
1019
  return middlewareEffect?.redirectLocation != null || dataTarget?.dataKind !== "static";
1017
1020
  }
1018
- async function resolveMiddlewareDataEffect(browserUrl, signal) {
1019
- const dataUrl = getMiddlewarePagesDataFetchUrl(browserUrl);
1021
+ async function resolveMiddlewareDataEffect(browserUrl, signal, dataTarget) {
1022
+ const dataUrl = getMiddlewarePagesDataFetchUrl(browserUrl, dataTarget);
1020
1023
  if (!dataUrl) return null;
1021
1024
  if (signal.aborted) throw new DOMException("Aborted", "AbortError");
1022
1025
  try {
@@ -1209,14 +1212,18 @@ async function navigateClientData(url, initialTarget, controller, navId, assertS
1209
1212
  await navigateClientHtml(redirectedUrl, redirectedUrl, controller, navId, assertStillCurrent);
1210
1213
  return;
1211
1214
  }
1212
- if (!res.ok) scheduleHardNavigationAndThrow(url, `Data navigation failed: ${res.status} ${res.statusText}`);
1215
+ if (!res.ok) {
1216
+ if (options.isHydrationQueryUpdate) return;
1217
+ scheduleHardNavigationAndThrow(url, `Data navigation failed: ${res.status} ${res.statusText}`);
1218
+ }
1213
1219
  const rewriteTarget = res.headers.get("x-nextjs-rewrite");
1214
- const target = rewriteTarget ? resolvePagesDataNavigationTarget(rewriteTarget, __basePath) : initialTarget;
1220
+ const target = rewriteTarget ? resolvePagesDataNavigationTarget(rewriteTarget, __basePath, { locale: initialTarget.prefetchLocale }) : initialTarget;
1215
1221
  if (!target) scheduleHardNavigationAndThrow(url, "Data navigation failed: rewrite target has no page loader");
1216
1222
  let body;
1217
1223
  try {
1218
1224
  body = await res.json();
1219
1225
  } catch {
1226
+ if (options.isHydrationQueryUpdate) return;
1220
1227
  scheduleHardNavigationAndThrow(url, "Data navigation failed: invalid JSON response");
1221
1228
  }
1222
1229
  assertStillCurrent();
@@ -1382,20 +1389,21 @@ async function navigateClient(url, fetchUrl = url, options = {}, routeUrl = url)
1382
1389
  htmlFetchUrl = configRewrite.href;
1383
1390
  }
1384
1391
  }
1385
- let dataTarget = resolvePagesDataNavigationTarget(routeLookupUrl, __basePath);
1392
+ const pagesDataTargetOptions = { locale: options.locale };
1393
+ let dataTarget = resolvePagesDataNavigationTarget(routeLookupUrl, __basePath, pagesDataTargetOptions);
1386
1394
  let middlewareDataResponse;
1387
1395
  let middlewareEffect = null;
1388
1396
  let middlewareRewrittenTarget;
1389
- const middlewareProbeDataHref = getMiddlewarePagesDataFetchUrl(browserUrl);
1397
+ const middlewareProbeDataHref = getMiddlewarePagesDataFetchUrl(browserUrl, dataTarget);
1390
1398
  if (middlewareProbeDataHref !== null) {
1391
1399
  middlewareDataCacheEvictHref = getPagesDataCacheHref(middlewareProbeDataHref);
1392
1400
  try {
1393
- middlewareEffect = await resolveMiddlewareDataEffect(browserUrl, controller.signal);
1401
+ middlewareEffect = await resolveMiddlewareDataEffect(browserUrl, controller.signal, dataTarget);
1394
1402
  } catch (err) {
1395
1403
  if (err instanceof DOMException && err.name === "AbortError") throw new NavigationCancelledError(browserUrl);
1396
1404
  throw err;
1397
1405
  }
1398
- if (middlewareEffect?.rewriteTarget) middlewareRewrittenTarget = resolvePagesDataNavigationTarget(middlewareEffect.rewriteTarget, __basePath);
1406
+ if (middlewareEffect?.rewriteTarget) middlewareRewrittenTarget = resolvePagesDataNavigationTarget(middlewareEffect.rewriteTarget, __basePath, pagesDataTargetOptions);
1399
1407
  if (middlewareEffect) if (shouldEvictMiddlewareDataCache(middlewareEffect, middlewareRewrittenTarget !== void 0 ? middlewareRewrittenTarget : dataTarget)) middlewareDataCacheEvictHref = middlewareEffect.dataHref;
1400
1408
  else middlewareDataCacheEvictHref = null;
1401
1409
  assertStillCurrent();
@@ -1412,7 +1420,9 @@ async function navigateClient(url, fetchUrl = url, options = {}, routeUrl = url)
1412
1420
  } else if (middlewareEffect) {
1413
1421
  if (middlewareEffect.rewriteTarget || routeUrl === url) middlewareDataResponse = middlewareEffect.response;
1414
1422
  if (middlewareEffect.rewriteTarget) {
1415
- const rewrittenTarget = middlewareRewrittenTarget ?? resolvePagesDataNavigationTarget(middlewareEffect.rewriteTarget, __basePath);
1423
+ const rewrittenOwner = resolveDirectHybridClientRouteOwner(middlewareEffect.rewriteTarget, __basePath);
1424
+ if (rewrittenOwner === "app" || rewrittenOwner === "document") scheduleHardNavigationAndThrow(browserUrl, "Navigation rewritten to a non-Pages route");
1425
+ const rewrittenTarget = middlewareRewrittenTarget ?? resolvePagesDataNavigationTarget(middlewareEffect.rewriteTarget, __basePath, pagesDataTargetOptions);
1416
1426
  if (!rewrittenTarget) scheduleHardNavigationAndThrow(browserUrl, "Navigation rewritten to a non-Pages route");
1417
1427
  dataTarget = rewrittenTarget;
1418
1428
  }
@@ -1618,11 +1628,15 @@ async function performNavigation(url, as, options, mode, onStateUpdate) {
1618
1628
  } : null;
1619
1629
  const navigateOptions = errorRouteHtmlFetchUrl ? {
1620
1630
  allowNotFoundResponse: true,
1631
+ locale: navigationLocale,
1621
1632
  mode,
1622
- scroll: scrollTarget
1633
+ scroll: scrollTarget,
1634
+ isHydrationQueryUpdate: options?._h === 1
1623
1635
  } : {
1636
+ locale: navigationLocale,
1624
1637
  mode,
1625
- scroll: scrollTarget
1638
+ scroll: scrollTarget,
1639
+ isHydrationQueryUpdate: options?._h === 1
1626
1640
  };
1627
1641
  const currentLocale = getCurrentUrlLocale();
1628
1642
  if (mode === "push" && interpolatedRoute !== resolved && stripHash(full) === routerRuntimeState.lastPathnameAndSearch && navigationLocale === currentLocale) mode = "replace";
@@ -1882,10 +1896,12 @@ setPagesRouterPopStateHandler(handlePagesRouterPopState);
1882
1896
  */
1883
1897
  function wrapWithRouterContext(element, onCommit = noopCommit, onError = noopCommit) {
1884
1898
  const { CommitBoundary, Provider } = getPagesRouterRuntimeComponents();
1899
+ let inner = createElement(Provider, null, element);
1900
+ if (typeof window !== "undefined" && window.__VINEXT_REACT_STRICT_MODE__ === true) inner = createElement(StrictMode, null, inner);
1885
1901
  return createElement(CommitBoundary, {
1886
1902
  onCommit,
1887
1903
  onError
1888
- }, createElement(Provider, null, element));
1904
+ }, inner);
1889
1905
  }
1890
1906
  /**
1891
1907
  * Higher-order component that injects the Pages Router `router` instance as
@@ -36,6 +36,7 @@ function createRequestContext(opts) {
36
36
  currentFetchCacheMode: null,
37
37
  currentForceDynamicFetchDefault: false,
38
38
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
39
+ refreshStaleFetchesInForeground: false,
39
40
  isFetchDedupeActive: false,
40
41
  currentFetchDedupeEntries: /* @__PURE__ */ new Map(),
41
42
  executionContext: _getInheritedExecutionContext(),
package/dist/typegen.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { findDir } from "./utils/project.js";
2
- import { decodeRouteSegment, isInvisibleSegment } from "./routing/utils.js";
3
2
  import { normalizePathSeparators } from "./utils/path.js";
3
+ import { decodeRouteSegment, isInvisibleSegment } from "./routing/utils.js";
4
4
  import { patternToNextFormat } from "./routing/route-validation.js";
5
5
  import { compareStrings } from "./utils/compare.js";
6
6
  import "./routing/app-route-graph.js";
@@ -59,7 +59,7 @@ function buildRequestHeadersFromMiddlewareResponse(baseHeaders, middlewareHeader
59
59
  return nextHeaders;
60
60
  }
61
61
  function shouldKeepMiddlewareHeader(key) {
62
- return key === "x-middleware-override-headers" || key === "x-middleware-set-cookie" || key.startsWith("x-middleware-request-");
62
+ return key === "x-middleware-override-headers" || key === "x-middleware-cache" || key === "x-middleware-set-cookie" || key.startsWith("x-middleware-request-");
63
63
  }
64
64
  //#endregion
65
65
  export { buildRequestHeadersFromMiddlewareResponse, encodeMiddlewareRequestHeaders, shouldKeepMiddlewareHeader };