@tanstack/router-core 1.134.15 → 1.134.20

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.
package/src/Matches.ts CHANGED
@@ -148,6 +148,8 @@ export interface RouteMatch<
148
148
  displayPendingPromise?: Promise<void>
149
149
  minPendingPromise?: ControlledPromise<void>
150
150
  dehydrated?: boolean
151
+ /** @internal */
152
+ error?: unknown
151
153
  }
152
154
  loaderData?: TLoaderData
153
155
  /** @internal */
@@ -111,6 +111,8 @@ const handleRedirectAndNotFound = (
111
111
 
112
112
  const status = isRedirect(err) ? 'redirected' : 'notFound'
113
113
 
114
+ match._nonReactive.error = err
115
+
114
116
  inner.updateMatch(match.id, (prev) => ({
115
117
  ...prev,
116
118
  status,
@@ -560,9 +562,23 @@ const getLoaderContext = (
560
562
  route: AnyRoute,
561
563
  ): LoaderFnContext => {
562
564
  const parentMatchPromise = inner.matchPromises[index - 1] as any
563
- const { params, loaderDeps, abortController, context, cause } =
565
+ const { params, loaderDeps, abortController, cause } =
564
566
  inner.router.getMatch(matchId)!
565
567
 
568
+ let context = inner.router.options.context ?? {}
569
+
570
+ for (let i = 0; i <= index; i++) {
571
+ const innerMatch = inner.matches[i]
572
+ if (!innerMatch) continue
573
+ const m = inner.router.getMatch(innerMatch.id)
574
+ if (!m) continue
575
+ context = {
576
+ ...context,
577
+ ...(m.__routeContext ?? {}),
578
+ ...(m.__beforeLoadContext ?? {}),
579
+ }
580
+ }
581
+
566
582
  const preload = resolvePreload(inner, matchId)
567
583
 
568
584
  return {
@@ -750,8 +766,9 @@ const loadRouteMatch = async (
750
766
  }
751
767
  await prevMatch._nonReactive.loaderPromise
752
768
  const match = inner.router.getMatch(matchId)!
753
- if (match.error) {
754
- handleRedirectAndNotFound(inner, match, match.error)
769
+ const error = match._nonReactive.error || match.error
770
+ if (error) {
771
+ handleRedirectAndNotFound(inner, match, error)
755
772
  }
756
773
  } else {
757
774
  // This is where all of the stale-while-revalidate magic happens
package/src/router.ts CHANGED
@@ -896,6 +896,7 @@ export class RouterCore<
896
896
  rewrite?: LocationRewrite
897
897
  origin?: string
898
898
  latestLocation!: ParsedLocation<FullSearchSchema<TRouteTree>>
899
+ pendingBuiltLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
899
900
  basepath!: string
900
901
  routeTree!: TRouteTree
901
902
  routesById!: RoutesById<TRouteTree>
@@ -1593,7 +1594,8 @@ export class RouterCore<
1593
1594
  } = {},
1594
1595
  ): ParsedLocation => {
1595
1596
  // We allow the caller to override the current location
1596
- const currentLocation = dest._fromLocation || this.latestLocation
1597
+ const currentLocation =
1598
+ dest._fromLocation || this.pendingBuiltLocation || this.latestLocation
1597
1599
 
1598
1600
  const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
1599
1601
  _buildLocation: true,
@@ -1956,7 +1958,11 @@ export class RouterCore<
1956
1958
  _includeValidateSearch: true,
1957
1959
  })
1958
1960
 
1959
- return this.commitLocation({
1961
+ this.pendingBuiltLocation = location as ParsedLocation<
1962
+ FullSearchSchema<TRouteTree>
1963
+ >
1964
+
1965
+ const commitPromise = this.commitLocation({
1960
1966
  ...location,
1961
1967
  viewTransition,
1962
1968
  replace,
@@ -1964,6 +1970,16 @@ export class RouterCore<
1964
1970
  hashScrollIntoView,
1965
1971
  ignoreBlocker,
1966
1972
  })
1973
+
1974
+ // Clear pending location after commit starts
1975
+ // We do this on next microtask to allow synchronous navigate calls to chain
1976
+ Promise.resolve().then(() => {
1977
+ if (this.pendingBuiltLocation === location) {
1978
+ this.pendingBuiltLocation = undefined
1979
+ }
1980
+ })
1981
+
1982
+ return commitPromise
1967
1983
  }
1968
1984
 
1969
1985
  /**
@@ -2279,23 +2295,27 @@ export class RouterCore<
2279
2295
  }
2280
2296
 
2281
2297
  updateMatch: UpdateMatchFn = (id, updater) => {
2282
- const matchesKey = this.state.pendingMatches?.some((d) => d.id === id)
2283
- ? 'pendingMatches'
2284
- : this.state.matches.some((d) => d.id === id)
2285
- ? 'matches'
2286
- : this.state.cachedMatches.some((d) => d.id === id)
2287
- ? 'cachedMatches'
2288
- : ''
2289
-
2290
- if (matchesKey) {
2291
- this.__store.setState((s) => ({
2292
- ...s,
2293
- [matchesKey]: s[matchesKey]?.map((d) => (d.id === id ? updater(d) : d)),
2294
- }))
2295
- }
2298
+ this.startTransition(() => {
2299
+ const matchesKey = this.state.pendingMatches?.some((d) => d.id === id)
2300
+ ? 'pendingMatches'
2301
+ : this.state.matches.some((d) => d.id === id)
2302
+ ? 'matches'
2303
+ : this.state.cachedMatches.some((d) => d.id === id)
2304
+ ? 'cachedMatches'
2305
+ : ''
2306
+
2307
+ if (matchesKey) {
2308
+ this.__store.setState((s) => ({
2309
+ ...s,
2310
+ [matchesKey]: s[matchesKey]?.map((d) =>
2311
+ d.id === id ? updater(d) : d,
2312
+ ),
2313
+ }))
2314
+ }
2315
+ })
2296
2316
  }
2297
2317
 
2298
- getMatch: GetMatchFn = (matchId: string) => {
2318
+ getMatch: GetMatchFn = (matchId: string): AnyRouteMatch | undefined => {
2299
2319
  const findFn = (d: { id: string }) => d.id === matchId
2300
2320
  return (
2301
2321
  this.state.cachedMatches.find(findFn) ??