vinext 0.0.42 → 0.0.44

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 (35) hide show
  1. package/dist/client/vinext-next-data.d.ts +1 -3
  2. package/dist/deploy.js +21 -4
  3. package/dist/deploy.js.map +1 -1
  4. package/dist/entries/app-rsc-entry.js +39 -9
  5. package/dist/entries/app-rsc-entry.js.map +1 -1
  6. package/dist/index.js +3 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/routing/app-router.d.ts +2 -1
  9. package/dist/routing/app-router.js +28 -5
  10. package/dist/routing/app-router.js.map +1 -1
  11. package/dist/server/app-browser-entry.js +219 -96
  12. package/dist/server/app-browser-entry.js.map +1 -1
  13. package/dist/server/app-page-route-wiring.d.ts +1 -0
  14. package/dist/server/app-page-route-wiring.js +12 -2
  15. package/dist/server/app-page-route-wiring.js.map +1 -1
  16. package/dist/server/app-route-handler-policy.js +5 -3
  17. package/dist/server/app-route-handler-policy.js.map +1 -1
  18. package/dist/server/app-route-handler-response.js +2 -0
  19. package/dist/server/app-route-handler-response.js.map +1 -1
  20. package/dist/server/app-router-entry.js +8 -1
  21. package/dist/server/app-router-entry.js.map +1 -1
  22. package/dist/server/app-ssr-entry.js +2 -1
  23. package/dist/server/app-ssr-entry.js.map +1 -1
  24. package/dist/server/prod-server.js +16 -13
  25. package/dist/server/prod-server.js.map +1 -1
  26. package/dist/server/request-pipeline.d.ts +33 -1
  27. package/dist/server/request-pipeline.js +44 -2
  28. package/dist/server/request-pipeline.js.map +1 -1
  29. package/dist/shims/navigation.d.ts +1 -1
  30. package/dist/shims/navigation.js +32 -5
  31. package/dist/shims/navigation.js.map +1 -1
  32. package/package.json +1 -1
  33. package/dist/client/entry.d.ts +0 -1
  34. package/dist/client/entry.js +0 -60
  35. package/dist/client/entry.js.map +0 -1
@@ -7,9 +7,9 @@ import "../client/instrumentation-client.js";
7
7
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
8
8
  import { createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl, resolveAndClassifyNavigationCommit, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDisposition, resolveServerActionRequestState, routerReducer } from "./app-browser-state.js";
9
9
  import { devOnCaughtError } from "./app-browser-error.js";
10
- import { createElement, startTransition, use, useLayoutEffect, useReducer, useRef } from "react";
11
- import { hydrateRoot } from "react-dom/client";
10
+ import { createElement, startTransition, use, useLayoutEffect, useRef, useState } from "react";
12
11
  import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
12
+ import { hydrateRoot } from "react-dom/client";
13
13
  //#region src/server/app-browser-entry.ts
