@tanstack/router-core 1.131.7 → 1.132.0-alpha.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 (88) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +9 -7
  3. package/dist/cjs/defer.cjs +1 -1
  4. package/dist/cjs/defer.cjs.map +1 -1
  5. package/dist/cjs/index.cjs +0 -2
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.cts +1 -1
  8. package/dist/cjs/lru-cache.cjs.map +1 -1
  9. package/dist/cjs/not-found.cjs +1 -1
  10. package/dist/cjs/not-found.cjs.map +1 -1
  11. package/dist/cjs/path.cjs +10 -12
  12. package/dist/cjs/path.cjs.map +1 -1
  13. package/dist/cjs/qss.cjs.map +1 -1
  14. package/dist/cjs/redirect.cjs.map +1 -1
  15. package/dist/cjs/route.cjs +6 -7
  16. package/dist/cjs/route.cjs.map +1 -1
  17. package/dist/cjs/router.cjs +168 -196
  18. package/dist/cjs/router.cjs.map +1 -1
  19. package/dist/cjs/router.d.cts +1 -2
  20. package/dist/cjs/scroll-restoration.cjs +2 -3
  21. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  22. package/dist/cjs/scroll-restoration.d.cts +9 -0
  23. package/dist/cjs/searchMiddleware.cjs.map +1 -1
  24. package/dist/cjs/searchParams.cjs.map +1 -1
  25. package/dist/cjs/ssr/createRequestHandler.cjs +2 -3
  26. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
  27. package/dist/cjs/ssr/handlerCallback.cjs.map +1 -1
  28. package/dist/cjs/ssr/headers.cjs.map +1 -1
  29. package/dist/cjs/ssr/json.cjs +1 -1
  30. package/dist/cjs/ssr/json.cjs.map +1 -1
  31. package/dist/cjs/ssr/seroval-plugins.cjs.map +1 -1
  32. package/dist/cjs/ssr/ssr-client.cjs +47 -48
  33. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  34. package/dist/cjs/ssr/ssr-server.cjs +2 -3
  35. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  36. package/dist/cjs/ssr/transformStreamWithRouter.cjs +3 -4
  37. package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
  38. package/dist/cjs/typePrimitives.d.cts +6 -6
  39. package/dist/cjs/utils.cjs +4 -27
  40. package/dist/cjs/utils.cjs.map +1 -1
  41. package/dist/cjs/utils.d.cts +0 -6
  42. package/dist/esm/Matches.d.ts +9 -7
  43. package/dist/esm/Matches.js.map +1 -1
  44. package/dist/esm/defer.js +1 -1
  45. package/dist/esm/defer.js.map +1 -1
  46. package/dist/esm/index.d.ts +1 -1
  47. package/dist/esm/index.js +1 -3
  48. package/dist/esm/lru-cache.js.map +1 -1
  49. package/dist/esm/not-found.js +1 -1
  50. package/dist/esm/not-found.js.map +1 -1
  51. package/dist/esm/path.js +10 -12
  52. package/dist/esm/path.js.map +1 -1
  53. package/dist/esm/qss.js.map +1 -1
  54. package/dist/esm/redirect.js.map +1 -1
  55. package/dist/esm/route.js +6 -7
  56. package/dist/esm/route.js.map +1 -1
  57. package/dist/esm/router.d.ts +1 -2
  58. package/dist/esm/router.js +168 -196
  59. package/dist/esm/router.js.map +1 -1
  60. package/dist/esm/scroll-restoration.d.ts +9 -0
  61. package/dist/esm/scroll-restoration.js +2 -3
  62. package/dist/esm/scroll-restoration.js.map +1 -1
  63. package/dist/esm/searchMiddleware.js.map +1 -1
  64. package/dist/esm/searchParams.js.map +1 -1
  65. package/dist/esm/ssr/createRequestHandler.js +2 -3
  66. package/dist/esm/ssr/createRequestHandler.js.map +1 -1
  67. package/dist/esm/ssr/handlerCallback.js.map +1 -1
  68. package/dist/esm/ssr/headers.js.map +1 -1
  69. package/dist/esm/ssr/json.js +1 -1
  70. package/dist/esm/ssr/json.js.map +1 -1
  71. package/dist/esm/ssr/seroval-plugins.js.map +1 -1
  72. package/dist/esm/ssr/ssr-client.js +47 -48
  73. package/dist/esm/ssr/ssr-client.js.map +1 -1
  74. package/dist/esm/ssr/ssr-server.js +2 -3
  75. package/dist/esm/ssr/ssr-server.js.map +1 -1
  76. package/dist/esm/ssr/transformStreamWithRouter.js +3 -4
  77. package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
  78. package/dist/esm/typePrimitives.d.ts +6 -6
  79. package/dist/esm/utils.d.ts +0 -6
  80. package/dist/esm/utils.js +5 -28
  81. package/dist/esm/utils.js.map +1 -1
  82. package/package.json +2 -2
  83. package/src/Matches.ts +8 -16
  84. package/src/index.ts +0 -2
  85. package/src/router.ts +112 -110
  86. package/src/ssr/ssr-client.ts +41 -42
  87. package/src/typePrimitives.ts +6 -6
  88. package/src/utils.ts +0 -41
