@tanstack/react-router 1.16.2 → 1.16.5
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 -149
- 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 -150
- 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 +168 -179
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
|
-
|
|
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;
|
|
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;
|
|
610
576
|
}
|
|
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
|
})
|
|
@@ -808,20 +791,6 @@ class Router {
|
|
|
808
791
|
return matches;
|
|
809
792
|
};
|
|
810
793
|
this.invalidate = () => {
|
|
811
|
-
const invalidate = (d) => ({
|
|
812
|
-
...d,
|
|
813
|
-
invalid: true
|
|
814
|
-
});
|
|
815
|
-
this.__store.setState((s) => {
|
|
816
|
-
var _a;
|
|
817
|
-
return {
|
|
818
|
-
...s,
|
|
819
|
-
matches: s.matches.map(invalidate),
|
|
820
|
-
cachedMatches: s.cachedMatches.map(invalidate),
|
|
821
|
-
pendingMatches: (_a = s.pendingMatches) == null ? void 0 : _a.map(invalidate)
|
|
822
|
-
};
|
|
823
|
-
});
|
|
824
|
-
this.load();
|
|
825
794
|
};
|
|
826
795
|
this.load = async () => {
|
|
827
796
|
const promise = new Promise(async (resolve, reject) => {
|
|
@@ -860,6 +829,11 @@ class Router {
|
|
|
860
829
|
checkLatest: () => this.checkLatest(promise)
|
|
861
830
|
});
|
|
862
831
|
} catch (err) {
|
|
832
|
+
if (isRedirect(err)) {
|
|
833
|
+
this.handleRedirect(err);
|
|
834
|
+
} else if (isNotFound(err)) {
|
|
835
|
+
this.handleNotFound(pendingMatches, err);
|
|
836
|
+
}
|
|
863
837
|
}
|
|
864
838
|
if (latestPromise = this.checkLatest(promise)) {
|
|
865
839
|
return latestPromise;
|
|
@@ -913,6 +887,15 @@ class Router {
|
|
|
913
887
|
this.latestLoadPromise = promise;
|
|
914
888
|
return this.latestLoadPromise;
|
|
915
889
|
};
|
|
890
|
+
this.handleRedirect = (err) => {
|
|
891
|
+
if (!err.href) {
|
|
892
|
+
err.href = this.buildLocation(err).href;
|
|
893
|
+
}
|
|
894
|
+
if (isServer) {
|
|
895
|
+
throw err;
|
|
896
|
+
}
|
|
897
|
+
this.navigate(err);
|
|
898
|
+
};
|
|
916
899
|
this.cleanCache = () => {
|
|
917
900
|
this.__store.setState((s) => {
|
|
918
901
|
return {
|
|
@@ -951,12 +934,19 @@ class Router {
|
|
|
951
934
|
}
|
|
952
935
|
});
|
|
953
936
|
});
|
|
954
|
-
|
|
955
|
-
matches
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
937
|
+
try {
|
|
938
|
+
matches = await this.loadMatches({
|
|
939
|
+
matches,
|
|
940
|
+
preload: true,
|
|
941
|
+
checkLatest: () => void 0
|
|
942
|
+
});
|
|
943
|
+
return matches;
|
|
944
|
+
} catch (err) {
|
|
945
|
+
if (!isRedirect(err) && !isNotFound(err)) {
|
|
946
|
+
console.error(err);
|
|
947
|
+
}
|
|
948
|
+
return void 0;
|
|
949
|
+
}
|
|
960
950
|
};
|
|
961
951
|
this.matchRoute = (location, opts) => {
|
|
962
952
|
const matchLocation = {
|
|
@@ -1092,6 +1082,7 @@ class Router {
|
|
|
1092
1082
|
...match,
|
|
1093
1083
|
...dehydratedMatch,
|
|
1094
1084
|
meta: (_b2 = (_a2 = route.options).meta) == null ? void 0 : _b2.call(_a2, {
|
|
1085
|
+
params: match.params,
|
|
1095
1086
|
loaderData: dehydratedMatch.loaderData
|
|
1096
1087
|
}),
|
|
1097
1088
|
links: (_d = (_c2 = route.options).links) == null ? void 0 : _d.call(_c2),
|
|
@@ -1108,27 +1099,29 @@ class Router {
|
|
|
1108
1099
|
};
|
|
1109
1100
|
});
|
|
1110
1101
|
};
|
|
1111
|
-
this.
|
|
1102
|
+
this.handleNotFound = (matches, err) => {
|
|
1112
1103
|
const matchesByRouteId = Object.fromEntries(
|
|
1113
1104
|
matches.map((match) => [match.routeId, match])
|
|
1114
1105
|
);
|
|
1115
|
-
if (err.global) {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1106
|
+
if (!err.global && err.routeId) {
|
|
1107
|
+
let currentRoute = this.looseRoutesById[err.routeId];
|
|
1108
|
+
if (currentRoute) {
|
|
1109
|
+
while (!currentRoute.options.notFoundComponent) {
|
|
1110
|
+
currentRoute = currentRoute == null ? void 0 : currentRoute.parentRoute;
|
|
1111
|
+
invariant(
|
|
1112
|
+
currentRoute,
|
|
1113
|
+
"Found invalid route tree while trying to find not-found handler."
|
|
1114
|
+
);
|
|
1115
|
+
if (currentRoute.id === rootRouteId)
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
const match = matchesByRouteId[currentRoute.id];
|
|
1119
|
+
invariant(match, "Could not find match for route: " + currentRoute.id);
|
|
1120
|
+
match.notFoundError = err;
|
|
1121
|
+
return;
|
|
1127
1122
|
}
|
|
1128
|
-
const match = matchesByRouteId[currentRoute.id];
|
|
1129
|
-
invariant(match, "Could not find match for route: " + currentRoute.id);
|
|
1130
|
-
match.notFoundError = err;
|
|
1131
1123
|
}
|
|
1124
|
+
matchesByRouteId[rootRouteId].notFoundError = err;
|
|
1132
1125
|
};
|
|
1133
1126
|
this.hasNotFoundMatch = () => {
|
|
1134
1127
|
return this.__store.state.matches.some((d) => d.notFoundError);
|