14
14
  function toActionType(kind) {
15
15
  return kind === "traverse" ? "traverse" : "navigate";
@@ -21,21 +21,56 @@ let nextNavigationRenderId = 0;
21
21
  let activeNavigationId = 0;
22
22
  const pendingNavigationCommits = /* @__PURE__ */ new Map();
23
23
  const pendingNavigationPrePaintEffects = /* @__PURE__ */ new Map();
24
- let dispatchBrowserRouterAction = null;
24
+ function isRouterStatePromise(value) {
25
+ return value instanceof Promise;
26
+ }
27
+ let setBrowserRouterState = null;
25
28
  let browserRouterStateRef = null;
29
+ let activePendingBrowserRouterState = null;
26
30
  let latestClientParams = {};
27
31
  const visitedResponseCache = /* @__PURE__ */ new Map();
28
32
  function isServerActionResult(value) {
29
33
  return !!value && typeof value === "object" && "root" in value;
30
34
  }
31
- function getBrowserRouterDispatch() {
32
- if (!dispatchBrowserRouterAction) throw new Error("[vinext] Browser router dispatch is not initialized");
33
- return dispatchBrowserRouterAction;
35
+ function getBrowserRouterStateSetter() {
36
+ if (!setBrowserRouterState) throw new Error("[vinext] Browser router state setter is not initialized");
37
+ return setBrowserRouterState;
34
38
  }
35
39
  function getBrowserRouterState() {
36
40
  if (!browserRouterStateRef) throw new Error("[vinext] Browser router state is not initialized");
37
41
  return browserRouterStateRef.current;
38
42
  }
43
+ function beginPendingBrowserRouterState() {
44
+ const setter = getBrowserRouterStateSetter();
45
+ if (activePendingBrowserRouterState && !activePendingBrowserRouterState.settled) {
46
+ activePendingBrowserRouterState.settled = true;
47
+ activePendingBrowserRouterState.resolve(getBrowserRouterState());
48
+ }
49
+ let resolve;
50
+ const promise = new Promise((resolvePromise) => {
51
+ resolve = resolvePromise;
52
+ });
53
+ const pending = {
54
+ promise,
55
+ resolve,
56
+ settled: false
57
+ };
58
+ activePendingBrowserRouterState = pending;
59
+ setter(promise);
60
+ return pending;
61
+ }
62
+ function settlePendingBrowserRouterState(pending) {
63
+ if (!pending || pending.settled) return;
64
+ pending.settled = true;
65
+ pending.resolve(getBrowserRouterState());
66
+ if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
67
+ }
68
+ function resolvePendingBrowserRouterState(pending, action) {
69
+ if (!pending || pending.settled) return;
70
+ pending.settled = true;
71
+ pending.resolve(routerReducer(getBrowserRouterState(), action));
72
+ if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
73
+ }
39
74
  function applyClientParams(params) {
40
75
  latestClientParams = params;
41
76
  setClientParams(params);
@@ -213,7 +248,7 @@ async function commitSameUrlNavigatePayload(nextElements, returnValue) {
213
248
  window.location.assign(window.location.href);
214
249
  return;
215
250
  }
216
- if (disposition === "dispatch") dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "navigate", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, false);
251
+ if (disposition === "dispatch") dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "navigate", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, null, false);
217
252
  if (returnValue) {
218
253
  if (!returnValue.ok) throw returnValue.data;
219
254
  return returnValue.data;
@@ -222,7 +257,7 @@ async function commitSameUrlNavigatePayload(nextElements, returnValue) {
222
257
  function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
223
258
  const resolvedElements = use(initialElements);
224
259
  const initialMetadata = readAppElementsMetadata(resolvedElements);
225
- const [treeState, dispatchTreeState] = useReducer(routerReducer, {
260
+ const [treeStateValue, setTreeStateValue] = useState({
226
261
  elements: resolvedElements,
227
262
  interceptionContext: initialMetadata.interceptionContext,
228
263
  layoutFlags: initialMetadata.layoutFlags,
@@ -232,17 +267,18 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
232
267
  rootLayoutTreePath: initialMetadata.rootLayoutTreePath,
233
268
  routeId: initialMetadata.routeId
234
269
  });
270
+ const treeState = isRouterStatePromise(treeStateValue) ? use(treeStateValue) : treeStateValue;
235
271
  const stateRef = useRef(treeState);
236
272
  stateRef.current = treeState;
237
273
  useLayoutEffect(() => {
238
- dispatchBrowserRouterAction = dispatchTreeState;
274
+ setBrowserRouterState = setTreeStateValue;
239
275
  browserRouterStateRef = stateRef;
240
276
  return () => {
241
- if (dispatchBrowserRouterAction === dispatchTreeState) dispatchBrowserRouterAction = null;
277
+ if (setBrowserRouterState === setTreeStateValue) setBrowserRouterState = null;
242
278
  if (browserRouterStateRef === stateRef) browserRouterStateRef = null;
243
279
  setMountedSlotsHeader(null);
244
280
  };
245
- }, [dispatchTreeState]);
281
+ }, [setTreeStateValue]);
246
282
  useLayoutEffect(() => {
247
283
  setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
248
284
  }, [treeState.elements]);
@@ -255,9 +291,9 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
255
291
  if (!ClientNavigationRenderContext) return committedTree;
256
292
  return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, committedTree);
257
293
  }
258
- function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType, interceptionContext, layoutFlags, previousNextUrl, routeId, rootLayoutTreePath, useTransitionMode) {
259
- const dispatch = getBrowserRouterDispatch();
260
- const applyAction = () => dispatch({
294
+ function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType, interceptionContext, layoutFlags, previousNextUrl, routeId, rootLayoutTreePath, pendingRouterState, useTransitionMode) {
295
+ const setter = getBrowserRouterStateSetter();
296
+ const action = {
261
297
  elements,
262
298
  interceptionContext,
263
299
  layoutFlags,
@@ -267,11 +303,18 @@ function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType,
267
303
  rootLayoutTreePath,
268
304
  routeId,
269
305
  type: actionType
270
- });
306
+ };
307
+ const applyAction = () => {
308
+ if (pendingRouterState) {
309
+ resolvePendingBrowserRouterState(pendingRouterState, action);
310
+ return;
311
+ }
312
+ setter(routerReducer(getBrowserRouterState(), action));
313
+ };
271
314
  if (useTransitionMode) startTransition(applyAction);
272
315
  else applyAction();
273
316
  }