package/src/router.ts CHANGED
@@ -614,8 +614,8 @@ export type InvalidateFn<TRouter extends AnyRouter> = (opts?: {
614
614
  }) => Promise<void>
615
615
 
616
616
  export type ParseLocationFn<TRouteTree extends AnyRoute> = (
617
- locationToParse: HistoryLocation,
618
617
  previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>,
618
+ locationToParse?: HistoryLocation,
619
619
  ) => ParsedLocation<FullSearchSchema<TRouteTree>>
620
620
 
621
621
  export type GetMatchRoutesFn = (
@@ -901,7 +901,7 @@ export class RouterCore<
901
901
  initialEntries: [this.basepath || '/'],
902
902
  })
903
903
  : createBrowserHistory()) as TRouterHistory)
904
- this.updateLatestLocation()
904
+ this.latestLocation = this.parseLocation()
905
905
  }
906
906
 
907
907
  if (this.options.routeTree !== this.routeTree) {
@@ -939,13 +939,6 @@ export class RouterCore<
939
939
  return this.__store.state
940
940
  }
941
941
 
942
- updateLatestLocation = () => {
943
- this.latestLocation = this.parseLocation(
944
- this.history.location,
945
- this.latestLocation,
946
- )
947
- }
948
-
949
942
  buildRouteTree = () => {
950
943
  const { routesById, routesByPath, flatRoutes } = processRouteTree({
951
944
  routeTree: this.routeTree,
@@ -992,8 +985,8 @@ export class RouterCore<
992
985
  }
993
986
 
994
987
  parseLocation: ParseLocationFn<TRouteTree> = (
995
- locationToParse,
996
988
  previousLocation,
989
+ locationToParse,
997
990
  ) => {
998
991
  const parse = ({
999
992
  pathname,
@@ -1014,7 +1007,7 @@ export class RouterCore<
1014
1007
  }
1015
1008
  }
1016
1009
 
1017
- const location = parse(locationToParse)
1010
+ const location = parse(locationToParse ?? this.history.location)
1018
1011
 
1019
1012
  const { __tempLocation, __tempKey } = location.state
1020
1013
 
@@ -1146,8 +1139,8 @@ export class RouterCore<
1146
1139
  const parentMatchId = parentMatch?.id
1147
1140
 
1148
1141
  const parentContext = !parentMatchId
1149
- ? ((this.options.context as any) ?? undefined)
1150
- : (parentMatch.context ?? this.options.context ?? undefined)
1142
+ ? ((this.options.context as any) ?? {})
1143
+ : (parentMatch.context ?? this.options.context ?? {})
1151
1144
 
1152
1145
  return parentContext
1153
1146
  }
@@ -1169,12 +1162,12 @@ export class RouterCore<
1169
1162
  ] = (() => {
1170
1163
  // Validate the search params and stabilize them
1171
1164
  const parentSearch = parentMatch?.search ?? next.search
1172
- const parentStrictSearch = parentMatch?._strictSearch ?? undefined
1165
+ const parentStrictSearch = parentMatch?._strictSearch ?? {}
1173
1166
 
1174
1167
  try {
1175
1168
  const strictSearch =
1176
1169
  validateSearch(route.options.validateSearch, { ...parentSearch }) ??
1177
- undefined
1170
+ {}
1178
1171
 
1179
1172
  return [
1180
1173
  {
@@ -1284,10 +1277,7 @@ export class RouterCore<
1284
1277
  isFetching: false,
1285
1278
  error: undefined,
1286
1279
  paramsError: parseErrors[index],
1287
- __routeContext: undefined,
1288
- _nonReactive: {
1289
- loadPromise: createControlledPromise(),
1290
- },
1280
+ __routeContext: {},
1291
1281
  __beforeLoadContext: undefined,
1292
1282
  context: {},
1293
1283
  abortController: new AbortController(),
@@ -1303,6 +1293,7 @@ export class RouterCore<
1303
1293
  headScripts: undefined,
1304
1294
  meta: undefined,
1305
1295
  staticData: route.options.staticData || {},
1296
+ loadPromise: createControlledPromise(),
1306
1297
  fullPath: route.fullPath,
1307
1298
  }
1308
1299
  }
@@ -1337,26 +1328,23 @@ export class RouterCore<
1337
1328
  const parentContext = getParentContext(parentMatch)
1338
1329
 
1339
1330
  // Update the match's context
1340
-
1341
- if (route.options.context) {
1342
- const contextFnContext: RouteContextOptions<any, any, any, any> = {
1343
- deps: match.loaderDeps,
1344
- params: match.params,
1345
- context: parentContext ?? {},
1346
- location: next,
1347
- navigate: (opts: any) =>
1348
- this.navigate({ ...opts, _fromLocation: next }),
1349
- buildLocation: this.buildLocation,
1350
- cause: match.cause,
1351
- abortController: match.abortController,
1352
- preload: !!match.preload,
1353
- matches,
1354
- }
1355
- // Get the route context
1356
- match.__routeContext =
1357
- route.options.context(contextFnContext) ?? undefined
1331
+ const contextFnContext: RouteContextOptions<any, any, any, any> = {
1332
+ deps: match.loaderDeps,
1333
+ params: match.params,
1334
+ context: parentContext,
1335
+ location: next,
1336
+ navigate: (opts: any) =>
1337
+ this.navigate({ ...opts, _fromLocation: next }),
1338
+ buildLocation: this.buildLocation,
1339
+ cause: match.cause,
1340
+ abortController: match.abortController,
1341
+ preload: !!match.preload,
1342
+ matches,
1358
1343
  }
1359
1344
 
1345
+ // Get the route context
1346
+ match.__routeContext = route.options.context?.(contextFnContext) ?? {}
1347
+
1360
1348
  match.context = {
1361
1349
  ...parentContext,
1362
1350
  ...match.__routeContext,
@@ -1393,8 +1381,13 @@ export class RouterCore<
1393
1381
  if (!match) return
1394
1382
 
1395
1383
  match.abortController.abort()
1396
- match._nonReactive.pendingTimeout = undefined
1397
- clearTimeout(match._nonReactive.pendingTimeout)
1384
+ this.updateMatch(id, (prev) => {
1385
+ clearTimeout(prev.pendingTimeout)
1386
+ return {
1387
+ ...prev,
1388
+ pendingTimeout: undefined,
1389
+ }
1390
+ })
1398
1391
  }
1399
1392
 
1400
1393
  cancelMatches = () => {
@@ -1420,7 +1413,7 @@ export class RouterCore<
1420
1413
 
1421
1414
  // First let's find the starting pathname
1422
1415
  // By default, start with the current location
1423
- let fromPath = this.resolvePathWithBase(lastMatch.fullPath, '.')
1416
+ let fromPath = lastMatch.fullPath
1424
1417
  const toPath = dest.to
1425
1418
  ? this.resolvePathWithBase(fromPath, `${dest.to}`)
1426
1419
  : this.resolvePathWithBase(fromPath, '.')
@@ -1461,8 +1454,6 @@ export class RouterCore<
1461
1454
  }
1462
1455
  }
1463
1456
 
1464
- fromPath = this.resolvePathWithBase(fromPath, '.')
1465
-
1466
1457
  // From search should always use the current location
1467
1458
  const fromSearch = lastMatch.search
1468
1459
  // Same with params. It can't hurt to provide as many as possible
@@ -1491,9 +1482,13 @@ export class RouterCore<
1491
1482
  parseCache: this.parsePathnameCache,
1492
1483
  }).interpolatedPath
1493
1484
 
1494
- const destRoutes = this.matchRoutes(interpolatedNextTo, undefined, {
1495
- _buildLocation: true,
1496
- }).map((d) => this.looseRoutesById[d.routeId]!)
1485
+ const destRoutes = this.matchRoutes(
1486
+ interpolatedNextTo,
1487
+ {},
1488
+ {
1489
+ _buildLocation: true,
1490
+ },
1491
+ ).map((d) => this.looseRoutesById[d.routeId]!)
1497
1492
 
1498
1493
  // If there are any params, we need to stringify them
1499
1494
  if (Object.keys(nextParams).length > 0) {
@@ -1810,7 +1805,7 @@ export class RouterCore<
1810
1805
  beforeLoad = () => {
1811
1806
  // Cancel any pending matches
1812
1807
  this.cancelMatches()
1813
- this.updateLatestLocation()
1808
+ this.latestLocation = this.parseLocation(this.latestLocation)
1814
1809
 
1815
1810
  if (this.isServer) {
1816
1811
  // for SPAs on the initial load, this is handled by the Transitioner
@@ -2131,10 +2126,8 @@ export class RouterCore<
2131
2126
  }
2132
2127
  }
2133
2128
 
2134
- match._nonReactive.beforeLoadPromise?.resolve()
2135
- match._nonReactive.loaderPromise?.resolve()
2136
- match._nonReactive.beforeLoadPromise = undefined
2137
- match._nonReactive.loaderPromise = undefined
2129
+ match.beforeLoadPromise?.resolve()
2130
+ match.loaderPromise?.resolve()
2138
2131
 
2139
2132
  updateMatch(match.id, (prev) => ({
2140
2133
  ...prev,
@@ -2145,13 +2138,15 @@ export class RouterCore<
2145
2138
  : 'error',
2146
2139
  isFetching: false,
2147
2140
  error: err,
2141
+ beforeLoadPromise: undefined,
2142
+ loaderPromise: undefined,
2148
2143
  }))
2149
2144
 
2150
2145
  if (!(err as any).routeId) {
2151
2146
  ;(err as any).routeId = match.routeId
2152
2147
  }
2153
2148
 
2154
- match._nonReactive.loadPromise?.resolve()
2149
+ match.loadPromise?.resolve()
2155
2150
 
2156
2151
  if (isRedirect(err)) {
2157
2152
  rendered = true
@@ -2171,7 +2166,7 @@ export class RouterCore<
2171
2166
  const shouldSkipLoader = (matchId: string) => {
2172
2167
  const match = this.getMatch(matchId)!
2173
2168
  // upon hydration, we skip the loader if the match has been dehydrated on the server
2174
- if (!this.isServer && match._nonReactive.dehydrated) {
2169
+ if (!this.isServer && match._dehydrated) {
2175
2170
  return true
2176
2171
  }
2177
2172
 
@@ -2214,9 +2209,8 @@ export class RouterCore<
2214
2209
  }
2215
2210
 
2216
2211
  updateMatch(matchId, (prev) => {
2217
- prev._nonReactive.beforeLoadPromise?.resolve()
2218
- prev._nonReactive.beforeLoadPromise = undefined
2219
- prev._nonReactive.loadPromise?.resolve()
2212
+ prev.beforeLoadPromise?.resolve()
2213
+ prev.loadPromise?.resolve()
2220
2214
 
2221
2215
  return {
2222
2216
  ...prev,
@@ -2225,6 +2219,7 @@ export class RouterCore<
2225
2219
  isFetching: false,
2226
2220
  updatedAt: Date.now(),
2227
2221
  abortController: new AbortController(),
2222
+ beforeLoadPromise: undefined,
2228
2223
  }
2229
2224
  })
2230
2225
  }
@@ -2294,7 +2289,10 @@ export class RouterCore<
2294
2289
  }
2295
2290
  }
2296
2291
  }
2297
- existingMatch.ssr = ssr
2292
+ updateMatch(matchId, (prev) => ({
2293
+ ...prev,
2294
+ ssr,
2295
+ }))
2298
2296
  }
