@tanstack/react-router 1.16.2 → 1.16.6
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/dist/cjs/fileRoute.cjs.map +1 -1
- package/dist/cjs/fileRoute.d.cts +4 -2
- package/dist/cjs/link.cjs +16 -16
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/not-found.d.cts +1 -1
- package/dist/cjs/redirects.cjs.map +1 -1
- package/dist/cjs/redirects.d.cts +1 -0
- package/dist/cjs/route.cjs +1 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +4 -3
- package/dist/cjs/router.cjs +142 -135
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +4 -2
- package/dist/esm/fileRoute.d.ts +4 -2
- package/dist/esm/fileRoute.js.map +1 -1
- package/dist/esm/link.js +16 -16
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/not-found.d.ts +1 -1
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/redirects.d.ts +1 -0
- package/dist/esm/redirects.js.map +1 -1
- package/dist/esm/route.d.ts +4 -3
- package/dist/esm/route.js +1 -1
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +4 -2
- package/dist/esm/router.js +143 -136
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/fileRoute.ts +2 -2
- package/src/link.tsx +18 -18
- package/src/not-found.tsx +1 -1
- package/src/redirects.ts +1 -0
- package/src/route.ts +11 -3
- package/src/router.ts +167 -164
package/dist/esm/router.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createBrowserHistory, createMemoryHistory } from "@tanstack/history";
|
|
|
2
2
|
import { Store } from "@tanstack/react-store";
|
|
3
3
|
import { rootRouteId } from "./route.js";
|
|
4
4
|
import { defaultStringifySearch, defaultParseSearch } from "./searchParams.js";
|
|
5
|
-
import { replaceEqualDeep, pick, deepEqual, escapeJSON, last, functionalUpdate } from "./utils.js";
|
|
5
|
+
import { replaceEqualDeep, pick, isServer, deepEqual, escapeJSON, last, functionalUpdate } from "./utils.js";
|
|
6
6
|
import { getRouteMatch } from "./RouterProvider.js";
|
|
7
7
|
import { trimPath, trimPathLeft, parsePathname, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths } from "./path.js";
|
|
8
8
|
import invariant from "tiny-invariant";
|
|
@@ -552,111 +552,94 @@ class Router {
|
|
|
552
552
|
};
|
|
553
553
|
});
|
|
554
554
|
};
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
try {
|
|
571
|
-
(_b2 = (_a2 = route.options).onError) == null ? void 0 : _b2.call(_a2, err);
|
|
572
|
-
} catch (errorHandlerErr) {
|
|
573
|
-
err = errorHandlerErr;
|
|
574
|
-
if (isRedirect(errorHandlerErr)) {
|
|
575
|
-
throw errorHandlerErr;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
matches[index] = match = {
|
|
579
|
-
...match,
|
|
580
|
-
error: err,
|
|
581
|
-
status: "error",
|
|
582
|
-
updatedAt: Date.now(),
|
|
583
|
-
abortController: new AbortController()
|
|
584
|
-
};
|
|
585
|
-
};
|
|
555
|
+
for (let [index, match] of matches.entries()) {
|
|
556
|
+
const parentMatch = matches[index - 1];
|
|
557
|
+
const route = this.looseRoutesById[match.routeId];
|
|
558
|
+
const abortController = new AbortController();
|
|
559
|
+
const handleError = (err, code) => {
|
|
560
|
+
var _a2, _b2;
|
|
561
|
+
err.routerCode = code;
|
|
562
|
+
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
563
|
+
if (isRedirect(err)) {
|
|
564
|
+
throw err;
|
|
565
|
+
}
|
|
566
|
+
if (isNotFound(err)) {
|
|
567
|
+
err.routeId = match.routeId;
|
|
568
|
+
throw err;
|
|
569
|
+
}
|
|
586
570
|
try {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (
|
|
591
|
-
|
|
571
|
+
(_b2 = (_a2 = route.options).onError) == null ? void 0 : _b2.call(_a2, err);
|
|
572
|
+
} catch (errorHandlerErr) {
|
|
573
|
+
err = errorHandlerErr;
|
|
574
|
+
if (isRedirect(errorHandlerErr)) {
|
|
575
|
+
throw errorHandlerErr;
|
|
592
576
|
}
|
|
593
|
-
const parentContext = (parentMatch == null ? void 0 : parentMatch.context) ?? this.options.context ?? {};
|
|
594
|
-
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
595
|
-
const pendingPromise = typeof pendingMs === "number" && pendingMs <= 0 ? Promise.resolve() : new Promise((r) => setTimeout(r, pendingMs));
|
|
596
|
-
const beforeLoadContext = await ((_b = (_a = route.options).beforeLoad) == null ? void 0 : _b.call(_a, {
|
|
597
|
-
search: match.search,
|
|
598
|
-
abortController,
|
|
599
|
-
params: match.params,
|
|
600
|
-
preload: !!preload,
|
|
601
|
-
context: parentContext,
|
|
602
|
-
location: this.state.location,
|
|
603
|
-
// TOOD: just expose state and router, etc
|
|
604
|
-
navigate: (opts) => this.navigate({ ...opts, from: match.pathname }),
|
|
605
|
-
buildLocation: this.buildLocation,
|
|
606
|
-
cause: preload ? "preload" : match.cause
|
|
607
|
-
})) ?? {};
|
|
608
|
-
if (isRedirect(beforeLoadContext)) {
|
|
609
|
-
throw beforeLoadContext;
|
|
610
|
-
}
|
|
611
|
-
const context = {
|
|
612
|
-
...parentContext,
|
|
613
|
-
...beforeLoadContext
|
|
614
|
-
};
|
|
615
|
-
matches[index] = match = {
|
|
616
|
-
...match,
|
|
617
|
-
routeContext: replaceEqualDeep(
|
|
618
|
-
match.routeContext,
|
|
619
|
-
beforeLoadContext
|
|
620
|
-
),
|
|
621
|
-
context: replaceEqualDeep(match.context, context),
|
|
622
|
-
abortController,
|
|
623
|
-
pendingPromise
|
|
624
|
-
};
|
|
625
|
-
} catch (err) {
|
|
626
|
-
handleErrorAndRedirect(err, "BEFORE_LOAD");
|
|
627
|
-
break;
|
|
628
577
|
}
|
|
578
|
+
matches[index] = match = {
|
|
579
|
+
...match,
|
|
580
|
+
error: err,
|
|
581
|
+
status: "error",
|
|
582
|
+
updatedAt: Date.now(),
|
|
583
|
+
abortController: new AbortController()
|
|
584
|
+
};
|
|
585
|
+
};
|
|
586
|
+
try {
|
|
587
|
+
if (match.paramsError) {
|
|
588
|
+
handleError(match.paramsError, "PARSE_PARAMS");
|
|
589
|
+
}
|
|
590
|
+
if (match.searchError) {
|
|
591
|
+
handleError(match.searchError, "VALIDATE_SEARCH");
|
|
592
|
+
}
|
|
593
|
+
const parentContext = (parentMatch == null ? void 0 : parentMatch.context) ?? this.options.context ?? {};
|
|
594
|
+
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
595
|
+
const pendingPromise = typeof pendingMs === "number" && pendingMs <= 0 ? Promise.resolve() : new Promise((r) => setTimeout(r, pendingMs));
|
|
596
|
+
const beforeLoadContext = await ((_b = (_a = route.options).beforeLoad) == null ? void 0 : _b.call(_a, {
|
|
597
|
+
search: match.search,
|
|
598
|
+
abortController,
|
|
599
|
+
params: match.params,
|
|
600
|
+
preload: !!preload,
|
|
601
|
+
context: parentContext,
|
|
602
|
+
location: this.state.location,
|
|
603
|
+
// TOOD: just expose state and router, etc
|
|
604
|
+
navigate: (opts) => this.navigate({ ...opts, from: match.pathname }),
|
|
605
|
+
buildLocation: this.buildLocation,
|
|
606
|
+
cause: preload ? "preload" : match.cause
|
|
607
|
+
})) ?? {};
|
|
608
|
+
if (isRedirect(beforeLoadContext)) {
|
|
609
|
+
throw beforeLoadContext;
|
|
610
|
+
}
|
|
611
|
+
const context = {
|
|
612
|
+
...parentContext,
|
|
613
|
+
...beforeLoadContext
|
|
614
|
+
};
|
|
615
|
+
matches[index] = match = {
|
|
616
|
+
...match,
|
|
617
|
+
routeContext: replaceEqualDeep(match.routeContext, beforeLoadContext),
|
|
618
|
+
context: replaceEqualDeep(match.context, context),
|
|
619
|
+
abortController,
|
|
620
|
+
pendingPromise
|
|
621
|
+
};
|
|
622
|
+
} catch (err) {
|
|
623
|
+
handleError(err, "BEFORE_LOAD");
|
|
624
|
+
break;
|
|
629
625
|
}
|
|
630
|
-
} catch (err) {
|
|
631
|
-
if (isRedirect(err)) {
|
|
632
|
-
if (!preload)
|
|
633
|
-
this.navigate(err);
|
|
634
|
-
return matches;
|
|
635
|
-
}
|
|
636
|
-
throw err;
|
|
637
626
|
}
|
|
638
627
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
639
628
|
const matchPromises = [];
|
|
640
629
|
validResolvedMatches.forEach((match, index) => {
|
|
641
630
|
matchPromises.push(
|
|
642
|
-
new Promise(async (resolve) => {
|
|
631
|
+
new Promise(async (resolve, reject) => {
|
|
643
632
|
var _a2;
|
|
644
633
|
const parentMatchPromise = matchPromises[index - 1];
|
|
645
634
|
const route = this.looseRoutesById[match.routeId];
|
|
646
|
-
const
|
|
635
|
+
const handleError = (err) => {
|
|
647
636
|
if (isRedirect(err)) {
|
|
648
|
-
|
|
649
|
-
this.navigate(err);
|
|
650
|
-
}
|
|
651
|
-
return true;
|
|
637
|
+
throw err;
|
|
652
638
|
}
|
|
653
639
|
if (isNotFound(err)) {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
return true;
|
|
640
|
+
err.routeId = match.routeId;
|
|
641
|
+
throw err;
|
|
658
642
|
}
|
|
659
|
-
return false;
|
|
660
643
|
};
|
|
661
644
|
let loadPromise;
|
|
662
645
|
matches[index] = match = {
|
|
@@ -724,10 +707,7 @@ class Router {
|
|
|
724
707
|
const loaderData = await loadPromise;
|
|
725
708
|
if (latestPromise = checkLatest())
|
|
726
709
|
return await latestPromise;
|
|
727
|
-
|
|
728
|
-
if (handleErrorAndRedirect(loaderData))
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
710
|
+
handleError(loaderData);
|
|
731
711
|
if (didShowPending && pendingMinMs) {
|
|
732
712
|
await new Promise((r) => setTimeout(r, pendingMinMs));
|
|
733
713
|
}
|
|
@@ -735,6 +715,7 @@ class Router {
|
|
|
735
715
|
return await latestPromise;
|
|
736
716
|
const [meta, headers] = await Promise.all([
|
|
737
717
|
(_d = (_c = route.options).meta) == null ? void 0 : _d.call(_c, {
|
|
718
|
+
params: match.params,
|
|
738
719
|
loaderData
|
|
739
720
|
}),
|
|
740
721
|
(_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, {
|
|
@@ -755,14 +736,12 @@ class Router {
|
|
|
755
736
|
} catch (error) {
|
|
756
737
|
if (latestPromise = checkLatest())
|
|
757
738
|
return await latestPromise;
|
|
758
|
-
|
|
759
|
-
return;
|
|
739
|
+
handleError(error);
|
|
760
740
|
try {
|
|
761
741
|
(_h = (_g = route.options).onError) == null ? void 0 : _h.call(_g, error);
|
|
762
742
|
} catch (onErrorError) {
|
|
763
743
|
error = onErrorError;
|
|
764
|
-
|
|
765
|
-
return;
|
|
744
|
+
handleError(onErrorError);
|
|
766
745
|
}
|
|
767
746
|
matches[index] = match = {
|
|
768
747
|
...match,
|
|
@@ -782,23 +761,27 @@ class Router {
|
|
|
782
761
|
...match,
|
|
783
762
|
preload: !!preload && !this.state.matches.find((d) => d.id === match.id)
|
|
784
763
|
};
|
|
785
|
-
|
|
786
|
-
if (
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
764
|
+
try {
|
|
765
|
+
if (match.status !== "success") {
|
|
766
|
+
if (shouldPending) {
|
|
767
|
+
(_a2 = match.pendingPromise) == null ? void 0 : _a2.then(async () => {
|
|
768
|
+
if (latestPromise = checkLatest())
|
|
769
|
+
return latestPromise;
|
|
770
|
+
didShowPending = true;
|
|
771
|
+
matches[index] = match = {
|
|
772
|
+
...match,
|
|
773
|
+
showPending: true
|
|
774
|
+
};
|
|
775
|
+
updateMatch(match);
|
|
776
|
+
resolve();
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
await fetch();
|
|
780
|
+
} else if (match.invalid || (shouldReload ?? age > staleAge)) {
|
|
781
|
+
fetch();
|
|
798
782
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
fetch();
|
|
783
|
+
} catch (err) {
|
|
784
|
+
reject(err);
|
|
802
785
|
}
|
|
803
786
|
resolve();
|
|
804
787
|
})
|
|
@@ -860,6 +843,11 @@ class Router {
|
|
|
860
843
|
checkLatest: () => this.checkLatest(promise)
|
|
861
844
|
});
|
|
862
845
|
} catch (err) {
|
|
846
|
+
if (isRedirect(err)) {
|
|
847
|
+
this.handleRedirect(err);
|
|
848
|
+
} else if (isNotFound(err)) {
|
|
849
|
+
this.handleNotFound(pendingMatches, err);
|
|
850
|
+
}
|
|
863
851
|
}
|
|
864
852
|
if (latestPromise = this.checkLatest(promise)) {
|
|
865
853
|
return latestPromise;
|
|
@@ -913,6 +901,15 @@ class Router {
|
|
|
913
901
|
this.latestLoadPromise = promise;
|
|
914
902
|
return this.latestLoadPromise;
|
|
915
903
|
};
|
|
904
|
+
this.handleRedirect = (err) => {
|
|
905
|
+
if (!err.href) {
|
|
906
|
+
err.href = this.buildLocation(err).href;
|
|
907
|
+
}
|
|
908
|
+
if (isServer) {
|
|
909
|
+
throw err;
|
|
910
|
+
}
|
|
911
|
+
this.navigate(err);
|
|
912
|
+
};
|
|
916
913
|
this.cleanCache = () => {
|
|
917
914
|
this.__store.setState((s) => {
|
|
918
915
|
return {
|
|
@@ -951,12 +948,19 @@ class Router {
|
|
|
951
948
|
}
|
|
952
949
|
});
|
|
953
950
|
});
|
|
954
|
-
|
|
955
|
-
matches
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
951
|
+
try {
|
|
952
|
+
matches = await this.loadMatches({
|
|
953
|
+
matches,
|
|
954
|
+
preload: true,
|
|
955
|
+
checkLatest: () => void 0
|
|
956
|
+
});
|
|
957
|
+
return matches;
|
|
958
|
+
} catch (err) {
|
|
959
|
+
if (!isRedirect(err) && !isNotFound(err)) {
|
|
960
|
+
console.error(err);
|
|
961
|
+
}
|
|
962
|
+
return void 0;
|
|
963
|
+
}
|
|
960
964
|
};
|
|
961
965
|
this.matchRoute = (location, opts) => {
|
|
962
966
|
const matchLocation = {
|
|
@@ -1092,6 +1096,7 @@ class Router {
|
|
|
1092
1096
|
...match,
|
|
1093
1097
|
...dehydratedMatch,
|
|
1094
1098
|
meta: (_b2 = (_a2 = route.options).meta) == null ? void 0 : _b2.call(_a2, {
|
|
1099
|
+
params: match.params,
|
|
1095
1100
|
loaderData: dehydratedMatch.loaderData
|
|
1096
1101
|
}),
|
|
1097
1102
|
links: (_d = (_c2 = route.options).links) == null ? void 0 : _d.call(_c2),
|
|
@@ -1108,27 +1113,29 @@ class Router {
|
|
|
1108
1113
|
};
|
|
1109
1114
|
});
|
|
1110
1115
|
};
|
|
1111
|
-
this.
|
|
1116
|
+
this.handleNotFound = (matches, err) => {
|
|
1112
1117
|
const matchesByRouteId = Object.fromEntries(
|
|
1113
1118
|
matches.map((match) => [match.routeId, match])
|
|
1114
1119
|
);
|
|
1115
|
-
if (err.global) {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1120
|
+
if (!err.global && err.routeId) {
|
|
1121
|
+
let currentRoute = this.looseRoutesById[err.routeId];
|
|
1122
|
+
if (currentRoute) {
|
|
1123
|
+
while (!currentRoute.options.notFoundComponent) {
|
|
1124
|
+
currentRoute = currentRoute == null ? void 0 : currentRoute.parentRoute;
|
|
1125
|
+
invariant(
|
|
1126
|
+
currentRoute,
|
|
1127
|
+
"Found invalid route tree while trying to find not-found handler."
|
|
1128
|
+
);
|
|
1129
|
+
if (currentRoute.id === rootRouteId)
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
const match = matchesByRouteId[currentRoute.id];
|
|
1133
|
+
invariant(match, "Could not find match for route: " + currentRoute.id);
|
|
1134
|
+
match.notFoundError = err;
|
|
1135
|
+
return;
|
|
1127
1136
|
}
|
|
1128
|
-
const match = matchesByRouteId[currentRoute.id];
|
|
1129
|
-
invariant(match, "Could not find match for route: " + currentRoute.id);
|
|
1130
|
-
match.notFoundError = err;
|
|
1131
1137
|
}
|
|
1138
|
+
matchesByRouteId[rootRouteId].notFoundError = err;
|
|
1132
1139
|
};
|
|
1133
1140
|
this.hasNotFoundMatch = () => {
|
|
1134
1141
|
return this.__store.state.matches.some((d) => d.notFoundError);
|