274
- async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, useTransition = true, actionType = "navigate") {
317
+ async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, useTransition = true, actionType = "navigate") {
275
318
  const renderId = ++nextNavigationRenderId;
276
319
  const committed = new Promise((resolve) => {
277
320
  pendingNavigationCommits.set(renderId, resolve);
@@ -294,12 +337,14 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
294
337
  startedNavigationId: navId
295
338
  });
296
339
  if (disposition === "skip") {
340
+ settlePendingBrowserRouterState(pendingRouterState);
297
341
  const resolve = pendingNavigationCommits.get(renderId);
298
342
  pendingNavigationCommits.delete(renderId);
299
343
  resolve?.();
300
344
  return;
301
345
  }
302
346
  if (disposition === "hard-navigate") {
347
+ settlePendingBrowserRouterState(pendingRouterState);
303
348
  pendingNavigationCommits.delete(renderId);
304
349
  window.location.assign(targetHref);
305
350
  return;
@@ -307,12 +352,13 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
307
352
  queuePrePaintNavigationEffect(renderId, createNavigationCommitEffect(targetHref, historyUpdateMode, navId, params, pending.previousNextUrl));
308
353
  activateNavigationSnapshot();
309
354
  snapshotActivated = true;
310
- dispatchBrowserTree(pending.action.elements, navigationSnapshot, renderId, actionType, pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, useTransition);
355
+ dispatchBrowserTree(pending.action.elements, navigationSnapshot, renderId, actionType, pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, pendingRouterState, useTransition);
311
356
  } catch (error) {
312
357
  pendingNavigationPrePaintEffects.delete(renderId);
313
358
  const resolve = pendingNavigationCommits.get(renderId);
314
359
  pendingNavigationCommits.delete(renderId);
315
360
  if (snapshotActivated) commitClientNavigationState(navId);
361
+ settlePendingBrowserRouterState(pendingRouterState);
316
362
  resolve?.();
317
363
  throw error;
318
364
  }
@@ -333,9 +379,45 @@ function restorePopstateScrollPosition(state) {
333
379
  window.scrollTo(x, y);
334
380
  });
335
381
  }