2299
2297
 
2300
2298
  if (shouldSkipLoader(matchId)) {
@@ -2316,10 +2314,9 @@ export class RouterCore<
2316
2314
 
2317
2315
  let executeBeforeLoad = true
2318
2316
  const setupPendingTimeout = () => {
2319
- const match = this.getMatch(matchId)!
2320
2317
  if (
2321
2318
  shouldPending &&
2322
- match._nonReactive.pendingTimeout === undefined
2319
+ this.getMatch(matchId)!.pendingTimeout === undefined
2323
2320
  ) {
2324
2321
  const pendingTimeout = setTimeout(() => {
2325
2322
  try {
@@ -2328,19 +2325,22 @@ export class RouterCore<
2328
2325
  triggerOnReady()
2329
2326
  } catch {}
2330
2327
  }, pendingMs)
2331
- match._nonReactive.pendingTimeout = pendingTimeout
2328
+ updateMatch(matchId, (prev) => ({
2329
+ ...prev,
2330
+ pendingTimeout,
2331
+ }))
2332
2332
  }
2333
2333
  }
2334
2334
  if (
2335
2335
  // If we are in the middle of a load, either of these will be present
2336
2336
  // (not to be confused with `loadPromise`, which is always defined)
2337
- existingMatch._nonReactive.beforeLoadPromise ||
2338
- existingMatch._nonReactive.loaderPromise
2337
+ existingMatch.beforeLoadPromise ||
2338
+ existingMatch.loaderPromise
2339
2339
  ) {
2340
2340
  setupPendingTimeout()
2341
2341
 
2342
2342
  // Wait for the beforeLoad to resolve before we continue
2343
- await existingMatch._nonReactive.beforeLoadPromise
2343
+ await existingMatch.beforeLoadPromise
2344
2344
  const match = this.getMatch(matchId)!
2345
2345
  if (match.status === 'error') {
2346
2346
  executeBeforeLoad = true
@@ -2354,15 +2354,17 @@ export class RouterCore<
2354
2354
  if (executeBeforeLoad) {
2355
2355
  // If we are not in the middle of a load OR the previous load failed, start it
2356
2356
  try {
2357
- const match = this.getMatch(matchId)!
2358
- match._nonReactive.beforeLoadPromise =
2359
- createControlledPromise<void>()
2360
- // explicitly capture the previous loadPromise
2361
- const prevLoadPromise = match._nonReactive.loadPromise
2362
- match._nonReactive.loadPromise =
2363
- createControlledPromise<void>(() => {
2364
- prevLoadPromise?.resolve()
2365
- })
2357
+ updateMatch(matchId, (prev) => {
2358
+ // explicitly capture the previous loadPromise
2359
+ const prevLoadPromise = prev.loadPromise
2360
+ return {
2361
+ ...prev,
2362
+ loadPromise: createControlledPromise<void>(() => {
2363
+ prevLoadPromise?.resolve()
2364
+ }),
2365
+ beforeLoadPromise: createControlledPromise<void>(),
2366
+ }
2367
+ })
2366
2368
 
2367
2369
  const { paramsError, searchError } = this.getMatch(matchId)!
2368
2370
 
@@ -2379,7 +2381,7 @@ export class RouterCore<
2379
2381
  const abortController = new AbortController()
2380
2382
 
2381
2383
  const parentMatchContext =
2382
- parentMatch?.context ?? this.options.context ?? undefined
2384
+ parentMatch?.context ?? this.options.context ?? {}
2383
2385
 
2384
2386
  updateMatch(matchId, (prev) => ({
2385
2387
  ...prev,
@@ -2444,11 +2446,11 @@ export class RouterCore<
2444
2446
  }
2445
2447
 
2446
2448
  updateMatch(matchId, (prev) => {
2447
- prev._nonReactive.beforeLoadPromise?.resolve()
2448
- prev._nonReactive.beforeLoadPromise = undefined
2449
+ prev.beforeLoadPromise?.resolve()
2449
2450
 
2450
2451
  return {
2451
2452
  ...prev,
2453
+ beforeLoadPromise: undefined,
2452
2454
  isFetching: false,
2453
2455
  }
2454
2456
  })
@@ -2498,8 +2500,8 @@ export class RouterCore<
2498
2500
 
2499
2501
  const potentialPendingMinPromise = async () => {
2500
2502
  const latestMatch = this.getMatch(matchId)!
2501
- if (latestMatch._nonReactive.minPendingPromise) {
2502
- await latestMatch._nonReactive.minPendingPromise
2503
+ if (latestMatch.minPendingPromise) {
2504
+ await latestMatch.minPendingPromise
2503
2505
  }
2504
2506
  }
2505
2507
 
@@ -2515,7 +2517,7 @@ export class RouterCore<
2515
2517
  }
2516
2518
  }
2517
2519
  // there is a loaderPromise, so we are in the middle of a load
2518
- else if (prevMatch._nonReactive.loaderPromise) {
2520
+ else if (prevMatch.loaderPromise) {
2519
2521
  // do not block if we already have stale data we can show
2520
2522
  // but only if the ongoing load is not a preload since error handling is different for preloads
2521
2523
  // and we don't want to swallow errors
@@ -2526,7 +2528,7 @@ export class RouterCore<
2526
2528
  ) {
2527
2529
  return this.getMatch(matchId)!
2528
2530
  }
2529
- await prevMatch._nonReactive.loaderPromise
2531
+ await prevMatch.loaderPromise
2530
2532
  const match = this.getMatch(matchId)!
2531
2533
  if (match.error) {
2532
2534
  handleRedirectAndNotFound(match, match.error)
@@ -2583,16 +2585,13 @@ export class RouterCore<
2583
2585
  ? shouldReloadOption(getLoaderContext())
2584
2586
  : shouldReloadOption
2585
2587
 
2586
- updateMatch(matchId, (prev) => {
2587
- prev._nonReactive.loaderPromise =
2588
- createControlledPromise<void>()
2589
- return {
2590
- ...prev,
2591
- preload:
2592
- !!preload &&
2593
- !this.state.matches.some((d) => d.id === matchId),
2594
- }
2595
- })
2588
+ updateMatch(matchId, (prev) => ({
2589
+ ...prev,
2590
+ loaderPromise: createControlledPromise<void>(),
2591
+ preload:
2592
+ !!preload &&
2593
+ !this.state.matches.some((d) => d.id === matchId),
2594
+ }))
2596
2595
 
2597
2596
  const runLoader = async () => {
2598
2597
  try {
@@ -2676,13 +2675,11 @@ export class RouterCore<
2676
2675
  } catch (err) {
2677
2676
  const head = await executeHead()
2678
2677
 
2679
- updateMatch(matchId, (prev) => {
2680
- prev._nonReactive.loaderPromise = undefined
2681
- return {
2682
- ...prev,
2683
- ...head,
2684
- }
2685
- })
2678
+ updateMatch(matchId, (prev) => ({
2679
+ ...prev,
2680
+ loaderPromise: undefined,
2681
+ ...head,
2682
+ }))
2686
2683
  handleRedirectAndNotFound(this.getMatch(matchId)!, err)
2687
2684
  }
2688
2685
  }
@@ -2699,10 +2696,14 @@ export class RouterCore<
2699
2696
  ;(async () => {
2700
2697
  try {
2701
2698
  await runLoader()
2702
- const match = this.getMatch(matchId)!
2703
- match._nonReactive.loaderPromise?.resolve()
2704
- match._nonReactive.loadPromise?.resolve()
2705
- match._nonReactive.loaderPromise = undefined
2699
+ const { loaderPromise, loadPromise } =
2700
+ this.getMatch(matchId)!
2701
+ loaderPromise?.resolve()
2702
+ loadPromise?.resolve()
2703
+ updateMatch(matchId, (prev) => ({
2704
+ ...prev,
2705
+ loaderPromise: undefined,
2706
+ }))
2706
2707
  } catch (err) {
2707
2708
  if (isRedirect(err)) {
2708
2709
  await this.navigate(err.options)
@@ -2726,23 +2727,25 @@ export class RouterCore<
2726
2727
  }
2727
2728
  }
2728
2729
  if (!loaderIsRunningAsync) {
2729
- const match = this.getMatch(matchId)!
2730
- match._nonReactive.loaderPromise?.resolve()
2731
- match._nonReactive.loadPromise?.resolve()
2730
+ const { loaderPromise, loadPromise } =
2731
+ this.getMatch(matchId)!
2732
+ loaderPromise?.resolve()
2733
+ loadPromise?.resolve()
2732
2734
  }
2733
2735
 
2734
2736
  updateMatch(matchId, (prev) => {
2735
- clearTimeout(prev._nonReactive.pendingTimeout)
2736
- prev._nonReactive.pendingTimeout = undefined
2737
- if (!loaderIsRunningAsync)
2738
- prev._nonReactive.loaderPromise = undefined
2739
- prev._nonReactive.dehydrated = undefined
2737
+ clearTimeout(prev.pendingTimeout)
2740
2738
  return {
2741
2739
  ...prev,
2742
2740
  isFetching: loaderIsRunningAsync
2743
2741
  ? prev.isFetching
2744
2742
  : false,
2743
+ loaderPromise: loaderIsRunningAsync
2744
+ ? prev.loaderPromise
2745
+ : undefined,
2745
2746
  invalid: false,
2747
+ pendingTimeout: undefined,
2748
+ _dehydrated: undefined,
2746
2749
  }
2747
2750
  })
2748
2751
  return this.getMatch(matchId)!
@@ -2788,7 +2791,7 @@ export class RouterCore<
2788
2791
  invalid: true,
2789
2792
  ...(opts?.forcePending || d.status === 'error'
2790
2793
  ? ({ status: 'pending', error: undefined } as const)
2791
- : undefined),
2794
+ : {}),
2792
2795
  }
2793
2796
  }
2794
2797
  return d
@@ -3559,8 +3562,7 @@ function applySearchMiddleware({
3559
3562
  try {
3560
3563
  const validatedSearch = {
3561
3564
  ...result,
3562
- ...(validateSearch(route.options.validateSearch, result) ??
3563
- undefined),
3565
+ ...(validateSearch(route.options.validateSearch, result) ?? {}),
3564
3566
  }
3565
3567
  return validatedSearch
3566
3568
  } catch {
@@ -20,16 +20,17 @@ export interface TsrSsrGlobal {
20
20
  }
21
21
 
22
22
  function hydrateMatch(
23
- match: AnyRouteMatch,
24
23
  deyhydratedMatch: DehydratedMatch,
25
- ): void {
26
- match.id = deyhydratedMatch.i
27
- match.__beforeLoadContext = deyhydratedMatch.b
28
- match.loaderData = deyhydratedMatch.l
29
- match.status = deyhydratedMatch.s
30
- match.ssr = deyhydratedMatch.ssr
31
- match.updatedAt = deyhydratedMatch.u
32
- match.error = deyhydratedMatch.e
24
+ ): Partial<MakeRouteMatch> {
25
+ return {
26
+ id: deyhydratedMatch.i,
27
+ __beforeLoadContext: deyhydratedMatch.b,
28
+ loaderData: deyhydratedMatch.l,
29
+ status: deyhydratedMatch.s,
30
+ ssr: deyhydratedMatch.ssr,
31
+ updatedAt: deyhydratedMatch.u,
32
+ error: deyhydratedMatch.e,
33
+ }
33
34
  }
34
35
  export interface DehydratedMatch {
35
36
  i: MakeRouteMatch['id']
@@ -79,19 +80,17 @@ export async function hydrate(router: AnyRouter): Promise<any> {
79
80
  route.options.pendingMinMs ?? router.options.defaultPendingMinMs
80
81
  if (pendingMinMs) {
81
82
  const minPendingPromise = createControlledPromise<void>()
82
- match._nonReactive.minPendingPromise = minPendingPromise
83
+ match.minPendingPromise = minPendingPromise
83
84
  match._forcePending = true
84
85
 
85
86
  setTimeout(() => {
86
87
  minPendingPromise.resolve()
87
88
  // We've handled the minPendingPromise, so we can delete it
88
- router.updateMatch(match.id, (prev) => {
89
- prev._nonReactive.minPendingPromise = undefined
90
- return {
91
- ...prev,
92
- _forcePending: undefined,
93
- }
94
- })
89
+ router.updateMatch(match.id, (prev) => ({
90
+ ...prev,
91
+ minPendingPromise: undefined,
92
+ _forcePending: undefined,
93
+ }))
95
94
  }, pendingMinMs)
96
95
  }
97
96
  }
@@ -104,14 +103,17 @@ export async function hydrate(router: AnyRouter): Promise<any> {
104
103
  (d) => d.i === match.id,
105
104
  )
106
105
  if (!dehydratedMatch) {
107
- match._nonReactive.dehydrated = false
108
- match.ssr = false
106
+ Object.assign(match, { dehydrated: false, ssr: false })
109
107
  return
110
108
  }
111
109
 
112
- hydrateMatch(match, dehydratedMatch)
110
+ Object.assign(match, hydrateMatch(dehydratedMatch))
113
111
 
114
- match._nonReactive.dehydrated = match.ssr !== false
112
+ if (match.ssr === false) {
113
+ match._dehydrated = false
114
+ } else {
115
+ match._dehydrated = true
116
+ }
115
117
 
116
118
  if (match.ssr === 'data-only' || match.ssr === false) {
117
119
  if (firstNonSsrMatchIndex === undefined) {
@@ -139,27 +141,24 @@ export async function hydrate(router: AnyRouter): Promise<any> {
139
141
  const route = router.looseRoutesById[match.routeId]!
140
142
 
141
143
  const parentMatch = router.state.matches[match.index - 1]
142
- const parentContext = parentMatch?.context ?? router.options.context
144
+ const parentContext = parentMatch?.context ?? router.options.context ?? {}
143
145
 
144
146
  // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
145
147
  // so run it again and merge route context
146
- if (route.options.context) {
147
- const contextFnContext: RouteContextOptions<any, any, any, any> = {
148
- deps: match.loaderDeps,
149
- params: match.params,
150
- context: parentContext ?? {},
151
- location: router.state.location,
152
- navigate: (opts: any) =>
153
- router.navigate({ ...opts, _fromLocation: router.state.location }),
154
- buildLocation: router.buildLocation,
155
- cause: match.cause,
156
- abortController: match.abortController,
157
- preload: false,
158
- matches,
159
- }
160
- match.__routeContext =
161
- route.options.context(contextFnContext) ?? undefined
148
+ const contextFnContext: RouteContextOptions<any, any, any, any> = {
149
+ deps: match.loaderDeps,
150
+ params: match.params,
151
+ context: parentContext,
152
+ location: router.state.location,
153
+ navigate: (opts: any) =>
154
+ router.navigate({ ...opts, _fromLocation: router.state.location }),
155
+ buildLocation: router.buildLocation,
156
+ cause: match.cause,
157
+ abortController: match.abortController,
158
+ preload: false,
159
+ matches,
162
160
  }
161
+ match.__routeContext = route.options.context?.(contextFnContext) ?? {}
163
162
 
164
163
  match.context = {
165
164
  ...parentContext,
@@ -187,11 +186,11 @@ export async function hydrate(router: AnyRouter): Promise<any> {
187
186
 
188
187
  const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId
189
188
  const hasSsrFalseMatches = matches.some((m) => m.ssr === false)
190
- // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
189
+ // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
191
190
  if (!hasSsrFalseMatches && !isSpaMode) {
192
191
  matches.forEach((match) => {
193
- // remove the dehydrated flag since we won't run router.load() which would remove it
194
- match._nonReactive.dehydrated = undefined
192
+ // remove the _dehydrate flag since we won't run router.load() which would remove it
193
+ match._dehydrated = undefined
195
194
  })
196
195
  return routeChunkPromise
197
196
  }
@@ -214,7 +213,7 @@ export async function hydrate(router: AnyRouter): Promise<any> {
214
213
  setMatchForcePending(match)
215
214
 
216
215
  match._displayPending = true
217
- match._nonReactive.displayPendingPromise = loadPromise
216
+ match.displayPendingPromise = loadPromise
218
217
 
219
218
  loadPromise.then(() => {
220
219
  batch(() => {