@tanstack/router-core 1.171.24 → 1.171.25

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.
@@ -61,7 +61,7 @@ const SUCCESS = 0;
61
61
  const ERROR = 1;
62
62
  const NOT_FOUND = 2;
63
63
  const REDIRECTED = 3;
64
- const CANCELED = 4;
64
+ const CANCELED_OUTCOME = [4];
65
65
  function isControl(result) {
66
66
  return typeof result[0] === "number";
67
67
  }
@@ -95,24 +95,15 @@ function normalizeError(route, cause) {
95
95
  }
96
96
  return outcome;
97
97
  }
98
- function normalizeLaneError(route, cause, options) {
99
- if (options[0].signal.aborted || !options[2]()) {
100
- options[0].abort();
101
- return [CANCELED];
102
- }
103
- return normalizeError(route, cause);
104
- }
105
- function navigateFrom(router, location) {
106
- return (opts) => router.navigate({
107
- ...opts,
108
- _fromLocation: location
109
- });
98
+ function normalizeLaneError(router, lane, route, cause, options) {
99
+ if (options[0].signal.aborted) return CANCELED_OUTCOME;
100
+ return materializeRedirect(router, lane, route, normalizeError(route, cause), options);
110
101
  }
111
102
  async function contextualize(router, lane, options, end, planSuccessfulLane, retainedEnd) {
112
103
  const [location, matches] = lane;
113
104
  const signal = options[0].signal;
114
- const preload = !!options[4];
115
- for (let index = options[7] ?? 0; index < end; index++) {
105
+ const preload = !!options[3];
106
+ for (let index = options[6] ?? 0; index < end; index++) {
116
107
  const match = matches[index];
117
108
  const route = getRoute(router, match);
118
109
  match.abortController = options[0];
@@ -120,7 +111,10 @@ async function contextualize(router, lane, options, end, planSuccessfulLane, ret
120
111
  const common = {
121
112
  params: match.params,
122
113
  location,
123
- navigate: navigateFrom(router, location),
114
+ navigate: (opts) => router.navigate({
115
+ ...opts,
116
+ _fromLocation: location
117
+ }),
124
118
  buildLocation: router.buildLocation,
125
119
  cause: preload ? "preload" : match.cause,
126
120
  abortController: options[0],
@@ -143,16 +137,13 @@ async function contextualize(router, lane, options, end, planSuccessfulLane, ret
143
137
  match.context = context;
144
138
  } catch (cause) {
145
139
  releaseFlight(router, match);
146
- return [index, normalizeLaneError(route, cause, options)];
147
- }
148
- if (signal.aborted || !options[2]()) {
149
- options[0].abort();
150
- return [index, [CANCELED]];
140
+ return [index, normalizeLaneError(router, lane, route, cause, options)];
151
141
  }
142
+ if (signal.aborted) return [index, CANCELED_OUTCOME];
152
143
  const validationError = match.paramsError ?? match.searchError;
153
144
  if (validationError !== void 0) {
154
145
  releaseFlight(router, match);
155
- return [index, normalizeLaneError(route, validationError, options)];
146
+ return [index, normalizeLaneError(router, lane, route, validationError, options)];
156
147
  }
157
148
  const beforeLoad = route.options.beforeLoad;
158
149
  if (!beforeLoad) continue;
@@ -163,16 +154,15 @@ async function contextualize(router, lane, options, end, planSuccessfulLane, ret
163
154
  ...router.options.additionalContext
164
155
  };
165
156
  const previousStatus = match.status;
166
- if (previousStatus === "success" && index >= retainedEnd) match.status = "pending";
167
- options[8]?.();
157
+ if (index >= retainedEnd) {
158
+ match.status = "pending";
159
+ options[7]?.();
160
+ }
168
161
  try {
169
162
  setFetching(router, match, "beforeLoad", options[0]);
170
163
  const result = await waitFor(beforeLoad(beforeLoadContext), signal);
171
- if (!options[2]()) {
172
- options[0].abort();
173
- return [index, [CANCELED]];
174
- }
175
- const outcome = normalize(result, false, route.id);
164
+ if (signal.aborted) return [index, CANCELED_OUTCOME];
165
+ const outcome = materializeRedirect(router, lane, route, normalize(result, false, route.id), options);
176
166
  if (outcome[0] !== SUCCESS) {
177
167
  releaseFlight(router, match);
178
168
  return [index, outcome];
@@ -183,9 +173,9 @@ async function contextualize(router, lane, options, end, planSuccessfulLane, ret
183
173
  };
184
174
  } catch (cause) {
185
175
  releaseFlight(router, match);
186
- return [index, normalizeLaneError(route, cause, options)];
176
+ return [index, normalizeLaneError(router, lane, route, cause, options)];
187
177
  } finally {
188
- if (previousStatus === "success" && match.status === "pending") match.status = "success";
178
+ if (match.status === "pending") match.status = previousStatus;
189
179
  setFetching(router, match, false, options[0]);
190
180
  }
191
181
  }
@@ -195,7 +185,7 @@ function releaseOwnedFlight(router, match, flight) {
195
185
  if (!flight || --flight[2]) return;
196
186
  if (router._flights?.get(match.id) === flight) {
197
187
  const current = router._tx;
198
- if (current && !current[0].signal.aborted && !(process.env.NODE_ENV !== "production" && current[6]) && !current[3].includes(match) && current[3].some((candidate) => candidate.id === match.id) && current[3].some((candidate) => candidate.isFetching === "beforeLoad")) return;
188
+ if (current && !current[0].signal.aborted && !current[3].includes(match) && current[3].some((candidate) => candidate.id === match.id) && current[3].some((candidate) => candidate.isFetching === "beforeLoad")) return;
199
189
  router._flights.delete(match.id);
200
190
  }
201
191
  return flight[1];
@@ -214,7 +204,7 @@ function transferMatchResources(router, previous, next, deferSameIdFlight) {
214
204
  for (const match of previous) if (!next?.includes(match)) {
215
205
  const flight = match._flight;
216
206
  match._flight = void 0;
217
- if (deferSameIdFlight && flight?.[2] === 1 && router._flights?.get(match.id) === flight && !(process.env.NODE_ENV !== "production" && router._tx?.[6]) && next?.some((candidate) => candidate.id === match.id)) flight[2] = 0;
207
+ if (deferSameIdFlight && flight?.[2] === 1 && router._flights?.get(match.id) === flight && next?.some((candidate) => candidate.id === match.id)) flight[2] = 0;
218
208
  else {
219
209
  const controller = releaseOwnedFlight(router, match, flight);
220
210
  if (controller) abort.push(controller);
@@ -243,7 +233,10 @@ function getLoaderContext(router, lane, match, route, controller, parentMatchPro
243
233
  return {
244
234
  params: match.params,
245
235
  location,
246
- navigate: navigateFrom(router, location),
236
+ navigate: (opts) => router.navigate({
237
+ ...opts,
238
+ _fromLocation: location
239
+ }),
247
240
  cause: preload ? "preload" : match.cause,
248
241
  abortController: controller,
249
242
  preload,
@@ -254,9 +247,10 @@ function getLoaderContext(router, lane, match, route, controller, parentMatchPro
254
247
  ...router.options.additionalContext
255
248
  };
256
249
  }
257
- async function loadResource(router, lane, match, route, loader, parentMatchPromise, preload, owner) {
250
+ async function loadResource(router, lane, match, route, loader, parentMatchPromise, options) {
251
+ const owner = options[0];
258
252
  const signal = owner.signal;
259
- if (signal.aborted) return [CANCELED];
253
+ if (signal.aborted) return CANCELED_OUTCOME;
260
254
  if (!loader) return [SUCCESS, void 0];
261
255
  let flight = match._flight;
262
256
  setFetching(router, match, "loader", owner);
@@ -264,7 +258,7 @@ async function loadResource(router, lane, match, route, loader, parentMatchPromi
264
258
  if (!flight) {
265
259
  const controller = new AbortController();
266
260
  flight = [
267
- Promise.resolve().then(() => loader(getLoaderContext(router, lane, match, route, controller, parentMatchPromise, preload))).then((value) => normalize(value, false, route.id), (cause) => normalize(cause, true, route.id)).then((result) => {
261
+ Promise.resolve().then(() => loader(getLoaderContext(router, lane, match, route, controller, parentMatchPromise, !!options[3]))).then((value) => normalize(value, false, route.id), (cause) => normalize(cause, true, route.id)).then((result) => {
268
262
  if (result[0] !== SUCCESS && router._flights?.get(match.id) === flight) {
269
263
  router._flights.delete(match.id);
270
264
  if (!flight[2]) controller.abort();
@@ -278,11 +272,11 @@ async function loadResource(router, lane, match, route, loader, parentMatchPromi
278
272
  }
279
273
  match._flight = flight;
280
274
  match.abortController = flight[1];
281
- return await waitFor(flight[0], signal);
275
+ return materializeRedirect(router, lane, route, await waitFor(flight[0], signal), options);
282
276
  } catch (cause) {
283
- if (cause !== signal) throw cause;
277
+ if (cause !== signal || !signal.aborted) throw cause;
284
278
  releaseFlight(router, match);
285
- return [CANCELED];
279
+ return CANCELED_OUTCOME;
286
280
  } finally {
287
281
  setFetching(router, match, false, owner);
288
282
  }
@@ -325,7 +319,7 @@ function getParentSnapshot(match, outcome) {
325
319
  function createLoaderTask(router, lane, index, tasks, semanticParent, options, retainedEnd) {
326
320
  const match = lane[1][index];
327
321
  const route = getRoute(router, match);
328
- const preload = !!options[4];
322
+ const preload = !!options[3];
329
323
  const plannedCacheMatch = router._cache.get(match.id);
330
324
  let configured;
331
325
  let reload = false;
@@ -334,20 +328,17 @@ function createLoaderTask(router, lane, index, tasks, semanticParent, options, r
334
328
  if (match.status === "success") {
335
329
  configured = route.options.shouldReload;
336
330
  if (typeof configured === "function") configured = configured(getLoaderContext(router, lane, match, route, options[0], semanticParent, preload));
337
- if (!options[2]()) {
338
- options[0].abort();
339
- reloadFailure = [CANCELED];
340
- }
331
+ if (options[0].signal.aborted) reloadFailure = CANCELED_OUTCOME;
341
332
  }
342
333
  if (!reloadFailure) if (match.status !== "success") reload = true;
343
334
  else {
344
- const staleAge = options[4] || match.preload ? route.options.preloadStaleTime ?? router.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? router.options.defaultStaleTime ?? 0;
345
- reload = !!(match.invalid || configured || configured === void 0 && Date.now() - match.updatedAt >= staleAge && (options[6] || match.cause === "enter" || options[3].some((candidate) => candidate.routeId === match.routeId && candidate.id !== match.id)));
335
+ const staleAge = options[3] || match.preload ? route.options.preloadStaleTime ?? router.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? router.options.defaultStaleTime ?? 0;
336
+ reload = !!(match.invalid || configured || configured === void 0 && Date.now() - match.updatedAt >= staleAge && (options[5] || match.cause === "enter" || options[2].some((candidate) => candidate.routeId === match.routeId && candidate.id !== match.id)));
346
337
  }
347
338
  } catch (cause) {
348
339
  match.invalid = true;
349
340
  releaseFlight(router, match);
350
- reloadFailure = normalizeLaneError(route, cause, options);
341
+ reloadFailure = normalizeLaneError(router, lane, route, cause, options);
351
342
  }
352
343
  const routeLoader = route.options.loader;
353
344
  const loader = typeof routeLoader === "function" ? routeLoader : routeLoader?.handler;
@@ -355,10 +346,11 @@ function createLoaderTask(router, lane, index, tasks, semanticParent, options, r
355
346
  if (donor === match._flight || reloadFailure) donor = void 0;
356
347
  else if (donor && !reload && !preload && configured === void 0) reload = true;
357
348
  else if (!reload) donor = void 0;
358
- const background = !!(routeLoader && reload && match.status === "success" && !preload && !options[5] && ((typeof routeLoader === "function" ? void 0 : routeLoader?.staleReloadMode) ?? router.options.defaultStaleReloadMode) !== "blocking");
349
+ const background = !!(routeLoader && reload && match.status === "success" && !preload && !options[4] && ((typeof routeLoader === "function" ? void 0 : routeLoader?.staleReloadMode) ?? router.options.defaultStaleReloadMode) !== "blocking");
359
350
  const loaded = reload && (!preload || route.options.preload !== false);
360
351
  const blocking = loaded && !background && (match.status !== "success" || !!routeLoader);
361
- const onLazyReady = route.lazyFn && route._lazy !== true ? options[8] : void 0;
352
+ const onReady = index >= retainedEnd ? options[7] : void 0;
353
+ const onLazyReady = route.lazyFn && route._lazy !== true ? onReady : void 0;
362
354
  if (loaded && !routeLoader) {
363
355
  match.invalid = false;
364
356
  match.updatedAt = Date.now();
@@ -368,24 +360,24 @@ function createLoaderTask(router, lane, index, tasks, semanticParent, options, r
368
360
  const acceptedFlight = match._flight;
369
361
  match._flight = donor;
370
362
  releaseOwnedFlight(router, match, acceptedFlight)?.abort();
371
- if (match.status === "success" && index >= retainedEnd) match.status = "pending";
372
- options[8]?.();
363
+ if (index >= retainedEnd) match.status = "pending";
364
+ onReady?.();
373
365
  }
374
366
  if (!loaded) match.isFetching = false;
375
- const outcome = (reloadFailure ? Promise.resolve(reloadFailure) : !blocking ? Promise.resolve([SUCCESS, match.loaderData]) : loadResource(router, lane, match, route, loader, semanticParent, preload, options[0])).then((result) => {
367
+ const outcome = (reloadFailure ? Promise.resolve(reloadFailure) : !blocking ? Promise.resolve([SUCCESS, match.loaderData]) : loadResource(router, lane, match, route, loader, semanticParent, options)).then((result) => {
376
368
  if (blocking) {
377
369
  settleInto(match, result, preload);
378
370
  if (result[0] === SUCCESS) {
379
- if (routeLoader && !options[0].signal.aborted && !(process.env.NODE_ENV !== "production" && !preload && router._tx?.[6])) cacheLoaderMatch(router, match, plannedCacheMatch);
380
- match.status = "pending";
371
+ if (routeLoader && !options[0].signal.aborted) cacheLoaderMatch(router, match, plannedCacheMatch);
372
+ if (index >= retainedEnd) match.status = "pending";
381
373
  }
382
374
  }
383
375
  return result;
384
376
  });
385
- const chunkFailure = waitFor(Promise.resolve().then(() => loadRouteChunk(route, void 0, onLazyReady)), options[0].signal).then(() => void 0, (cause) => [index, normalizeLaneError(route, cause, options)]).then((failure) => outcome.then((result) => {
386
- if (blocking && !failure && result[0] === SUCCESS && match.status === "pending" && options[2]()) {
377
+ const chunkFailure = waitFor(Promise.resolve().then(() => loadRouteChunk(route, void 0, onLazyReady)), options[0].signal).then(() => void 0, (cause) => lane[1].some((candidate, candidateIndex) => candidateIndex <= index && (candidate.status === "error" || candidate.status === "notFound" || candidate._notFound)) ? void 0 : [index, normalizeLaneError(router, lane, route, cause, options)]).then((failure) => outcome.then((result) => {
378
+ if (blocking && !failure && result[0] === SUCCESS && match.status === "pending" && !options[0].signal.aborted) {
387
379
  match.status = "success";
388
- options[8]?.();
380
+ onReady?.();
389
381
  }
390
382
  return failure;
391
383
  }));
@@ -403,7 +395,7 @@ function createLoaderTask(router, lane, index, tasks, semanticParent, options, r
403
395
  };
404
396
  match.invalid = false;
405
397
  match.isFetching = "loader";
406
- const backgroundOutcome = loadResource(router, lane, candidate, route, loader, semanticParent, false, options[0]).then((result) => {
398
+ const backgroundOutcome = loadResource(router, lane, candidate, route, loader, semanticParent, options).then((result) => {
407
399
  match.isFetching = false;
408
400
  settleInto(candidate, result, false);
409
401
  return result;
@@ -422,11 +414,11 @@ async function getNotFoundBoundary(router, matches, indexed, signal, fallback =
422
414
  if (index < 0) index = 0;
423
415
  for (let i = index; i >= 0; i--) {
424
416
  const route = getRoute(router, matches[i]);
425
- const loading = loadRouteChunk(route, false);
426
- if (loading) try {
427
- await waitFor(loading, signal);
417
+ try {
418
+ const loading = loadRouteChunk(route, false);
419
+ if (loading) await waitFor(loading, signal);
428
420
  } catch (cause) {
429
- if (cause === signal) throw cause;
421
+ if (cause === signal && signal.aborted) throw cause;
430
422
  }
431
423
  if (route.options.notFoundComponent) return i;
432
424
  }
@@ -460,7 +452,32 @@ async function settleTasks(tasks, serialFailure, redirectTasks, gate) {
460
452
  }
461
453
  return serialFailure ?? loaderFailure;
462
454
  }
463
- async function reduceLane(router, lane, tasks, controller, redirects, settlement, onReady) {
455
+ function materializeRedirect(router, lane, route, outcome, options, failed) {
456
+ while (outcome[0] === REDIRECTED) {
457
+ const redirect = outcome[1];
458
+ if (redirect.options.reloadDocument ? options[3] : options[1] >= 20) return outcome;
459
+ try {
460
+ if (redirect.options.href && redirect.options.reloadDocument) {
461
+ router.resolveRedirect(redirect);
462
+ return outcome;
463
+ }
464
+ return [
465
+ REDIRECTED,
466
+ redirect,
467
+ router.buildLocation({
468
+ ...redirect.options,
469
+ _fromLocation: lane[0],
470
+ _includeValidateSearch: true
471
+ })
472
+ ];
473
+ } catch (cause) {
474
+ outcome = failed ? [ERROR, cause] : normalizeError(route, cause);
475
+ failed = true;
476
+ }
477
+ }
478
+ return outcome;
479
+ }
480
+ async function reduceLane(router, lane, tasks, controller, settlement, onReady) {
464
481
  const matches = lane[1];
465
482
  let failure = await settlement;
466
483
  let redirectLimitExceeded = false;
@@ -489,7 +506,7 @@ async function reduceLane(router, lane, tasks, controller, redirects, settlement
489
506
  }
490
507
  if ((failure?.[1][0] ?? 0) >= REDIRECTED) {
491
508
  const outcome = failure[1];
492
- if (outcome[0] !== REDIRECTED || outcome[1].options.reloadDocument || redirects < 20) {
509
+ if (outcome[0] !== REDIRECTED || outcome[1].options.reloadDocument || outcome[2]) {
493
510
  discardBackground(router, lane);
494
511
  return outcome;
495
512
  }
@@ -518,19 +535,18 @@ async function reduceLane(router, lane, tasks, controller, redirects, settlement
518
535
  }
519
536
  };
520
537
  install();
538
+ if (!outcome) onReady?.();
521
539
  const route = getRoute(router, match);
522
540
  try {
523
541
  await waitFor(outcome ? Promise.resolve().then(() => loadRouteChunk(route, kind === ERROR ? "errorComponent" : "notFoundComponent")) : Promise.all([loadRouteChunk(route), loadRouteChunk(route, "notFoundComponent")]), controller.signal);
524
542
  } catch (cause) {
525
- if (cause === controller.signal) {
543
+ if (cause === controller.signal && controller.signal.aborted) {
526
544
  discardBackground(router, lane);
527
- return [CANCELED];
545
+ return CANCELED_OUTCOME;
528
546
  }
529
547
  }
530
- if (!outcome) {
531
- match.status = "success";
532
- onReady?.();
533
- } else if (redirectLimitExceeded) {
548
+ if (!outcome) match.status = "success";
549
+ else if (redirectLimitExceeded) {
534
550
  controller.abort();
535
551
  await Promise.all([
536
552
  ...tasks.map((task) => task[1]),
@@ -564,7 +580,7 @@ async function projectLane(router, lane, signal, start = 0, end = lane[1].length
564
580
  match.styles = head?.styles;
565
581
  match.scripts = scripts;
566
582
  } catch (cause) {
567
- if (cause === signal) break;
583
+ if (cause === signal && signal.aborted) break;
568
584
  console.error(cause);
569
585
  }
570
586
  if (match.status !== "success" || match._notFound) break;
@@ -573,63 +589,66 @@ async function projectLane(router, lane, signal, start = 0, end = lane[1].length
573
589
  }
574
590
  async function executeClientLane(router, location, matches, options) {
575
591
  const matched = [location, matches];
576
- const presented = router.stores.matches.get();
577
- let plannedBoundary = matches.findIndex((match) => match._notFound);
578
- if (router.options.notFoundMode !== "root" && plannedBoundary >= 0) {
579
- const boundary = await getNotFoundBoundary(router, matched[1], void 0, options[0].signal, plannedBoundary);
580
- if (boundary !== plannedBoundary) {
581
- matches[plannedBoundary]._notFound = void 0;
582
- matches[boundary]._notFound = true;
592
+ const signal = options[0].signal;
593
+ let reduced;
594
+ try {
595
+ const presented = router.stores.matches.get();
596
+ let plannedBoundary = matches.findIndex((match) => match._notFound);
597
+ if (router.options.notFoundMode !== "root" && plannedBoundary >= 0) {
598
+ const boundary = await getNotFoundBoundary(router, matched[1], void 0, signal, plannedBoundary);
599
+ if (boundary !== plannedBoundary) {
600
+ matches[plannedBoundary]._notFound = void 0;
601
+ matches[boundary]._notFound = true;
602
+ }
603
+ plannedBoundary = boundary;
583
604
  }
584
- plannedBoundary = boundary;
585
- }
586
- let end = plannedBoundary < 0 ? matches.length : plannedBoundary + 1;
587
- let retainedEnd = 0;
588
- while (retainedEnd < end && retainedEnd !== plannedBoundary) {
589
- const match = matches[retainedEnd];
590
- const committed = options[3][retainedEnd];
591
- const visible = presented[retainedEnd];
592
- if (committed?.id !== match.id || committed.status !== "success" || committed._notFound || match.preload || visible?.id !== match.id || visible.status !== "success" || visible._notFound) break;
593
- retainedEnd++;
594
- }
595
- const tasks = [];
596
- const start = options[7] ?? 0;
597
- let semanticParent = start ? Promise.resolve(matched[1][start - 1]) : void 0;
598
- const planSuccessfulLane = () => {
599
- for (let index = start; index < end; index++) {
600
- if (options[0].signal.aborted) break;
601
- semanticParent = createLoaderTask(router, matched, index, tasks, semanticParent, options, retainedEnd);
605
+ let end = plannedBoundary < 0 ? matches.length : plannedBoundary + 1;
606
+ let retainedEnd = 0;
607
+ while (retainedEnd < end && retainedEnd !== plannedBoundary) {
608
+ const match = matches[retainedEnd];
609
+ const committed = options[2][retainedEnd];
610
+ const visible = presented[retainedEnd];
611
+ if (committed?.id !== match.id || committed.status !== "success" || committed._notFound || match.preload || visible?.id !== match.id || visible.status !== "success" || visible._notFound) break;
612
+ retainedEnd++;
602
613
  }
603
- };
604
- const failure = await contextualize(router, matched, options, end, planSuccessfulLane, retainedEnd);
605
- if (failure) {
606
- options[5] = true;
607
- end = failure[0];
608
- if (failure[1][0] === NOT_FOUND) {
609
- failure[2] = await getNotFoundBoundary(router, matched[1], failure, options[0].signal);
610
- end = Math.min(end, failure[2] + 1);
611
- } else if (failure[1][0] >= REDIRECTED) end = 0;
612
- planSuccessfulLane();
613
- }
614
- if (options[2]() && !options[4]) {
615
- const abort = [];
616
- for (const [id, flight] of router._flights ?? []) if (!flight[2]) {
617
- router._flights.delete(id);
618
- abort.push(flight[1]);
614
+ const tasks = [];
615
+ const start = options[6] ?? 0;
616
+ let semanticParent = start ? Promise.resolve(matched[1][start - 1]) : void 0;
617
+ const planSuccessfulLane = () => {
618
+ for (let index = start; index < end; index++) {
619
+ if (signal.aborted) break;
620
+ semanticParent = createLoaderTask(router, matched, index, tasks, semanticParent, options, retainedEnd);
621
+ }
622
+ };
623
+ const failure = await contextualize(router, matched, options, end, planSuccessfulLane, retainedEnd);
624
+ if (failure) {
625
+ options[4] = true;
626
+ end = failure[0];
627
+ if (failure[1][0] === NOT_FOUND) {
628
+ const boundary = await getNotFoundBoundary(router, matched[1], failure, signal);
629
+ failure[2] = boundary;
630
+ end = Math.min(end, boundary + 1);
631
+ } else if (failure[1][0] >= REDIRECTED) end = 0;
632
+ planSuccessfulLane();
619
633
  }
620
- for (const controller of abort) controller.abort();
621
- }
622
- let reduced;
623
- try {
624
- const reduction = reduceLane(router, matched, tasks, options[0], options[1], settleTasks(tasks, failure, matched[2]), options[8]);
634
+ if (!signal.aborted && !options[3]) {
635
+ const abort = [];
636
+ for (const [id, flight] of router._flights ?? []) if (!flight[2]) {
637
+ router._flights.delete(id);
638
+ abort.push(flight[1]);
639
+ }
640
+ for (const controller of abort) controller.abort();
641
+ }
642
+ const reduction = reduceLane(router, matched, tasks, options[0], settleTasks(tasks, failure, matched[2]), options[7]);
625
643
  if (matched[2]?.length) matched[3] = settleTasks(matched[2], void 0, void 0, reduction.then((foreground) => isControl(foreground) ? 0 : _getRenderedMatches(foreground[1]).length, () => 0));
626
644
  reduced = await reduction;
627
645
  } catch (cause) {
628
646
  discardBackground(router, matched);
647
+ if (cause === signal && signal.aborted) return CANCELED_OUTCOME;
629
648
  throw cause;
630
649
  }
631
650
  if (isControl(reduced)) return reduced;
632
- return projectLane(router, reduced, options[0].signal, options[7] === reduced[1].length ? options[7] : 0);
651
+ return projectLane(router, reduced, signal, options[6] === reduced[1].length ? options[6] : 0);
633
652
  }
634
653
  /**
635
654
  * Waits for `pendingMs`, then presents the complete lane. Rendering applies the
@@ -639,90 +658,94 @@ async function executeClientLane(router, location, matches, options) {
639
658
  */
640
659
  function offerPending(router, tx) {
641
660
  if (router._tx !== tx) return;
642
- let session = router._pending;
643
- let tookOver = false;
644
- const sessionMatchId = session?.[0][3][session[1]]?.id;
645
- if (session?.[0] !== tx) if (session && tx[3][session[1]]?.id === sessionMatchId) {
646
- session[0] = tx;
647
- tookOver = true;
648
- } else {
649
- clearTimeout(session?.[3]);
650
- router._pending = session = void 0;
651
- }
652
661
  const matches = tx[3];
653
662
  const presented = router.stores.matches.get();
654
- let boundary = -1;
655
- let delay;
656
- let min;
657
- let component;
658
- let presentedPending = false;
663
+ let session = router._pending;
659
664
  for (let index = 0; index < matches.length; index++) {
660
665
  const match = matches[index];
661
- const success = match.status === "success";
662
- presentedPending = presented[index]?.id === match.id && presented[index]?.status === "pending";
666
+ const success = match.status === "success" && !match._notFound;
667
+ const presentedPending = presented[index]?.id === match.id && presented[index]?.status === "pending";
663
668
  if (success && !presentedPending) continue;
664
669
  const route = getRoute(router, match);
665
- delay = success && presentedPending || match.invalid ? 0 : route.options.pendingMs ?? router.options.defaultPendingMs;
666
- component = route.options.pendingComponent ?? router.options.defaultPendingComponent;
667
- if (!component || typeof delay !== "number" || delay === Infinity) return;
668
- boundary = index;
669
- min = route.options.pendingMinMs ?? router.options.defaultPendingMinMs ?? 0;
670
- break;
671
- }
672
- if (boundary < 0) return;
673
- const matchId = matches[boundary].id;
674
- if (!session || session[1] !== boundary || sessionMatchId !== matchId) {
675
- clearTimeout(session?.[3]);
676
- router._pending = session = [
670
+ const delay = success && presentedPending || match.invalid ? 0 : route.options.pendingMs ?? router.options.defaultPendingMs;
671
+ const component = route.options.pendingComponent ?? router.options.defaultPendingComponent;
672
+ if (!component || typeof delay !== "number" || delay === Infinity) {
673
+ if (session) {
674
+ session[0] = tx;
675
+ session[2] = 0;
676
+ session[4] = true;
677
+ }
678
+ return;
679
+ }
680
+ const min = route.options.pendingMinMs ?? router.options.defaultPendingMinMs ?? 0;
681
+ let tookOver = false;
682
+ if (session?.[1] === match.id) {
683
+ tookOver = session[0] !== tx;
684
+ session[0] = tx;
685
+ } else {
686
+ clearTimeout(session?.[3]);
687
+ router._pending = session = void 0;
688
+ }
689
+ if (!session) router._pending = session = [
677
690
  tx,
678
- boundary,
691
+ match.id,
679
692
  presentedPending ? Date.now() + min : tx[4] + delay,
680
693
  void 0,
681
- presentedPending ? Promise.resolve(true) : void 0,
694
+ presentedPending || void 0,
682
695
  component
683
696
  ];
684
- }
685
- if (session[4] && !tookOver && session[5] === component) return;
686
- session[5] = component;
687
- if (!session[4]) {
688
- clearTimeout(session[3]);
689
- const remaining = session[2] - Date.now();
690
- if (remaining > 0) {
691
- session[3] = setTimeout(() => offerPending(router, tx), remaining);
692
- return;
697
+ if (session[4] && !tookOver && session[5] === component) return;
698
+ session[5] = component;
699
+ if (!session[4]) {
700
+ clearTimeout(session[3]);
701
+ const remaining = session[2] - Date.now();
702
+ if (remaining > 0) {
703
+ session[3] = setTimeout(() => offerPending(router, tx), remaining);
704
+ return;
705
+ }
706
+ session[2] = 0;
693
707
  }
694
- session[2] = 0;
708
+ const offered = matches.map((match) => ({
709
+ ...match,
710
+ _flight: void 0
711
+ }));
712
+ offered[index].status = "pending";
713
+ const ack = session[4] = router.startTransition(() => router.stores.setMatches(offered), offered).then((rendered) => {
714
+ if (rendered && router._pending === session && session[4] === ack && !session[2]) session[2] = Date.now() + min;
715
+ return rendered;
716
+ });
717
+ return;
695
718
  }
696
- const offered = matches.map((match) => ({
697
- ...match,
698
- _flight: void 0
699
- }));
700
- offered[boundary].status = "pending";
701
- const ack = router.startTransition(() => router.stores.setMatches(offered), offered).then((rendered) => {
702
- if (rendered && router._pending === session && session[4] === ack && !session[2]) session[2] = Date.now() + min;
703
- return rendered;
704
- });
705
- session[4] = ack;
706
719
  }
707
720
  /**
708
- * Cancels pending UI timing when its load ends. The ownership check prevents
709
- * an older, superseded load from clearing pending UI that a newer load took over.
721
+ * Cancels pending UI timing unless the current successor can take over the
722
+ * same boundary that remains painted.
710
723
  */
711
724
  function finishPending(router, tx) {
712
725
  const session = router._pending;
713
- if (session?.[0] === tx) {
714
- clearTimeout(session[3]);
726
+ if (router._tx === tx || !router._tx?.[3].some((match) => match.id === session?.[1])) {
727
+ clearTimeout(session?.[3]);
715
728
  router._pending = void 0;
716
729
  }
717
730
  }
731
+ async function awaitPendingMinimum(router, tx) {
732
+ const session = router._pending;
733
+ if (!session) return;
734
+ clearTimeout(session[3]);
735
+ const remaining = session[2] - Date.now();
736
+ if (!session[4] || remaining <= 0 || !_getRenderedMatches(tx[3]).some((match) => match.id === session[1])) return;
737
+ let timer;
738
+ try {
739
+ await waitFor(new Promise((resolve) => {
740
+ timer = setTimeout(resolve, remaining);
741
+ }), tx[0].signal);
742
+ } catch {}
743
+ clearTimeout(timer);
744
+ }
718
745
  function publishMatches(router, matches) {
719
746
  router._committed = matches;
720
747
  router.stores.setMatches(matches);
721
748
  }
722
- function discardLane(router, lane) {
723
- transferMatchResources(router, lane[1]);
724
- discardBackground(router, lane);
725
- }
726
749
  function commitMatches(router, tx, matches, resolvedPrefix) {
727
750
  const previous = router._committed;
728
751
  const previousCached = router._cache;
@@ -732,111 +755,29 @@ function commitMatches(router, tx, matches, resolvedPrefix) {
732
755
  }
733
756
  const cut = _getRenderedMatches(matches).length;
734
757
  const cached = /* @__PURE__ */ new Map();
735
- const now = Date.now();
736
- for (const match of [...previous, ...previousCached.values()]) {
737
- if (match.status !== "success" || matches.some((candidate, index) => candidate.id === match.id && (index < cut || candidate.status === "success"))) continue;
738
- const route = getRoute(router, match);
739
- if (!route.options.loader || now - match.updatedAt >= (match.preload ? route.options.preloadGcTime ?? router.options.defaultPreloadGcTime ?? 3e5 : route.options.gcTime ?? router.options.defaultGcTime ?? 3e5)) continue;
740
- cached.set(match.id, previousCached.get(match.id) === match ? match : {
741
- ...match,
742
- _flight: void 0,
743
- isFetching: false,
744
- context: {}
745
- });
758
+ if (process.env.NODE_ENV === "production" || !tx[6]) {
759
+ const now = Date.now();
760
+ for (const match of [...previous, ...previousCached.values()]) {
761
+ if (match.status !== "success" || matches.some((candidate, index) => candidate.id === match.id && (index < cut || candidate.status === "success"))) continue;
762
+ const route = getRoute(router, match);
763
+ if (!route.options.loader || now - match.updatedAt >= (match.preload ? route.options.preloadGcTime ?? router.options.defaultPreloadGcTime ?? 3e5 : route.options.gcTime ?? router.options.defaultGcTime ?? 3e5)) continue;
764
+ cached.set(match.id, previousCached.get(match.id) === match ? match : {
765
+ ...match,
766
+ _flight: void 0,
767
+ isFetching: false,
768
+ context: {}
769
+ });
770
+ }
746
771
  }
747
772
  tx[3] = [];
748
773
  router._cache = cached;
749
774
  publishMatches(router, matches);
750
775
  transferMatchResources(router, [...previousCached.values(), ...previous], [...matches, ...cached.values()]);
751
- require_router.runRouteLifecycle(router, previous, matches, () => router._tx === tx);
752
- }
753
- function commitRefreshMatches(router, tx, matches, checkpoint) {
754
- const previous = router._committed;
755
- const previousCached = router._cache;
756
- for (const match of matches) match.preload = false;
757
- const cached = /* @__PURE__ */ new Map();
758
- tx[3] = [];
759
- router._cache = cached;
760
- checkpoint.previousMatches = previous;
761
- checkpoint.previousCache = previousCached;
762
- checkpoint.published = true;
763
- publishMatches(router, matches);
764
- if (!checkpoint.published || router._tx !== tx) return;
765
- require_router.runRouteLifecycle(router, previous, matches, () => router._tx === tx);
766
- }
767
- function settlePublication(router, checkpoint) {
768
- if (!checkpoint.published) return;
769
- checkpoint.published = false;
770
- transferMatchResources(router, [...checkpoint.previousCache.values(), ...checkpoint.previousMatches], [...router._cache.values(), ...router._committed]);
771
- }
772
- function rollbackPublication(router, tx, lane, checkpoint) {
773
- if (!checkpoint.published || router._tx !== tx || router._committed !== lane[1]) {
774
- settlePublication(router, checkpoint);
775
- return false;
776
- }
777
- const discarded = [...router._cache.values(), ...router._committed];
778
- const restored = [...checkpoint.previousCache.values(), ...checkpoint.previousMatches];
779
- router._cache = checkpoint.previousCache;
780
- router._committed = checkpoint.previousMatches;
781
- checkpoint.published = false;
782
- for (const match of discarded) if (!restored.includes(match) && match._flight && router._flights?.get(match.id) === match._flight) router._flights.delete(match.id);
783
- finishPending(router, tx);
784
- router.batch(() => {
785
- router.stores.status.set("idle");
786
- router.stores.setMatches(checkpoint.previousPresentation);
787
- });
788
- tx[0].abort();
789
- transferMatchResources(router, discarded, restored);
790
- discardBackground(router, lane);
791
- if (router._tx === tx && router._commitPromise === checkpoint.commitPromise) {
792
- router._commitPromise?.resolve();
793
- router._commitPromise = void 0;
794
- }
795
- return true;
796
- }
797
- async function transitionRefresh(router, tx, lane, changeInfo) {
798
- const refresh = tx[6];
799
- const checkpoint = {
800
- previousMatches: router._committed,
801
- previousPresentation: refresh[0],
802
- previousCache: router._cache,
803
- commitPromise: router._commitPromise,
804
- published: false
805
- };
806
- const commit = () => {
807
- finishPending(router, tx);
808
- refresh[2] = rollback;
809
- commitRefreshMatches(router, tx, lane[1], checkpoint);
810
- if (!checkpoint.published || router._tx !== tx) return;
811
- router.emit({
812
- type: "onLoad",
813
- ...changeInfo
814
- });
815
- if (router._tx === tx) router.emit({
816
- type: "onBeforeRouteMount",
817
- ...changeInfo
818
- });
819
- };
820
- const rollback = () => {
821
- if (refresh[2] === rollback) refresh[2] = void 0;
822
- const restored = rollbackPublication(router, tx, lane, checkpoint);
823
- router._cancelTransition?.();
824
- return restored;
825
- };
826
- try {
827
- const rendered = await router.startTransition(commit, lane[1]);
828
- if (refresh[2] === rollback) refresh[2] = void 0;
829
- if (checkpoint.published) {
830
- const handoff = refresh[1];
831
- if (handoff && router._handoff === handoff) handoff[1]();
832
- if (router._tx === tx) tx[6] = void 0;
833
- }
834
- settlePublication(router, checkpoint);
835
- return rendered;
836
- } catch (cause) {
837
- if (rollback()) return;
838
- throw cause;
776
+ if (process.env.NODE_ENV !== "production") {
777
+ const handoff = tx[6]?.[0];
778
+ if (handoff && router._handoff === handoff) handoff[1]();
839
779
  }
780
+ require_router.runRouteLifecycle(router, previous, matches, tx);
840
781
  }
841
782
  async function awaitCurrent(router, owner) {
842
783
  let current = router._tx;
@@ -846,28 +787,40 @@ async function awaitCurrent(router, owner) {
846
787
  current = router._tx;
847
788
  }
848
789
  }
849
- async function followRedirect(router, tx, redirect) {
850
- await router.navigate({
851
- ...redirect.options,
790
+ async function followRedirect(router, tx, outcome) {
791
+ const redirect = outcome[1];
792
+ const location = outcome[2];
793
+ if (!location) {
794
+ await router.navigate({
795
+ ...redirect.options,
796
+ replace: true,
797
+ ignoreBlocker: true
798
+ });
799
+ return;
800
+ }
801
+ if (redirect.options.reloadDocument) {
802
+ await router.navigate({
803
+ href: location.publicHref,
804
+ reloadDocument: true,
805
+ replace: true,
806
+ ignoreBlocker: true
807
+ });
808
+ return;
809
+ }
810
+ location._redirects = tx[1] + 1;
811
+ router._pendingLocation = location;
812
+ const committed = router.commitLocation({
813
+ ...location,
814
+ viewTransition: redirect.options.viewTransition,
852
815
  replace: true,
853
- ignoreBlocker: true,
854
- _redirects: tx[1] + 1
816
+ resetScroll: redirect.options.resetScroll,
817
+ hashScrollIntoView: redirect.options.hashScrollIntoView,
818
+ ignoreBlocker: true
855
819
  });
856
- }
857
- function restoreCommitted(router, tx) {
858
- finishPending(router, tx);
859
- tx[0].abort();
860
- transferMatchResources(router, tx[3]);
861
- tx[3] = [];
862
- if (router._tx !== tx) return;
863
- router.batch(() => {
864
- router.stores.status.set("idle");
865
- router.stores.setMatches(router._committed);
820
+ queueMicrotask(() => {
821
+ if (router._pendingLocation === location) router._pendingLocation = void 0;
866
822
  });
867
- if (router._tx === tx) {
868
- router._commitPromise?.resolve();
869
- router._commitPromise = void 0;
870
- }
823
+ await committed;
871
824
  }
872
825
  async function runBackground(router, tx, base, tasks, settlement) {
873
826
  const next = base.map((match) => ({ ...match }));
@@ -879,14 +832,14 @@ async function runBackground(router, tx, base, tasks, settlement) {
879
832
  const lane = [tx[2], next];
880
833
  let reduced;
881
834
  try {
882
- reduced = await reduceLane(router, lane, tasks, tx[0], tx[1], settlement);
835
+ reduced = await reduceLane(router, lane, tasks, tx[0], settlement);
883
836
  } catch (cause) {
884
837
  transferMatchResources(router, next);
885
838
  throw cause;
886
839
  }
887
840
  if (isControl(reduced)) {
888
841
  transferMatchResources(router, next);
889
- if (reduced[0] === REDIRECTED && router._tx === tx && router._committed === base) await followRedirect(router, tx, reduced[1]);
842
+ if (reduced[0] === REDIRECTED && router._tx === tx && router._committed === base) await followRedirect(router, tx, reduced);
890
843
  return;
891
844
  }
892
845
  const projected = await projectLane(router, reduced, tx[0].signal);
@@ -908,7 +861,6 @@ async function runClientTransaction(router, tx, forceStaleReload, onReady, sync,
908
861
  const options = [
909
862
  tx[0],
910
863
  tx[1],
911
- () => router._tx === tx && !!tx[3].length,
912
864
  router._committed,
913
865
  void 0,
914
866
  sync,
@@ -918,50 +870,30 @@ async function runClientTransaction(router, tx, forceStaleReload, onReady, sync,
918
870
  ];
919
871
  const result = await executeClientLane(router, tx[2], tx[3], options);
920
872
  if (isControl(result)) {
921
- if (result[0] === REDIRECTED && router._tx === tx) {
873
+ const follow = result[0] === REDIRECTED && router._tx === tx;
874
+ if (!follow || result[1].options.reloadDocument) finishPending(router, tx);
875
+ transferMatchResources(router, tx[3]);
876
+ tx[3] = [];
877
+ if (!follow) return;
878
+ if (router._tx !== tx) {
922
879
  finishPending(router, tx);
923
- transferMatchResources(router, tx[3]);
924
- tx[3] = [];
925
- if (router._tx === tx) {
926
- if (process.env.NODE_ENV !== "production" && tx[6]) router._refreshNextLoad = true;
927
- await followRedirect(router, tx, result[1]);
928
- }
929
- } else restoreCommitted(router, tx);
880
+ return;
881
+ }
882
+ if (process.env.NODE_ENV !== "production" && tx[6]) router._refreshNextLoad = true;
883
+ await followRedirect(router, tx, result);
930
884
  return;
931
885
  }
932
- const pending = router._pending;
933
- if (pending?.[0] === tx) {
934
- /**
935
- * Loading finished, so cancel any pending reveal. If the fallback rendered,
936
- * wait out the rest of `pendingMinMs` before replacing it. If it never
937
- * rendered, there is no minimum wait; if another load took it over, that
938
- * load owns the deadline.
939
- */
940
- clearTimeout(pending[3]);
941
- if (pending[4]) {
942
- const signal = tx[0].signal;
943
- let rendered = false;
944
- try {
945
- rendered = await waitFor(pending[4], signal);
946
- } catch (cause) {
947
- if (cause !== signal) throw cause;
948
- }
949
- if (rendered && router._pending === pending && pending[0] === tx) {
950
- const remaining = pending[2] - Date.now();
951
- if (remaining > 0) {
952
- try {
953
- await waitFor(new Promise((resolve) => {
954
- pending[3] = setTimeout(resolve, remaining);
955
- }), signal);
956
- } catch {}
957
- clearTimeout(pending[3]);
958
- }
959
- }
960
- }
886
+ if (router._tx !== tx) {
887
+ finishPending(router, tx);
888
+ transferMatchResources(router, result[1]);
889
+ discardBackground(router, result);
890
+ return;
961
891
  }
892
+ await awaitPendingMinimum(router, tx);
962
893
  if (router._tx !== tx) {
963
894
  finishPending(router, tx);
964
- discardLane(router, result);
895
+ transferMatchResources(router, result[1]);
896
+ discardBackground(router, result);
965
897
  return;
966
898
  }
967
899
  const toLocation = tx[2];
@@ -969,7 +901,16 @@ async function runClientTransaction(router, tx, forceStaleReload, onReady, sync,
969
901
  const background = result[2];
970
902
  await router.startViewTransition(async () => {
971
903
  if (router._tx !== tx) {
972
- discardLane(router, result);
904
+ finishPending(router, tx);
905
+ transferMatchResources(router, result[1]);
906
+ discardBackground(router, result);
907
+ return;
908
+ }
909
+ await awaitPendingMinimum(router, tx);
910
+ if (router._tx !== tx) {
911
+ finishPending(router, tx);
912
+ transferMatchResources(router, result[1]);
913
+ discardBackground(router, result);
973
914
  return;
974
915
  }
975
916
  const commit = () => {
@@ -985,8 +926,8 @@ async function runClientTransaction(router, tx, forceStaleReload, onReady, sync,
985
926
  ...changeInfo
986
927
  });
987
928
  };
988
- const rendered = process.env.NODE_ENV !== "production" && tx[6] ? await transitionRefresh(router, tx, result, changeInfo) : await router.startTransition(commit, result[1]);
989
- if (process.env.NODE_ENV !== "production" && tx[6] && rendered === void 0) return;
929
+ const rendered = await router.startTransition(commit, result[1]);
930
+ if (process.env.NODE_ENV !== "production" && tx[6]) tx[6] = void 0;
990
931
  if (router._tx !== tx) {
991
932
  discardBackground(router, result);
992
933
  return;
@@ -1011,11 +952,7 @@ async function runClientTransaction(router, tx, forceStaleReload, onReady, sync,
1011
952
  }
1012
953
  async function loadClientRoute(router, opts) {
1013
954
  let rematerialize = false;
1014
- if (process.env.NODE_ENV !== "production") {
1015
- router._tx?.[6]?.[2]?.();
1016
- rematerialize = !!router._refreshNextLoad || !!router._tx?.[6];
1017
- }
1018
- const refreshPresentation = rematerialize ? router.stores.matches.get() : void 0;
955
+ if (process.env.NODE_ENV !== "production") rematerialize = !!router._refreshNextLoad || !!router._tx?.[6];
1019
956
  const previousOwner = router._tx;
1020
957
  const resolvedLocation = router.stores.resolvedLocation.get();
1021
958
  const previousLocation = resolvedLocation ?? router.stores.location.get();
@@ -1047,31 +984,12 @@ async function loadClientRoute(router, opts) {
1047
984
  return;
1048
985
  }
1049
986
  const sameHref = previousLocation.href === location.href;
1050
- let matches;
1051
987
  let controller = preflight;
1052
- try {
1053
- matches = process.env.NODE_ENV !== "production" && rematerialize ? router.matchRoutes(location, {
1054
- _controller: preflight,
1055
- _rematerialize: true
1056
- }) : router.matchRoutes(location, { _controller: preflight });
1057
- acquireMatchResources(matches);
1058
- } catch (cause) {
1059
- preflight.abort();
1060
- if (!require_redirect.isRedirect(cause)) {
1061
- if (process.env.NODE_ENV !== "production" && rematerialize) router._refreshNextLoad = void 0;
1062
- await awaitCurrent(router);
1063
- router._commitPromise?.resolve();
1064
- router._commitPromise = void 0;
1065
- return;
1066
- }
1067
- await router.navigate({
1068
- ...cause.options,
1069
- replace: true,
1070
- ignoreBlocker: true
1071
- });
1072
- await awaitCurrent(router, previousOwner);
1073
- return;
1074
- }
988
+ const matches = process.env.NODE_ENV !== "production" && rematerialize ? router.matchRoutes(location, {
989
+ _controller: preflight,
990
+ _rematerialize: true
991
+ }) : router.matchRoutes(location, { _controller: preflight });
992
+ acquireMatchResources(matches);
1075
993
  const resolvedPrefix = hydrationController ? handoff[1](matches) : void 0;
1076
994
  if (resolvedPrefix) controller = hydrationController;
1077
995
  else hydrationController?.abort();
@@ -1087,12 +1005,10 @@ async function loadClientRoute(router, opts) {
1087
1005
  location,
1088
1006
  matches,
1089
1007
  Date.now(),
1090
- Promise.resolve().then(() => runClientTransaction(router, tx, sameHref, () => offerPending(router, tx), opts?.sync, resolvedPrefix)).catch(() => {
1091
- if (router._tx === tx) restoreCommitted(router, tx);
1092
- })
1008
+ Promise.resolve().then(() => runClientTransaction(router, tx, sameHref, () => offerPending(router, tx), opts?.sync, resolvedPrefix)).then()
1093
1009
  ];
1094
1010
  if (process.env.NODE_ENV !== "production" && rematerialize) {
1095
- tx[6] = [refreshPresentation, handoff];
1011
+ tx[6] = [handoff];
1096
1012
  router._refreshNextLoad = void 0;
1097
1013
  }
1098
1014
  router._tx = tx;
@@ -1114,15 +1030,11 @@ async function loadClientRoute(router, opts) {
1114
1030
  router.stores.status.set("pending");
1115
1031
  router.stores.location.set(location);
1116
1032
  });
1117
- if (!resolvedLocation && !matches.some((match) => match._notFound)) offerPending(router, tx);
1118
- try {
1119
- await tx[5];
1120
- } finally {
1121
- await awaitCurrent(router, tx);
1122
- }
1033
+ if (resolvedPrefix || !router._committed.length && !matches.some((match) => match._notFound)) offerPending(router, tx);
1034
+ await tx[5];
1035
+ await awaitCurrent(router, tx);
1123
1036
  }
1124
1037
  async function refreshClientRoute(router) {
1125
- router._tx?.[6]?.[2]?.();
1126
1038
  const pending = router._tx;
1127
1039
  if (pending && !pending[6] && router.stores.status.get() === "pending") {
1128
1040
  await pending[5];
@@ -1133,10 +1045,9 @@ async function refreshClientRoute(router) {
1133
1045
  router._refreshNextLoad = true;
1134
1046
  await loadClientRoute(router, { sync: true });
1135
1047
  }
1136
- async function preloadClientRoute(router, opts, redirects = 0) {
1137
- if (redirects > 20) return;
1048
+ async function preloadClientRoute(router, opts, redirects = 0, builtLocation) {
1138
1049
  if (process.env.NODE_ENV !== "production" && (router._refreshNextLoad || router._tx?.[6])) return;
1139
- const location = opts._builtLocation ?? router.buildLocation(opts);
1050
+ const location = builtLocation ?? router.buildLocation(opts);
1140
1051
  const base = router._committed;
1141
1052
  const controller = new AbortController();
1142
1053
  let matches;
@@ -1156,7 +1067,6 @@ async function preloadClientRoute(router, opts, redirects = 0) {
1156
1067
  result = await executeClientLane(router, location, matches, [
1157
1068
  controller,
1158
1069
  redirects,
1159
- () => true,
1160
1070
  base,
1161
1071
  true
1162
1072
  ]);
@@ -1166,10 +1076,7 @@ async function preloadClientRoute(router, opts, redirects = 0) {
1166
1076
  controller.abort();
1167
1077
  }
1168
1078
  if (!isControl(result)) return result[1];
1169
- if (active && result[0] === REDIRECTED && !result[1].options.reloadDocument) return preloadClientRoute(router, {
1170
- ...result[1].options,
1171
- _fromLocation: location
1172
- }, redirects + 1);
1079
+ if (active && result[0] === REDIRECTED && !result[1].options.reloadDocument) return preloadClientRoute(router, result[1].options, redirects + 1, result[2]);
1173
1080
  } catch (cause) {
1174
1081
  if (!require_not_found.isNotFound(cause)) console.error(cause);
1175
1082
  }
@@ -1290,7 +1197,10 @@ async function hydrate(router) {
1290
1197
  params: match.params,
1291
1198
  context: parentContext,
1292
1199
  location,
1293
- navigate: navigateFrom(router, location),
1200
+ navigate: (opts) => router.navigate({
1201
+ ...opts,
1202
+ _fromLocation: location
1203
+ }),
1294
1204
  buildLocation: router.buildLocation,
1295
1205
  cause: match.cause,
1296
1206
  abortController: controller,