382
+ let isPageUnloading = false;
383
+ const RSC_RELOAD_KEY = "__vinext_rsc_initial_reload__";
384
+ function readReloadFlag() {
385
+ try {
386
+ return sessionStorage.getItem(RSC_RELOAD_KEY);
387
+ } catch {
388
+ return null;
389
+ }
390
+ }
391
+ function writeReloadFlag(path) {
392
+ try {
393
+ sessionStorage.setItem(RSC_RELOAD_KEY, path);
394
+ } catch {}
395
+ }
396
+ function clearReloadFlag() {
397
+ try {
398
+ sessionStorage.removeItem(RSC_RELOAD_KEY);
399
+ } catch {}
400
+ }
401
+ function recoverFromBadInitialRscResponse(reason) {
402
+ const currentPath = window.location.pathname + window.location.search;
403
+ if (readReloadFlag() === currentPath) {
404
+ clearReloadFlag();
405
+ console.error(`[vinext] Initial RSC fetch ${reason} after reload; aborting hydration. Server-rendered HTML remains visible; client components will not hydrate.`);
406
+ return null;
407
+ }
408
+ writeReloadFlag(currentPath);
409
+ if (readReloadFlag() !== currentPath) {
410
+ console.error(`[vinext] Initial RSC fetch ${reason}; sessionStorage unavailable so the reload-loop guard cannot persist — aborting hydration. Server-rendered HTML remains visible; client components will not hydrate.`);
411
+ return null;
412
+ }
413
+ console.warn(`[vinext] Initial RSC fetch ${reason}; reloading once to let the server render the HTML error page`);
414
+ window.location.reload();
415
+ return null;
416
+ }
336
417
  async function readInitialRscStream() {
337
418
  const vinext = getVinextBrowserGlobal();
338
419
  if (vinext.__VINEXT_RSC__ || vinext.__VINEXT_RSC_CHUNKS__ || vinext.__VINEXT_RSC_DONE__) {
420
+ clearReloadFlag();
339
421
  if (vinext.__VINEXT_RSC__) {
340
422
  const embedData = vinext.__VINEXT_RSC__;
341
423
  delete vinext.__VINEXT_RSC__;
@@ -350,6 +432,11 @@ async function readInitialRscStream() {
350
432
  return createProgressiveRscStream();
351
433
  }
352
434
  const rscResponse = await fetch(toRscUrl(window.location.pathname + window.location.search));
435
+ if (!rscResponse.ok) return recoverFromBadInitialRscResponse(`returned ${rscResponse.status}`);
436
+ const contentType = rscResponse.headers.get("content-type") ?? "";
437
+ if (!contentType.startsWith("text/x-component")) return recoverFromBadInitialRscResponse(`returned non-RSC content-type "${contentType || "(missing)"}"`);
438
+ if (!rscResponse.body) return recoverFromBadInitialRscResponse("returned empty body");
439
+ clearReloadFlag();
353
440
  let params = {};
354
441
  const paramsHeader = rscResponse.headers.get("X-Vinext-Params");
355
442
  if (paramsHeader) try {
@@ -357,7 +444,6 @@ async function readInitialRscStream() {
357
444
  applyClientParams(params);
358
445
  } catch {}
359
446
  restoreHydrationNavigationContext(window.location.pathname, window.location.search, params);
360
- if (!rscResponse.body) throw new Error("[vinext] Initial RSC response had no body");
361
447
  return rscResponse.body;
362
448
  }
363
449
  function registerServerActionCallback() {
@@ -396,7 +482,12 @@ function registerServerActionCallback() {
396
482
  }
397
483
  async function main() {
398
484
  registerServerActionCallback();
399
- const root = normalizeAppElementsPromise(createFromReadableStream(await readInitialRscStream()));
485
+ const rscStream = await readInitialRscStream();
486
+ if (rscStream === null) return;
487
+ bootstrapHydration(rscStream);
488
+ }
489
+ function bootstrapHydration(rscStream) {
490
+ const root = normalizeAppElementsPromise(createFromReadableStream(rscStream));
400
491
  const initialNavigationSnapshot = createClientNavigationRenderSnapshot(window.location.href, latestClientParams);
401
492
  replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(window.history.state, null), "", window.location.href);
402
493
  window.__VINEXT_RSC_ROOT__ = hydrateRoot(document, createElement(BrowserRoot, {
@@ -404,99 +495,123 @@ async function main() {
404
495
  initialNavigationSnapshot
405
496
  }), import.meta.env.DEV ? { onCaughtError: devOnCaughtError } : void 0);
406
497
  window.__VINEXT_HYDRATED_AT = performance.now();
407
- window.__VINEXT_RSC_NAVIGATE__ = async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride) {
408
- if (redirectDepth > 10) {
409
- console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
410
- window.location.href = href;
411
- return;
412
- }
498
+ window.__VINEXT_RSC_NAVIGATE__ = async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false) {
413
499
  let _snapshotPending = false;
500
+ let pendingRouterState = null;
414
501
  const navId = ++activeNavigationId;
502
+ let currentHref = href;
503
+ let currentHistoryMode = historyUpdateMode;
504
+ let currentPrevNextUrl = previousNextUrlOverride;
505
+ let redirectCount = redirectDepth;
415
506
  try {
416
- const url = new URL(href, window.location.origin);
417
- const rscUrl = toRscUrl(url.pathname + url.search);
418
- const requestState = getRequestState(navigationKind, previousNextUrlOverride);
419
- const requestInterceptionContext = requestState.interceptionContext;
420
- const requestPreviousNextUrl = requestState.previousNextUrl;
421
- const navState = getClientNavigationState();
422
- const currentPath = navState?.pendingPathname ?? navState?.cachedPathname ?? stripBasePath(window.location.pathname, __basePath);
423
- const isSameRoute = stripBasePath(url.pathname, __basePath) === currentPath;
424
- setPendingPathname(url.pathname, navId);
425
- const elementsAtNavStart = getBrowserRouterState().elements;
426
- const mountedSlotsHeader = getMountedSlotIdsHeader(elementsAtNavStart);
427
- const cachedRoute = getVisitedResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader, navigationKind);
428
- if (cachedRoute) {
507
+ if (programmaticTransition) pendingRouterState = beginPendingBrowserRouterState();
508
+ while (true) {
509
+ if (redirectCount > 10) {
510
+ console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
511
+ window.location.href = currentHref;
512
+ return;
513
+ }
514
+ const url = new URL(currentHref, window.location.origin);
515
+ const rscUrl = toRscUrl(url.pathname + url.search);
516
+ const requestState = getRequestState(navigationKind, currentPrevNextUrl);
517
+ const requestInterceptionContext = requestState.interceptionContext;
518
+ const requestPreviousNextUrl = requestState.previousNextUrl;
519
+ const navState = getClientNavigationState();
520
+ const currentPath = navState?.pendingPathname ?? navState?.cachedPathname ?? stripBasePath(window.location.pathname, __basePath);
521
+ const isSameRoute = stripBasePath(url.pathname, __basePath) === currentPath;
522
+ setPendingPathname(url.pathname, navId);
523
+ const elementsAtNavStart = getBrowserRouterState().elements;
524
+ const mountedSlotsHeader = getMountedSlotIdsHeader(elementsAtNavStart);
525
+ const cachedRoute = getVisitedResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader, navigationKind);
526
+ if (cachedRoute) {
527
+ if (navId !== activeNavigationId) return;
528
+ const cachedParams = cachedRoute.params;
529
+ const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, cachedParams);
530
+ const cachedPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
531
+ if (navId !== activeNavigationId) return;
532
+ _snapshotPending = true;
533
+ try {
534
+ await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, pendingRouterState, isSameRoute, toActionType(navigationKind));
535
+ } finally {
536
+ _snapshotPending = false;
537
+ }
538
+ return;
539
+ }
540
+ let navResponse;
541
+ let navResponseUrl = null;
542
+ if (navigationKind !== "refresh") {
543
+ const prefetchedResponse = consumePrefetchResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader);
544
+ if (prefetchedResponse) {
545
+ navResponse = restoreRscResponse(prefetchedResponse, false);
546
+ navResponseUrl = prefetchedResponse.url;
547
+ }
548
+ }
549
+ if (!navResponse) {
550
+ const requestHeaders = createRscRequestHeaders(requestInterceptionContext);
551
+ if (mountedSlotsHeader) requestHeaders.set("X-Vinext-Mounted-Slots", mountedSlotsHeader);
552
+ navResponse = await fetch(rscUrl, {
553
+ headers: requestHeaders,
554
+ credentials: "include"
555
+ });
556
+ }
557
+ if (navId !== activeNavigationId) return;
558
+ const isRscResponse = (navResponse.headers.get("content-type") ?? "").startsWith("text/x-component");
559
+ if (!navResponse.ok || !isRscResponse || !navResponse.body) {
560
+ const responseUrl = navResponseUrl ?? navResponse.url;
561
+ let hardNavTarget = currentHref;
562
+ if (responseUrl) {
563
+ const parsed = new URL(responseUrl, window.location.origin);
564
+ const origUrl = new URL(currentHref, window.location.origin);
565
+ let pathname = parsed.pathname.replace(/\.rsc$/, "");
566
+ if (origUrl.pathname.length > 1 && origUrl.pathname.endsWith("/") && !pathname.endsWith("/")) pathname += "/";
567
+ hardNavTarget = pathname + parsed.search;
568
+ if (origUrl.hash) hardNavTarget += origUrl.hash;
569
+ }
570
+ window.location.href = hardNavTarget;
571
+ return;
572
+ }
573
+ const finalUrl = new URL(navResponseUrl ?? navResponse.url, window.location.origin);
574
+ const requestedUrl = new URL(rscUrl, window.location.origin);
575
+ if (finalUrl.pathname !== requestedUrl.pathname) {
576
+ const destinationPath = finalUrl.pathname.replace(/\.rsc$/, "") + finalUrl.search;
577
+ replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(null, requestPreviousNextUrl), "", destinationPath);
578
+ currentHref = destinationPath;
579
+ currentHistoryMode = void 0;
580
+ currentPrevNextUrl = requestPreviousNextUrl;
581
+ redirectCount += 1;
582
+ continue;
583
+ }
584
+ let navParams = {};
585
+ const paramsHeader = navResponse.headers.get("X-Vinext-Params");
586
+ if (paramsHeader) try {
587
+ navParams = JSON.parse(decodeURIComponent(paramsHeader));
588
+ } catch {}
589
+ const navigationSnapshot = createClientNavigationRenderSnapshot(currentHref, navParams);
590
+ const responseSnapshot = await snapshotRscResponse(navResponse);
429
591
  if (navId !== activeNavigationId) return;
430
- const cachedParams = cachedRoute.params;
431
- const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(href, cachedParams);
432
- const cachedPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
592
+ const rscPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(responseSnapshot))));
433
593
  if (navId !== activeNavigationId) return;
