@tanstack/router-core 1.154.12 → 1.154.14

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.
@@ -47,6 +47,7 @@ class RouterCore {
47
47
  this.tempLocationKey = `${Math.round(
48
48
  Math.random() * 1e7
49
49
  )}`;
50
+ this.resetNextScroll = true;
50
51
  this.shouldViewTransition = void 0;
51
52
  this.isViewTransitionTypesSupported = void 0;
52
53
  this.subscribers = /* @__PURE__ */ new Set();
@@ -248,9 +249,9 @@ class RouterCore {
248
249
  search: locationSearchOrOpts
249
250
  },
250
251
  opts
251
- ).matches;
252
+ );
252
253
  }
253
- return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts).matches;
254
+ return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
254
255
  };
255
256
  this.getMatchedRoutes = (pathname) => {
256
257
  return getMatchedRoutes({
@@ -316,14 +317,12 @@ class RouterCore {
316
317
  }).interpolatedPath;
317
318
  const destMatchResult = this.getMatchedRoutes(interpolatedNextTo);
318
319
  let destRoutes = destMatchResult.matchedRoutes;
319
- const rawParams = destMatchResult.routeParams;
320
320
  const isGlobalNotFound = destMatchResult.foundRoute ? destMatchResult.foundRoute.path !== "/" && destMatchResult.routeParams["**"] : trimPathRight(interpolatedNextTo);
321
- let globalNotFoundRouteId;
322
321
  if (isGlobalNotFound) {
323
322
  if (this.options.notFoundRoute) {
324
323
  destRoutes = [...destRoutes, this.options.notFoundRoute];
325
324
  } else {
326
- globalNotFoundRouteId = findGlobalNotFoundRouteId(
325
+ findGlobalNotFoundRouteId(
327
326
  this.options.notFoundMode,
328
327
  destRoutes
329
328
  );
@@ -379,31 +378,19 @@ class RouterCore {
379
378
  const hashStr = hash ? `#${hash}` : "";
380
379
  let nextState = dest.state === true ? currentLocation.state : dest.state ? functionalUpdate(dest.state, currentLocation.state) : {};
381
380
  nextState = replaceEqualDeep(currentLocation.state, nextState);
382
- const snapshotParams = {
383
- ...rawParams,
384
- ...nextParams
385
- };
386
- const matchSnapshot = buildMatchSnapshotFromRoutes({
387
- routes: destRoutes,
388
- params: snapshotParams,
389
- searchStr,
390
- globalNotFoundRouteId
391
- });
392
381
  const fullPath = `${nextPathname}${searchStr}${hashStr}`;
393
382
  const url = new URL(fullPath, this.origin);
394
383
  const rewrittenUrl = executeRewriteOutput(this.rewrite, url);
395
- const encodedHref = url.href.replace(url.origin, "");
396
384
  return {
397
385
  publicHref: rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
398
- href: encodedHref,
386
+ href: fullPath,
399
387
  url: rewrittenUrl,
400
388
  pathname: nextPathname,
401
389
  search: nextSearch,
402
390
  searchStr,
403
391
  state: nextState,
404
392
  hash: hash ?? "",
405
- unmaskOnReload: dest.unmaskOnReload,
406
- _matchSnapshot: matchSnapshot
393
+ unmaskOnReload: dest.unmaskOnReload
407
394
  };
408
395
  };
409
396
  const buildWithMatches = (dest = {}, maskedDest) => {
@@ -475,73 +462,53 @@ class RouterCore {
475
462
  });
476
463
  if (isSameUrl && isSameState()) {
477
464
  this.load();
478
- return this.commitLocationPromise;
479
- }
480
- let {
481
- // eslint-disable-next-line prefer-const
482
- maskedLocation,
483
- // eslint-disable-next-line prefer-const
484
- hashScrollIntoView,
485
- // don't pass url into history since it is a URL instance that cannot be serialized
486
- // eslint-disable-next-line prefer-const
487
- url: _url,
488
- ...nextHistory
489
- } = next;
490
- if (maskedLocation) {
491
- nextHistory = {
492
- ...maskedLocation,
493
- state: {
494
- ...maskedLocation.state,
495
- __tempKey: void 0,
496
- __tempLocation: {
497
- ...nextHistory,
498
- search: nextHistory.searchStr,
499
- state: {
500
- ...nextHistory.state,
501
- __tempKey: void 0,
502
- __tempLocation: void 0,
503
- __TSR_key: void 0,
504
- key: void 0
505
- // TODO: Remove in v2 - use __TSR_key instead
465
+ } else {
466
+ let {
467
+ // eslint-disable-next-line prefer-const
468
+ maskedLocation,
469
+ // eslint-disable-next-line prefer-const
470
+ hashScrollIntoView,
471
+ // don't pass url into history since it is a URL instance that cannot be serialized
472
+ // eslint-disable-next-line prefer-const
473
+ url: _url,
474
+ ...nextHistory
475
+ } = next;
476
+ if (maskedLocation) {
477
+ nextHistory = {
478
+ ...maskedLocation,
479
+ state: {
480
+ ...maskedLocation.state,
481
+ __tempKey: void 0,
482
+ __tempLocation: {
483
+ ...nextHistory,
484
+ search: nextHistory.searchStr,
485
+ state: {
486
+ ...nextHistory.state,
487
+ __tempKey: void 0,
488
+ __tempLocation: void 0,
489
+ __TSR_key: void 0,
490
+ key: void 0
491
+ // TODO: Remove in v2 - use __TSR_key instead
492
+ }
506
493
  }
507
494
  }
495
+ };
496
+ if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
497
+ nextHistory.state.__tempKey = this.tempLocationKey;
508
498
  }
509
- };
510
- if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
511
- nextHistory.state.__tempKey = this.tempLocationKey;
512
499
  }
500
+ nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
501
+ this.shouldViewTransition = viewTransition;
502
+ this.history[next.replace ? "replace" : "push"](
503
+ nextHistory.publicHref,
504
+ nextHistory.state,
505
+ { ignoreBlocker }
506
+ );
513
507
  }
514
- nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
515
- nextHistory.state.__TSR_resetScroll = next.resetScroll ?? true;
516
- this.shouldViewTransition = viewTransition;
517
- nextHistory.state.__TSR_sessionId = this.sessionId;
518
- nextHistory.state.__TSR_matches = next._matchSnapshot ?? buildMatchSnapshot({
519
- matchResult: this.getMatchedRoutes(next.pathname),
520
- pathname: next.pathname,
521
- searchStr: next.searchStr,
522
- notFoundRoute: this.options.notFoundRoute,
523
- notFoundMode: this.options.notFoundMode
524
- });
525
- const precomputedLocation = {
526
- ...next,
527
- publicHref: nextHistory.publicHref,
528
- state: nextHistory.state,
529
- maskedLocation
530
- };
531
- const result = await this.history[next.replace ? "replace" : "push"](
532
- nextHistory.publicHref,
533
- nextHistory.state,
534
- { ignoreBlocker, skipTransitionerLoad: true }
535
- );
536
- if (result.type === "BLOCKED") {
537
- this.commitLocationPromise?.resolve();
538
- return this.commitLocationPromise;
539
- }
540
- if (this.history.location.href !== nextHistory.publicHref) {
541
- return this.commitLocationPromise;
508
+ this.resetNextScroll = next.resetScroll ?? true;
509
+ if (!this.history.subscribers.size) {
510
+ this.load();
542
511
  }
543
- this.latestLocation = precomputedLocation;
544
- this.load({ _skipUpdateLatestLocation: true });
545
512
  return this.commitLocationPromise;
546
513
  };
547
514
  this.buildAndCommitLocation = ({
@@ -648,11 +615,9 @@ class RouterCore {
648
615
  _isNavigate: true
649
616
  });
650
617
  };
651
- this.beforeLoad = (opts) => {
618
+ this.beforeLoad = () => {
652
619
  this.cancelMatches();
653
- if (!opts?._skipUpdateLatestLocation) {
654
- this.updateLatestLocation();
655
- }
620
+ this.updateLatestLocation();
656
621
  if (this.isServer) {
657
622
  const nextLocation = this.buildLocation({
658
623
  to: this.latestLocation.pathname,
@@ -667,8 +632,7 @@ class RouterCore {
667
632
  throw redirect({ href });
668
633
  }
669
634
  }
670
- const snapshot = this.latestLocation.state.__TSR_sessionId === this.sessionId ? this.latestLocation.state.__TSR_matches : void 0;
671
- const pendingMatches = this.matchRoutes(this.latestLocation, { snapshot });
635
+ const pendingMatches = this.matchRoutes(this.latestLocation);
672
636
  this.__store.setState((s) => ({
673
637
  ...s,
674
638
  status: "pending",
@@ -689,9 +653,7 @@ class RouterCore {
689
653
  loadPromise = new Promise((resolve) => {
690
654
  this.startTransition(async () => {
691
655
  try {
692
- this.beforeLoad({
693
- _skipUpdateLatestLocation: opts?._skipUpdateLatestLocation
694
- });
656
+ this.beforeLoad();
695
657
  const next = this.latestLocation;
696
658
  const prevLocation = this.state.resolvedLocation;
697
659
  if (!this.state.redirect) {
@@ -1048,7 +1010,6 @@ class RouterCore {
1048
1010
  (d) => d.status === "notFound" || d.globalNotFound
1049
1011
  );
1050
1012
  };
1051
- this.sessionId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
1052
1013
  this.update({
1053
1014
  defaultPreloadDelay: 50,
1054
1015
  defaultPendingMs: 1e3,
@@ -1077,57 +1038,33 @@ class RouterCore {
1077
1038
  return this.routesById;
1078
1039
  }
1079
1040
  matchRoutesInternal(next, opts) {
1080
- const snapshot = opts?.snapshot;
1081
- const snapshotValid = snapshot && snapshot.routeIds.length > 0 && snapshot.routeIds.every((id) => this.routesById[id]);
1082
- let matchedRoutes;
1083
- let routeParams;
1084
- let rawParams;
1085
- let globalNotFoundRouteId;
1086
- let parsedParams;
1087
- if (snapshotValid) {
1088
- matchedRoutes = snapshot.routeIds.map((id) => this.routesById[id]);
1089
- routeParams = { ...snapshot.params };
1090
- rawParams = { ...snapshot.params };
1091
- globalNotFoundRouteId = snapshot.globalNotFoundRouteId;
1092
- parsedParams = snapshot.parsedParams;
1093
- } else {
1094
- const matchedRoutesResult = this.getMatchedRoutes(next.pathname);
1095
- const { foundRoute, routeParams: rp } = matchedRoutesResult;
1096
- routeParams = rp;
1097
- rawParams = { ...rp };
1098
- matchedRoutes = matchedRoutesResult.matchedRoutes;
1099
- parsedParams = matchedRoutesResult.parsedParams;
1100
- let isGlobalNotFound = false;
1101
- if (
1102
- // If we found a route, and it's not an index route and we have left over path
1103
- foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
1104
- // Or if we didn't find a route and we have left over path
1105
- trimPathRight(next.pathname)
1106
- )
1107
- ) {
1108
- if (this.options.notFoundRoute) {
1109
- matchedRoutes = [...matchedRoutes, this.options.notFoundRoute];
1110
- } else {
1111
- isGlobalNotFound = true;
1112
- }
1041
+ const matchedRoutesResult = this.getMatchedRoutes(next.pathname);
1042
+ const { foundRoute, routeParams, parsedParams } = matchedRoutesResult;
1043
+ let { matchedRoutes } = matchedRoutesResult;
1044
+ let isGlobalNotFound = false;
1045
+ if (
1046
+ // If we found a route, and it's not an index route and we have left over path
1047
+ foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
1048
+ // Or if we didn't find a route and we have left over path
1049
+ trimPathRight(next.pathname)
1050
+ )
1051
+ ) {
1052
+ if (this.options.notFoundRoute) {
1053
+ matchedRoutes = [...matchedRoutes, this.options.notFoundRoute];
1054
+ } else {
1055
+ isGlobalNotFound = true;
1113
1056
  }
1114
- globalNotFoundRouteId = isGlobalNotFound ? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes) : void 0;
1115
1057
  }
1058
+ const globalNotFoundRouteId = isGlobalNotFound ? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes) : void 0;
1116
1059
  const matches = [];
1117
1060
  const getParentContext = (parentMatch) => {
1118
1061
  const parentMatchId = parentMatch?.id;
1119
1062
  const parentContext = !parentMatchId ? this.options.context ?? void 0 : parentMatch.context ?? this.options.context ?? void 0;
1120
1063
  return parentContext;
1121
1064
  };
1122
- const canUseCachedSearch = snapshotValid && snapshot.searchStr === next.searchStr && snapshot.validatedSearches?.length === matchedRoutes.length;
1123
- const validatedSearchesToCache = [];
1124
1065
  matchedRoutes.forEach((route, index) => {
1125
1066
  const parentMatch = matches[index - 1];
1126
1067
  const [preMatchSearch, strictMatchSearch, searchError] = (() => {
1127
- if (canUseCachedSearch) {
1128
- const cached = snapshot.validatedSearches[index];
1129
- return [cached.search, cached.strictSearch, void 0];
1130
- }
1131
1068
  const parentSearch = parentMatch?.search ?? next.search;
1132
1069
  const parentStrictSearch = parentMatch?._strictSearch ?? void 0;
1133
1070
  try {
@@ -1153,12 +1090,6 @@ class RouterCore {
1153
1090
  return [parentSearch, {}, searchParamError];
1154
1091
  }
1155
1092
  })();
1156
- if (!canUseCachedSearch) {
1157
- validatedSearchesToCache.push({
1158
- search: preMatchSearch,
1159
- strictSearch: strictMatchSearch
1160
- });
1161
- }
1162
1093
  const loaderDeps = route.options.loaderDeps?.({
1163
1094
  search: preMatchSearch
1164
1095
  }) ?? "";
@@ -1272,13 +1203,6 @@ class RouterCore {
1272
1203
  };
1273
1204
  matches.push(match);
1274
1205
  });
1275
- if (!canUseCachedSearch && validatedSearchesToCache.length > 0) {
1276
- const existingSnapshot = next.state?.__TSR_matches;
1277
- if (existingSnapshot) {
1278
- existingSnapshot.searchStr = next.searchStr;
1279
- existingSnapshot.validatedSearches = validatedSearchesToCache;
1280
- }
1281
- }
1282
1206
  matches.forEach((match, index) => {
1283
1207
  const route = this.looseRoutesById[match.routeId];
1284
1208
  const existingMatch = this.getMatch(match.id);
@@ -1307,7 +1231,7 @@ class RouterCore {
1307
1231
  };
1308
1232
  }
1309
1233
  });
1310
- return { matches, rawParams };
1234
+ return matches;
1311
1235
  }
1312
1236
  }
1313
1237
  class SearchParamError extends Error {
@@ -1366,7 +1290,7 @@ function getMatchedRoutes({
1366
1290
  const routeParams = {};
1367
1291
  const trimmedPath = trimPathRight(pathname);
1368
1292
  let foundRoute = void 0;
1369
- let parsedParams = {};
1293
+ let parsedParams = void 0;
1370
1294
  const match = findRouteMatch(trimmedPath, processedTree, true);
1371
1295
  if (match) {
1372
1296
  foundRoute = match.route;
@@ -1376,140 +1300,89 @@ function getMatchedRoutes({
1376
1300
  const matchedRoutes = match?.branch || [routesById[rootRouteId]];
1377
1301
  return { matchedRoutes, routeParams, foundRoute, parsedParams };
1378
1302
  }
1379
- function buildMatchSnapshot({
1380
- matchResult,
1381
- pathname,
1382
- searchStr,
1383
- notFoundRoute,
1384
- notFoundMode
1385
- }) {
1386
- const snapshot = {
1387
- routeIds: matchResult.matchedRoutes.map((r) => r.id),
1388
- params: matchResult.routeParams,
1389
- parsedParams: matchResult.parsedParams,
1390
- searchStr
1391
- };
1392
- const isGlobalNotFound = matchResult.foundRoute ? matchResult.foundRoute.path !== "/" && matchResult.routeParams["**"] : trimPathRight(pathname);
1393
- if (isGlobalNotFound) {
1394
- if (notFoundRoute) {
1395
- snapshot.globalNotFoundRouteId = notFoundRoute.id;
1396
- } else {
1397
- if (notFoundMode !== "root") {
1398
- for (let i = matchResult.matchedRoutes.length - 1; i >= 0; i--) {
1399
- const route = matchResult.matchedRoutes[i];
1400
- if (route.children) {
1401
- snapshot.globalNotFoundRouteId = route.id;
1402
- break;
1403
- }
1404
- }
1405
- }
1406
- if (!snapshot.globalNotFoundRouteId) {
1407
- snapshot.globalNotFoundRouteId = rootRouteId;
1408
- }
1409
- }
1410
- }
1411
- return snapshot;
1412
- }
1413
- function buildMatchSnapshotFromRoutes({
1414
- routes,
1415
- params,
1416
- searchStr,
1417
- globalNotFoundRouteId
1418
- }) {
1419
- const stringParams = {};
1420
- for (const key in params) {
1421
- const value = params[key];
1422
- if (value != null) {
1423
- stringParams[key] = String(value);
1424
- }
1425
- }
1426
- const snapshot = {
1427
- routeIds: routes.map((r) => r.id),
1428
- params: stringParams,
1429
- parsedParams: params,
1430
- searchStr
1431
- };
1432
- if (globalNotFoundRouteId) {
1433
- snapshot.globalNotFoundRouteId = globalNotFoundRouteId;
1434
- }
1435
- return snapshot;
1436
- }
1437
1303
  function applySearchMiddleware({
1438
1304
  search,
1439
1305
  dest,
1440
1306
  destRoutes,
1441
1307
  _includeValidateSearch
1442
1308
  }) {
1443
- const allMiddlewares = destRoutes.reduce(
1444
- (acc, route) => {
1445
- const middlewares = [];
1446
- if ("search" in route.options) {
1447
- if (route.options.search?.middlewares) {
1448
- middlewares.push(...route.options.search.middlewares);
1309
+ const middleware = buildMiddlewareChain(destRoutes);
1310
+ return middleware(search, dest, _includeValidateSearch ?? false);
1311
+ }
1312
+ function buildMiddlewareChain(destRoutes) {
1313
+ const context = {
1314
+ dest: null,
1315
+ _includeValidateSearch: false,
1316
+ middlewares: []
1317
+ };
1318
+ for (const route of destRoutes) {
1319
+ if ("search" in route.options) {
1320
+ if (route.options.search?.middlewares) {
1321
+ context.middlewares.push(...route.options.search.middlewares);
1322
+ }
1323
+ } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
1324
+ const legacyMiddleware = ({ search, next }) => {
1325
+ let nextSearch = search;
1326
+ if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
1327
+ nextSearch = route.options.preSearchFilters.reduce(
1328
+ (prev, next2) => next2(prev),
1329
+ search
1330
+ );
1449
1331
  }
1450
- } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
1451
- const legacyMiddleware = ({
1452
- search: search2,
1453
- next
1454
- }) => {
1455
- let nextSearch = search2;
1456
- if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
1457
- nextSearch = route.options.preSearchFilters.reduce(
1458
- (prev, next2) => next2(prev),
1459
- search2
1460
- );
1461
- }
1462
- const result = next(nextSearch);
1463
- if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
1464
- return route.options.postSearchFilters.reduce(
1465
- (prev, next2) => next2(prev),
1466
- result
1467
- );
1468
- }
1332
+ const result = next(nextSearch);
1333
+ if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
1334
+ return route.options.postSearchFilters.reduce(
1335
+ (prev, next2) => next2(prev),
1336
+ result
1337
+ );
1338
+ }
1339
+ return result;
1340
+ };
1341
+ context.middlewares.push(legacyMiddleware);
1342
+ }
1343
+ if (route.options.validateSearch) {
1344
+ const validate = ({ search, next }) => {
1345
+ const result = next(search);
1346
+ if (!context._includeValidateSearch) return result;
1347
+ try {
1348
+ const validatedSearch = {
1349
+ ...result,
1350
+ ...validateSearch(route.options.validateSearch, result) ?? void 0
1351
+ };
1352
+ return validatedSearch;
1353
+ } catch {
1469
1354
  return result;
1470
- };
1471
- middlewares.push(legacyMiddleware);
1472
- }
1473
- if (_includeValidateSearch && route.options.validateSearch) {
1474
- const validate = ({ search: search2, next }) => {
1475
- const result = next(search2);
1476
- try {
1477
- const validatedSearch = {
1478
- ...result,
1479
- ...validateSearch(route.options.validateSearch, result) ?? void 0
1480
- };
1481
- return validatedSearch;
1482
- } catch {
1483
- return result;
1484
- }
1485
- };
1486
- middlewares.push(validate);
1487
- }
1488
- return acc.concat(middlewares);
1489
- },
1490
- []
1491
- ) ?? [];
1492
- const final = ({ search: search2 }) => {
1355
+ }
1356
+ };
1357
+ context.middlewares.push(validate);
1358
+ }
1359
+ }
1360
+ const final = ({ search }) => {
1361
+ const dest = context.dest;
1493
1362
  if (!dest.search) {
1494
1363
  return {};
1495
1364
  }
1496
1365
  if (dest.search === true) {
1497
- return search2;
1366
+ return search;
1498
1367
  }
1499
- return functionalUpdate(dest.search, search2);
1368
+ return functionalUpdate(dest.search, search);
1500
1369
  };
1501
- allMiddlewares.push(final);
1502
- const applyNext = (index, currentSearch) => {
1503
- if (index >= allMiddlewares.length) {
1370
+ context.middlewares.push(final);
1371
+ const applyNext = (index, currentSearch, middlewares) => {
1372
+ if (index >= middlewares.length) {
1504
1373
  return currentSearch;
1505
1374
  }
1506
- const middleware = allMiddlewares[index];
1375
+ const middleware = middlewares[index];
1507
1376
  const next = (newSearch) => {
1508
- return applyNext(index + 1, newSearch);
1377
+ return applyNext(index + 1, newSearch, middlewares);
1509
1378
  };
1510
1379
  return middleware({ search: currentSearch, next });
1511
1380
  };
1512
- return applyNext(0, search);
1381
+ return function middleware(search, dest, _includeValidateSearch) {
1382
+ context.dest = dest;
1383
+ context._includeValidateSearch = _includeValidateSearch;
1384
+ return applyNext(0, search, context.middlewares);
1385
+ };
1513
1386
  }
1514
1387
  function findGlobalNotFoundRouteId(notFoundMode, routes) {
1515
1388
  if (notFoundMode !== "root") {
@@ -1526,8 +1399,6 @@ export {
1526
1399
  PathParamError,
1527
1400
  RouterCore,
1528
1401
  SearchParamError,
1529
- buildMatchSnapshot,
1530
- buildMatchSnapshotFromRoutes,
1531
1402
  defaultSerializeError,
1532
1403
  getInitialRouterState,
1533
1404
  getLocationChangeInfo,