434
594
  _snapshotPending = true;
435
595
  try {
436
- await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, href, navId, historyUpdateMode, cachedParams, requestPreviousNextUrl, isSameRoute, toActionType(navigationKind));
596
+ await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, pendingRouterState, isSameRoute, toActionType(navigationKind));
437
597
  } finally {
438
598
  _snapshotPending = false;
439
599
  }
600
+ if (navId !== activeNavigationId) return;
601
+ storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, readAppElementsMetadata(await rscPayload).interceptionContext), responseSnapshot, navParams);
440
602
  return;
441
603
  }
442
- let navResponse;
443
- let navResponseUrl = null;
444
- if (navigationKind !== "refresh") {
445
- const prefetchedResponse = consumePrefetchResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader);
446
- if (prefetchedResponse) {
447
- navResponse = restoreRscResponse(prefetchedResponse, false);
448
- navResponseUrl = prefetchedResponse.url;
449
- }
450
- }
451
- if (!navResponse) {
452
- const requestHeaders = createRscRequestHeaders(requestInterceptionContext);
453
- if (mountedSlotsHeader) requestHeaders.set("X-Vinext-Mounted-Slots", mountedSlotsHeader);
454
- navResponse = await fetch(rscUrl, {
455
- headers: requestHeaders,
456
- credentials: "include"
457
- });
458
- }
459
- if (navId !== activeNavigationId) return;
460
- const finalUrl = new URL(navResponseUrl ?? navResponse.url, window.location.origin);
461
- const requestedUrl = new URL(rscUrl, window.location.origin);
462
- if (finalUrl.pathname !== requestedUrl.pathname) {
463
- const destinationPath = finalUrl.pathname.replace(/\.rsc$/, "") + finalUrl.search;
464
- replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(null, requestPreviousNextUrl), "", destinationPath);
465
- const navigate = window.__VINEXT_RSC_NAVIGATE__;
466
- if (!navigate) {
467
- window.location.href = destinationPath;
468
- return;
469
- }
470
- return navigate(destinationPath, redirectDepth + 1, navigationKind, void 0, requestPreviousNextUrl);
471
- }
472
- let navParams = {};
473
- const paramsHeader = navResponse.headers.get("X-Vinext-Params");
474
- if (paramsHeader) try {
475
- navParams = JSON.parse(decodeURIComponent(paramsHeader));
476
- } catch {}
477
- const navigationSnapshot = createClientNavigationRenderSnapshot(href, navParams);
478
- const responseSnapshot = await snapshotRscResponse(navResponse);
479
- if (navId !== activeNavigationId) return;
480
- const rscPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(responseSnapshot))));
481
- if (navId !== activeNavigationId) return;
482
- _snapshotPending = true;
483
- try {
484
- await renderNavigationPayload(rscPayload, navigationSnapshot, href, navId, historyUpdateMode, navParams, requestPreviousNextUrl, isSameRoute, toActionType(navigationKind));
485
- } finally {
486
- _snapshotPending = false;
487
- }
488
- if (navId !== activeNavigationId) return;
489
- storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, readAppElementsMetadata(await rscPayload).interceptionContext), responseSnapshot, navParams);
490
- return;
491
604
  } catch (error) {
492
605
  if (_snapshotPending) {
493
606
  _snapshotPending = false;
494
607
  commitClientNavigationState(navId);
495
608
  }
496
- if (navId === activeNavigationId) clearPendingPathname(navId);
497
609
  if (navId !== activeNavigationId) return;
498
- console.error("[vinext] RSC navigation error:", error);
499
- window.location.href = href;
610
+ if (!isPageUnloading) console.error("[vinext] RSC navigation error:", error);
611
+ window.location.href = currentHref;
612
+ } finally {
613
+ settlePendingBrowserRouterState(pendingRouterState);
614
+ if (navId === activeNavigationId) clearPendingPathname(navId);
500
615
  }
501
616
  };
502
617
  if ("scrollRestoration" in history) history.scrollRestoration = "manual";
@@ -520,13 +635,21 @@ async function main() {
520
635
  renderId: ++nextNavigationRenderId,
521
636
  type: "replace"
522
637
  });
523
- dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "replace", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, false);
638
+ dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "replace", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, null, false);
524
639
  } catch (error) {
525
640
  console.error("[vinext] RSC HMR error:", error);
526
641
  }
527
642
  });
528
643
  }
529
- if (typeof document !== "undefined") main();
644
+ if (typeof document !== "undefined") {
645
+ window.addEventListener("pagehide", () => {
646
+ isPageUnloading = true;
647
+ });
648
+ window.addEventListener("pageshow", () => {
649
+ isPageUnloading = false;
650
+ });
651
+ main();
652
+ }
530
653
  //#endregion
531
654
  export {};
532
655