@tanstack/router-core 1.131.14 → 1.131.17

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.
@@ -703,525 +703,615 @@ class RouterCore {
703
703
  const findFn = (d) => d.id === matchId;
704
704
  return this.state.cachedMatches.find(findFn) ?? ((_a = this.state.pendingMatches) == null ? void 0 : _a.find(findFn)) ?? this.state.matches.find(findFn);
705
705
  };
706
- this.loadMatches = async ({
707
- location,
708
- matches,
709
- preload: allPreload,
710
- onReady,
711
- updateMatch = this.updateMatch,
712
- sync
713
- }) => {
714
- let firstBadMatchIndex;
715
- let rendered = false;
716
- const triggerOnReady = async () => {
717
- if (!rendered) {
718
- rendered = true;
719
- await (onReady == null ? void 0 : onReady());
706
+ this.triggerOnReady = (innerLoadContext) => {
707
+ var _a;
708
+ if (!innerLoadContext.rendered) {
709
+ innerLoadContext.rendered = true;
710
+ return (_a = innerLoadContext.onReady) == null ? void 0 : _a.call(innerLoadContext);
711
+ }
712
+ };
713
+ this.resolvePreload = (innerLoadContext, matchId) => {
714
+ return !!(innerLoadContext.preload && !this.state.matches.some((d) => d.id === matchId));
715
+ };
716
+ this.handleRedirectAndNotFound = (innerLoadContext, match, err) => {
717
+ var _a, _b, _c;
718
+ if (!isRedirect(err) && !isNotFound(err)) return;
719
+ if (isRedirect(err) && err.redirectHandled && !err.options.reloadDocument) {
720
+ throw err;
721
+ }
722
+ if (match) {
723
+ (_a = match._nonReactive.beforeLoadPromise) == null ? void 0 : _a.resolve();
724
+ (_b = match._nonReactive.loaderPromise) == null ? void 0 : _b.resolve();
725
+ match._nonReactive.beforeLoadPromise = void 0;
726
+ match._nonReactive.loaderPromise = void 0;
727
+ const status = isRedirect(err) ? "redirected" : "notFound";
728
+ innerLoadContext.updateMatch(match.id, (prev) => ({
729
+ ...prev,
730
+ status,
731
+ isFetching: false,
732
+ error: err
733
+ }));
734
+ if (isNotFound(err) && !err.routeId) {
735
+ err.routeId = match.routeId;
736
+ }
737
+ (_c = match._nonReactive.loadPromise) == null ? void 0 : _c.resolve();
738
+ }
739
+ if (isRedirect(err)) {
740
+ innerLoadContext.rendered = true;
741
+ err.options._fromLocation = innerLoadContext.location;
742
+ err.redirectHandled = true;
743
+ err = this.resolveRedirect(err);
744
+ throw err;
745
+ } else {
746
+ this._handleNotFound(innerLoadContext, err);
747
+ throw err;
748
+ }
749
+ };
750
+ this.shouldSkipLoader = (matchId) => {
751
+ const match = this.getMatch(matchId);
752
+ if (!this.isServer && match._nonReactive.dehydrated) {
753
+ return true;
754
+ }
755
+ if (this.isServer) {
756
+ if (match.ssr === false) {
757
+ return true;
720
758
  }
759
+ }
760
+ return false;
761
+ };
762
+ this.handleSerialError = (innerLoadContext, index, err, routerCode) => {
763
+ var _a, _b;
764
+ const { id: matchId, routeId } = innerLoadContext.matches[index];
765
+ const route = this.looseRoutesById[routeId];
766
+ if (err instanceof Promise) {
767
+ throw err;
768
+ }
769
+ err.routerCode = routerCode;
770
+ innerLoadContext.firstBadMatchIndex ?? (innerLoadContext.firstBadMatchIndex = index);
771
+ this.handleRedirectAndNotFound(
772
+ innerLoadContext,
773
+ this.getMatch(matchId),
774
+ err
775
+ );
776
+ try {
777
+ (_b = (_a = route.options).onError) == null ? void 0 : _b.call(_a, err);
778
+ } catch (errorHandlerErr) {
779
+ err = errorHandlerErr;
780
+ this.handleRedirectAndNotFound(
781
+ innerLoadContext,
782
+ this.getMatch(matchId),
783
+ err
784
+ );
785
+ }
786
+ innerLoadContext.updateMatch(matchId, (prev) => {
787
+ var _a2, _b2;
788
+ (_a2 = prev._nonReactive.beforeLoadPromise) == null ? void 0 : _a2.resolve();
789
+ prev._nonReactive.beforeLoadPromise = void 0;
790
+ (_b2 = prev._nonReactive.loadPromise) == null ? void 0 : _b2.resolve();
791
+ return {
792
+ ...prev,
793
+ error: err,
794
+ status: "error",
795
+ isFetching: false,
796
+ updatedAt: Date.now(),
797
+ abortController: new AbortController()
798
+ };
799
+ });
800
+ };
801
+ this.isBeforeLoadSsr = (innerLoadContext, matchId, index, route) => {
802
+ var _a;
803
+ const existingMatch = this.getMatch(matchId);
804
+ const parentMatchId = (_a = innerLoadContext.matches[index - 1]) == null ? void 0 : _a.id;
805
+ const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
806
+ if (this.isShell()) {
807
+ existingMatch.ssr = matchId === rootRouteId;
808
+ return;
809
+ }
810
+ if ((parentMatch == null ? void 0 : parentMatch.ssr) === false) {
811
+ existingMatch.ssr = false;
812
+ return;
813
+ }
814
+ const parentOverride = (tempSsr2) => {
815
+ if (tempSsr2 === true && (parentMatch == null ? void 0 : parentMatch.ssr) === "data-only") {
816
+ return "data-only";
817
+ }
818
+ return tempSsr2;
721
819
  };
722
- const resolvePreload = (matchId) => {
723
- return !!(allPreload && !this.state.matches.some((d) => d.id === matchId));
820
+ const defaultSsr = this.options.defaultSsr ?? true;
821
+ if (route.options.ssr === void 0) {
822
+ existingMatch.ssr = parentOverride(defaultSsr);
823
+ return;
824
+ }
825
+ if (typeof route.options.ssr !== "function") {
826
+ existingMatch.ssr = parentOverride(route.options.ssr);
827
+ return;
828
+ }
829
+ const { search, params } = this.getMatch(matchId);
830
+ const ssrFnContext = {
831
+ search: makeMaybe(search, existingMatch.searchError),
832
+ params: makeMaybe(params, existingMatch.paramsError),
833
+ location: innerLoadContext.location,
834
+ matches: innerLoadContext.matches.map((match) => ({
835
+ index: match.index,
836
+ pathname: match.pathname,
837
+ fullPath: match.fullPath,
838
+ staticData: match.staticData,
839
+ id: match.id,
840
+ routeId: match.routeId,
841
+ search: makeMaybe(match.search, match.searchError),
842
+ params: makeMaybe(match.params, match.paramsError),
843
+ ssr: match.ssr
844
+ }))
724
845
  };
725
- if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
726
- triggerOnReady();
846
+ const tempSsr = route.options.ssr(ssrFnContext);
847
+ if (isPromise(tempSsr)) {
848
+ return tempSsr.then((ssr) => {
849
+ existingMatch.ssr = parentOverride(ssr ?? defaultSsr);
850
+ });
727
851
  }
728
- const handleRedirectAndNotFound = (match, err) => {
729
- var _a, _b, _c;
730
- if (!isRedirect(err) && !isNotFound(err)) return;
731
- if (isRedirect(err) && err.redirectHandled && !err.options.reloadDocument) {
732
- throw err;
852
+ existingMatch.ssr = parentOverride(tempSsr ?? defaultSsr);
853
+ return;
854
+ };
855
+ this.setupPendingTimeout = (innerLoadContext, matchId, route) => {
856
+ var _a;
857
+ const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
858
+ const shouldPending = !!(innerLoadContext.onReady && !this.isServer && !this.resolvePreload(innerLoadContext, matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? ((_a = this.options) == null ? void 0 : _a.defaultPendingComponent)));
859
+ const match = this.getMatch(matchId);
860
+ if (shouldPending && match._nonReactive.pendingTimeout === void 0) {
861
+ const pendingTimeout = setTimeout(() => {
862
+ this.triggerOnReady(innerLoadContext);
863
+ }, pendingMs);
864
+ match._nonReactive.pendingTimeout = pendingTimeout;
865
+ }
866
+ };
867
+ this.shouldExecuteBeforeLoad = (innerLoadContext, matchId, route) => {
868
+ const existingMatch = this.getMatch(matchId);
869
+ if (!existingMatch._nonReactive.beforeLoadPromise && !existingMatch._nonReactive.loaderPromise)
870
+ return true;
871
+ this.setupPendingTimeout(innerLoadContext, matchId, route);
872
+ const then = () => {
873
+ let shouldExecuteBeforeLoad = true;
874
+ const match = this.getMatch(matchId);
875
+ if (match.status === "error") {
876
+ shouldExecuteBeforeLoad = true;
877
+ } else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
878
+ this.handleRedirectAndNotFound(innerLoadContext, match, match.error);
733
879
  }
734
- if (match) {
735
- (_a = match._nonReactive.beforeLoadPromise) == null ? void 0 : _a.resolve();
736
- (_b = match._nonReactive.loaderPromise) == null ? void 0 : _b.resolve();
737
- match._nonReactive.beforeLoadPromise = void 0;
738
- match._nonReactive.loaderPromise = void 0;
739
- const status = isRedirect(err) ? "redirected" : "notFound";
740
- updateMatch(match.id, (prev) => ({
880
+ return shouldExecuteBeforeLoad;
881
+ };
882
+ return existingMatch._nonReactive.beforeLoadPromise ? existingMatch._nonReactive.beforeLoadPromise.then(then) : then();
883
+ };
884
+ this.executeBeforeLoad = (innerLoadContext, matchId, index, route) => {
885
+ var _a;
886
+ const match = this.getMatch(matchId);
887
+ match._nonReactive.beforeLoadPromise = createControlledPromise();
888
+ const prevLoadPromise = match._nonReactive.loadPromise;
889
+ match._nonReactive.loadPromise = createControlledPromise(() => {
890
+ prevLoadPromise == null ? void 0 : prevLoadPromise.resolve();
891
+ });
892
+ const { paramsError, searchError } = match;
893
+ if (paramsError) {
894
+ this.handleSerialError(
895
+ innerLoadContext,
896
+ index,
897
+ paramsError,
898
+ "PARSE_PARAMS"
899
+ );
900
+ }
901
+ if (searchError) {
902
+ this.handleSerialError(
903
+ innerLoadContext,
904
+ index,
905
+ searchError,
906
+ "VALIDATE_SEARCH"
907
+ );
908
+ }
909
+ this.setupPendingTimeout(innerLoadContext, matchId, route);
910
+ const abortController = new AbortController();
911
+ const parentMatchId = (_a = innerLoadContext.matches[index - 1]) == null ? void 0 : _a.id;
912
+ const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
913
+ const parentMatchContext = (parentMatch == null ? void 0 : parentMatch.context) ?? this.options.context ?? void 0;
914
+ const context = { ...parentMatchContext, ...match.__routeContext };
915
+ let isPending = false;
916
+ const pending = () => {
917
+ if (isPending) return;
918
+ isPending = true;
919
+ innerLoadContext.updateMatch(matchId, (prev) => ({
920
+ ...prev,
921
+ isFetching: "beforeLoad",
922
+ fetchCount: prev.fetchCount + 1,
923
+ abortController,
924
+ context
925
+ }));
926
+ };
927
+ const resolve = () => {
928
+ var _a2;
929
+ (_a2 = match._nonReactive.beforeLoadPromise) == null ? void 0 : _a2.resolve();
930
+ match._nonReactive.beforeLoadPromise = void 0;
931
+ innerLoadContext.updateMatch(matchId, (prev) => ({
932
+ ...prev,
933
+ isFetching: false
934
+ }));
935
+ };
936
+ if (!route.options.beforeLoad) {
937
+ batch(() => {
938
+ pending();
939
+ resolve();
940
+ });
941
+ return;
942
+ }
943
+ const { search, params, cause } = match;
944
+ const preload = this.resolvePreload(innerLoadContext, matchId);
945
+ const beforeLoadFnContext = {
946
+ search,
947
+ abortController,
948
+ params,
949
+ preload,
950
+ context,
951
+ location: innerLoadContext.location,
952
+ navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
953
+ buildLocation: this.buildLocation,
954
+ cause: preload ? "preload" : cause,
955
+ matches: innerLoadContext.matches
956
+ };
957
+ const updateContext = (beforeLoadContext2) => {
958
+ if (beforeLoadContext2 === void 0) {
959
+ batch(() => {
960
+ pending();
961
+ resolve();
962
+ });
963
+ return;
964
+ }
965
+ if (isRedirect(beforeLoadContext2) || isNotFound(beforeLoadContext2)) {
966
+ pending();
967
+ this.handleSerialError(
968
+ innerLoadContext,
969
+ index,
970
+ beforeLoadContext2,
971
+ "BEFORE_LOAD"
972
+ );
973
+ }
974
+ batch(() => {
975
+ pending();
976
+ innerLoadContext.updateMatch(matchId, (prev) => ({
741
977
  ...prev,
742
- status,
743
- isFetching: false,
744
- error: err
978
+ __beforeLoadContext: beforeLoadContext2,
979
+ context: {
980
+ ...prev.context,
981
+ ...beforeLoadContext2
982
+ }
745
983
  }));
746
- if (isNotFound(err) && !err.routeId) {
747
- err.routeId = match.routeId;
748
- }
749
- (_c = match._nonReactive.loadPromise) == null ? void 0 : _c.resolve();
984
+ resolve();
985
+ });
986
+ };
987
+ let beforeLoadContext;
988
+ try {
989
+ beforeLoadContext = route.options.beforeLoad(beforeLoadFnContext);
990
+ if (isPromise(beforeLoadContext)) {
991
+ pending();
992
+ return beforeLoadContext.catch((err) => {
993
+ this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
994
+ }).then(updateContext);
750
995
  }
751
- if (isRedirect(err)) {
752
- rendered = true;
753
- err.options._fromLocation = location;
754
- err.redirectHandled = true;
755
- err = this.resolveRedirect(err);
756
- throw err;
757
- } else {
758
- this._handleNotFound(matches, err, updateMatch);
759
- throw err;
996
+ } catch (err) {
997
+ pending();
998
+ this.handleSerialError(innerLoadContext, index, err, "BEFORE_LOAD");
999
+ }
1000
+ updateContext(beforeLoadContext);
1001
+ return;
1002
+ };
1003
+ this.handleBeforeLoad = (innerLoadContext, index) => {
1004
+ const { id: matchId, routeId } = innerLoadContext.matches[index];
1005
+ const route = this.looseRoutesById[routeId];
1006
+ const serverSsr = () => {
1007
+ if (this.isServer) {
1008
+ const maybePromise = this.isBeforeLoadSsr(
1009
+ innerLoadContext,
1010
+ matchId,
1011
+ index,
1012
+ route
1013
+ );
1014
+ if (isPromise(maybePromise)) return maybePromise.then(queueExecution);
760
1015
  }
1016
+ return queueExecution();
761
1017
  };
762
- const shouldSkipLoader = (matchId) => {
1018
+ const queueExecution = () => {
1019
+ if (this.shouldSkipLoader(matchId)) return;
1020
+ const shouldExecuteBeforeLoadResult = this.shouldExecuteBeforeLoad(
1021
+ innerLoadContext,
1022
+ matchId,
1023
+ route
1024
+ );
1025
+ return isPromise(shouldExecuteBeforeLoadResult) ? shouldExecuteBeforeLoadResult.then(execute) : execute(shouldExecuteBeforeLoadResult);
1026
+ };
1027
+ const execute = (shouldExecuteBeforeLoad) => {
1028
+ if (shouldExecuteBeforeLoad) {
1029
+ return this.executeBeforeLoad(innerLoadContext, matchId, index, route);
1030
+ }
1031
+ return;
1032
+ };
1033
+ return serverSsr();
1034
+ };
1035
+ this.executeHead = (innerLoadContext, matchId, route) => {
1036
+ var _a, _b, _c, _d, _e, _f;
1037
+ const match = this.getMatch(matchId);
1038
+ if (!match) {
1039
+ return;
1040
+ }
1041
+ if (!route.options.head && !route.options.scripts && !route.options.headers) {
1042
+ return;
1043
+ }
1044
+ const assetContext = {
1045
+ matches: innerLoadContext.matches,
1046
+ match,
1047
+ params: match.params,
1048
+ loaderData: match.loaderData
1049
+ };
1050
+ return Promise.all([
1051
+ (_b = (_a = route.options).head) == null ? void 0 : _b.call(_a, assetContext),
1052
+ (_d = (_c = route.options).scripts) == null ? void 0 : _d.call(_c, assetContext),
1053
+ (_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext)
1054
+ ]).then(([headFnContent, scripts, headers]) => {
1055
+ const meta = headFnContent == null ? void 0 : headFnContent.meta;
1056
+ const links = headFnContent == null ? void 0 : headFnContent.links;
1057
+ const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
1058
+ const styles = headFnContent == null ? void 0 : headFnContent.styles;
1059
+ return {
1060
+ meta,
1061
+ links,
1062
+ headScripts,
1063
+ headers,
1064
+ scripts,
1065
+ styles
1066
+ };
1067
+ });
1068
+ };
1069
+ this.potentialPendingMinPromise = (matchId) => {
1070
+ const latestMatch = this.getMatch(matchId);
1071
+ return latestMatch._nonReactive.minPendingPromise;
1072
+ };
1073
+ this.getLoaderContext = (innerLoadContext, matchId, index, route) => {
1074
+ const parentMatchPromise = innerLoadContext.matchPromises[index - 1];
1075
+ const { params, loaderDeps, abortController, context, cause } = this.getMatch(matchId);
1076
+ const preload = this.resolvePreload(innerLoadContext, matchId);
1077
+ return {
1078
+ params,
1079
+ deps: loaderDeps,
1080
+ preload: !!preload,
1081
+ parentMatchPromise,
1082
+ abortController,
1083
+ context,
1084
+ location: innerLoadContext.location,
1085
+ navigate: (opts) => this.navigate({ ...opts, _fromLocation: innerLoadContext.location }),
1086
+ cause: preload ? "preload" : cause,
1087
+ route
1088
+ };
1089
+ };
1090
+ this.runLoader = async (innerLoadContext, matchId, index, route) => {
1091
+ var _a, _b, _c, _d;
1092
+ try {
1093
+ try {
1094
+ if (!this.isServer || this.getMatch(matchId).ssr === true) {
1095
+ this.loadRouteChunk(route);
1096
+ }
1097
+ const loaderResult = (_b = (_a = route.options).loader) == null ? void 0 : _b.call(
1098
+ _a,
1099
+ this.getLoaderContext(innerLoadContext, matchId, index, route)
1100
+ );
1101
+ const loaderResultIsPromise = route.options.loader && isPromise(loaderResult);
1102
+ const willLoadSomething = !!(loaderResultIsPromise || route._lazyPromise || route._componentsPromise || route.options.head || route.options.scripts || route.options.headers || this.getMatch(matchId)._nonReactive.minPendingPromise);
1103
+ if (willLoadSomething) {
1104
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1105
+ ...prev,
1106
+ isFetching: "loader"
1107
+ }));
1108
+ }
1109
+ if (route.options.loader) {
1110
+ const loaderData = loaderResultIsPromise ? await loaderResult : loaderResult;
1111
+ this.handleRedirectAndNotFound(
1112
+ innerLoadContext,
1113
+ this.getMatch(matchId),
1114
+ loaderData
1115
+ );
1116
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1117
+ ...prev,
1118
+ loaderData
1119
+ }));
1120
+ }
1121
+ if (route._lazyPromise) await route._lazyPromise;
1122
+ const headResult = this.executeHead(innerLoadContext, matchId, route);
1123
+ const head = headResult ? await headResult : void 0;
1124
+ const pendingPromise = this.potentialPendingMinPromise(matchId);
1125
+ if (pendingPromise) await pendingPromise;
1126
+ if (route._componentsPromise) await route._componentsPromise;
1127
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1128
+ ...prev,
1129
+ error: void 0,
1130
+ status: "success",
1131
+ isFetching: false,
1132
+ updatedAt: Date.now(),
1133
+ ...head
1134
+ }));
1135
+ } catch (e) {
1136
+ let error = e;
1137
+ const pendingPromise = this.potentialPendingMinPromise(matchId);
1138
+ if (pendingPromise) await pendingPromise;
1139
+ this.handleRedirectAndNotFound(
1140
+ innerLoadContext,
1141
+ this.getMatch(matchId),
1142
+ e
1143
+ );
1144
+ try {
1145
+ (_d = (_c = route.options).onError) == null ? void 0 : _d.call(_c, e);
1146
+ } catch (onErrorError) {
1147
+ error = onErrorError;
1148
+ this.handleRedirectAndNotFound(
1149
+ innerLoadContext,
1150
+ this.getMatch(matchId),
1151
+ onErrorError
1152
+ );
1153
+ }
1154
+ const headResult = this.executeHead(innerLoadContext, matchId, route);
1155
+ const head = headResult ? await headResult : void 0;
1156
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1157
+ ...prev,
1158
+ error,
1159
+ status: "error",
1160
+ isFetching: false,
1161
+ ...head
1162
+ }));
1163
+ }
1164
+ } catch (err) {
763
1165
  const match = this.getMatch(matchId);
764
- if (!this.isServer && match._nonReactive.dehydrated) {
765
- return true;
1166
+ if (match) {
1167
+ const headResult = this.executeHead(innerLoadContext, matchId, route);
1168
+ if (headResult) {
1169
+ const head = await headResult;
1170
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1171
+ ...prev,
1172
+ ...head
1173
+ }));
1174
+ }
1175
+ match._nonReactive.loaderPromise = void 0;
766
1176
  }
1177
+ this.handleRedirectAndNotFound(innerLoadContext, match, err);
1178
+ }
1179
+ };
1180
+ this.loadRouteMatch = async (innerLoadContext, index) => {
1181
+ var _a, _b;
1182
+ const { id: matchId, routeId } = innerLoadContext.matches[index];
1183
+ let loaderShouldRunAsync = false;
1184
+ let loaderIsRunningAsync = false;
1185
+ const route = this.looseRoutesById[routeId];
1186
+ const prevMatch = this.getMatch(matchId);
1187
+ if (this.shouldSkipLoader(matchId)) {
767
1188
  if (this.isServer) {
768
- if (match.ssr === false) {
769
- return true;
1189
+ const headResult = this.executeHead(innerLoadContext, matchId, route);
1190
+ if (headResult) {
1191
+ const head = await headResult;
1192
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1193
+ ...prev,
1194
+ ...head
1195
+ }));
770
1196
  }
1197
+ return this.getMatch(matchId);
771
1198
  }
772
- return false;
773
- };
1199
+ } else if (prevMatch._nonReactive.loaderPromise) {
1200
+ if (prevMatch.status === "success" && !innerLoadContext.sync && !prevMatch.preload) {
1201
+ return this.getMatch(matchId);
1202
+ }
1203
+ await prevMatch._nonReactive.loaderPromise;
1204
+ const match = this.getMatch(matchId);
1205
+ if (match.error) {
1206
+ this.handleRedirectAndNotFound(innerLoadContext, match, match.error);
1207
+ }
1208
+ } else {
1209
+ const age = Date.now() - this.getMatch(matchId).updatedAt;
1210
+ const preload = this.resolvePreload(innerLoadContext, matchId);
1211
+ const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
1212
+ const shouldReloadOption = route.options.shouldReload;
1213
+ const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(
1214
+ this.getLoaderContext(innerLoadContext, matchId, index, route)
1215
+ ) : shouldReloadOption;
1216
+ innerLoadContext.updateMatch(matchId, (prev) => {
1217
+ prev._nonReactive.loaderPromise = createControlledPromise();
1218
+ return {
1219
+ ...prev,
1220
+ preload: !!preload && !this.state.matches.some((d) => d.id === matchId)
1221
+ };
1222
+ });
1223
+ const { status, invalid } = this.getMatch(matchId);
1224
+ loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
1225
+ if (preload && route.options.preload === false) ;
1226
+ else if (loaderShouldRunAsync && !innerLoadContext.sync) {
1227
+ loaderIsRunningAsync = true;
1228
+ (async () => {
1229
+ var _a2, _b2;
1230
+ try {
1231
+ await this.runLoader(innerLoadContext, matchId, index, route);
1232
+ const match = this.getMatch(matchId);
1233
+ (_a2 = match._nonReactive.loaderPromise) == null ? void 0 : _a2.resolve();
1234
+ (_b2 = match._nonReactive.loadPromise) == null ? void 0 : _b2.resolve();
1235
+ match._nonReactive.loaderPromise = void 0;
1236
+ } catch (err) {
1237
+ if (isRedirect(err)) {
1238
+ await this.navigate(err.options);
1239
+ }
1240
+ }
1241
+ })();
1242
+ } else if (status !== "success" || loaderShouldRunAsync && innerLoadContext.sync) {
1243
+ await this.runLoader(innerLoadContext, matchId, index, route);
1244
+ } else {
1245
+ const headResult = this.executeHead(innerLoadContext, matchId, route);
1246
+ if (headResult) {
1247
+ const head = await headResult;
1248
+ innerLoadContext.updateMatch(matchId, (prev) => ({
1249
+ ...prev,
1250
+ ...head
1251
+ }));
1252
+ }
1253
+ }
1254
+ }
1255
+ if (!loaderIsRunningAsync) {
1256
+ const match = this.getMatch(matchId);
1257
+ (_a = match._nonReactive.loaderPromise) == null ? void 0 : _a.resolve();
1258
+ (_b = match._nonReactive.loadPromise) == null ? void 0 : _b.resolve();
1259
+ }
1260
+ innerLoadContext.updateMatch(matchId, (prev) => {
1261
+ clearTimeout(prev._nonReactive.pendingTimeout);
1262
+ prev._nonReactive.pendingTimeout = void 0;
1263
+ if (!loaderIsRunningAsync) prev._nonReactive.loaderPromise = void 0;
1264
+ prev._nonReactive.dehydrated = void 0;
1265
+ return {
1266
+ ...prev,
1267
+ isFetching: loaderIsRunningAsync ? prev.isFetching : false,
1268
+ invalid: false
1269
+ };
1270
+ });
1271
+ return this.getMatch(matchId);
1272
+ };
1273
+ this.loadMatches = async (baseContext) => {
1274
+ const innerLoadContext = baseContext;
1275
+ innerLoadContext.updateMatch ?? (innerLoadContext.updateMatch = this.updateMatch);
1276
+ innerLoadContext.matchPromises = [];
1277
+ if (!this.isServer && this.state.matches.some((d) => d._forcePending)) {
1278
+ this.triggerOnReady(innerLoadContext);
1279
+ }
774
1280
  try {
775
1281
  await new Promise((resolveAll, rejectAll) => {
776
1282
  ;
777
1283
  (async () => {
778
- var _a, _b, _c, _d;
779
1284
  try {
780
- const handleSerialError = (index, err, routerCode) => {
781
- var _a2, _b2;
782
- const { id: matchId, routeId } = matches[index];
783
- const route = this.looseRoutesById[routeId];
784
- if (err instanceof Promise) {
785
- throw err;
786
- }
787
- err.routerCode = routerCode;
788
- firstBadMatchIndex = firstBadMatchIndex ?? index;
789
- handleRedirectAndNotFound(this.getMatch(matchId), err);
790
- try {
791
- (_b2 = (_a2 = route.options).onError) == null ? void 0 : _b2.call(_a2, err);
792
- } catch (errorHandlerErr) {
793
- err = errorHandlerErr;
794
- handleRedirectAndNotFound(this.getMatch(matchId), err);
795
- }
796
- updateMatch(matchId, (prev) => {
797
- var _a3, _b3;
798
- (_a3 = prev._nonReactive.beforeLoadPromise) == null ? void 0 : _a3.resolve();
799
- prev._nonReactive.beforeLoadPromise = void 0;
800
- (_b3 = prev._nonReactive.loadPromise) == null ? void 0 : _b3.resolve();
801
- return {
802
- ...prev,
803
- error: err,
804
- status: "error",
805
- isFetching: false,
806
- updatedAt: Date.now(),
807
- abortController: new AbortController()
808
- };
809
- });
810
- };
811
- for (const [index, { id: matchId, routeId }] of matches.entries()) {
812
- const existingMatch = this.getMatch(matchId);
813
- const parentMatchId = (_a = matches[index - 1]) == null ? void 0 : _a.id;
814
- const parentMatch = parentMatchId ? this.getMatch(parentMatchId) : void 0;
815
- const route = this.looseRoutesById[routeId];
816
- const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
817
- if (this.isServer) {
818
- let ssr;
819
- if (this.isShell()) {
820
- ssr = matchId === rootRouteId;
821
- } else {
822
- const defaultSsr = this.options.defaultSsr ?? true;
823
- if ((parentMatch == null ? void 0 : parentMatch.ssr) === false) {
824
- ssr = false;
825
- } else {
826
- let tempSsr;
827
- if (route.options.ssr === void 0) {
828
- tempSsr = defaultSsr;
829
- } else if (typeof route.options.ssr === "function") {
830
- let makeMaybe = function(value, error) {
831
- if (error) {
832
- return { status: "error", error };
833
- }
834
- return { status: "success", value };
835
- };
836
- const { search, params } = this.getMatch(matchId);
837
- const ssrFnContext = {
838
- search: makeMaybe(search, existingMatch.searchError),
839
- params: makeMaybe(params, existingMatch.paramsError),
840
- location,
841
- matches: matches.map((match) => ({
842
- index: match.index,
843
- pathname: match.pathname,
844
- fullPath: match.fullPath,
845
- staticData: match.staticData,
846
- id: match.id,
847
- routeId: match.routeId,
848
- search: makeMaybe(match.search, match.searchError),
849
- params: makeMaybe(match.params, match.paramsError),
850
- ssr: match.ssr
851
- }))
852
- };
853
- tempSsr = await route.options.ssr(ssrFnContext) ?? defaultSsr;
854
- } else {
855
- tempSsr = route.options.ssr;
856
- }
857
- if (tempSsr === true && (parentMatch == null ? void 0 : parentMatch.ssr) === "data-only") {
858
- ssr = "data-only";
859
- } else {
860
- ssr = tempSsr;
861
- }
862
- }
863
- }
864
- existingMatch.ssr = ssr;
865
- }
866
- if (shouldSkipLoader(matchId)) {
867
- continue;
868
- }
869
- const shouldPending = !!(onReady && !this.isServer && !resolvePreload(matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? ((_b = this.options) == null ? void 0 : _b.defaultPendingComponent)));
870
- let executeBeforeLoad = true;
871
- const setupPendingTimeout = () => {
872
- const match = this.getMatch(matchId);
873
- if (shouldPending && match._nonReactive.pendingTimeout === void 0) {
874
- const pendingTimeout = setTimeout(() => {
875
- try {
876
- triggerOnReady();
877
- } catch {
878
- }
879
- }, pendingMs);
880
- match._nonReactive.pendingTimeout = pendingTimeout;
881
- }
882
- };
883
- if (
884
- // If we are in the middle of a load, either of these will be present
885
- // (not to be confused with `loadPromise`, which is always defined)
886
- existingMatch._nonReactive.beforeLoadPromise || existingMatch._nonReactive.loaderPromise
887
- ) {
888
- setupPendingTimeout();
889
- await existingMatch._nonReactive.beforeLoadPromise;
890
- const match = this.getMatch(matchId);
891
- if (match.status === "error") {
892
- executeBeforeLoad = true;
893
- } else if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
894
- handleRedirectAndNotFound(match, match.error);
895
- }
896
- }
897
- if (executeBeforeLoad) {
898
- try {
899
- const match = this.getMatch(matchId);
900
- match._nonReactive.beforeLoadPromise = createControlledPromise();
901
- const prevLoadPromise = match._nonReactive.loadPromise;
902
- match._nonReactive.loadPromise = createControlledPromise(() => {
903
- prevLoadPromise == null ? void 0 : prevLoadPromise.resolve();
904
- });
905
- const { paramsError, searchError } = this.getMatch(matchId);
906
- if (paramsError) {
907
- handleSerialError(index, paramsError, "PARSE_PARAMS");
908
- }
909
- if (searchError) {
910
- handleSerialError(index, searchError, "VALIDATE_SEARCH");
911
- }
912
- setupPendingTimeout();
913
- const abortController = new AbortController();
914
- const parentMatchContext = (parentMatch == null ? void 0 : parentMatch.context) ?? this.options.context ?? void 0;
915
- updateMatch(matchId, (prev) => ({
916
- ...prev,
917
- isFetching: "beforeLoad",
918
- fetchCount: prev.fetchCount + 1,
919
- abortController,
920
- context: {
921
- ...parentMatchContext,
922
- ...prev.__routeContext
923
- }
924
- }));
925
- const { search, params, context, cause } = this.getMatch(matchId);
926
- const preload = resolvePreload(matchId);
927
- const beforeLoadFnContext = {
928
- search,
929
- abortController,
930
- params,
931
- preload,
932
- context,
933
- location,
934
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
935
- buildLocation: this.buildLocation,
936
- cause: preload ? "preload" : cause,
937
- matches
938
- };
939
- const beforeLoadContext = await ((_d = (_c = route.options).beforeLoad) == null ? void 0 : _d.call(_c, beforeLoadFnContext));
940
- if (isRedirect(beforeLoadContext) || isNotFound(beforeLoadContext)) {
941
- handleSerialError(index, beforeLoadContext, "BEFORE_LOAD");
942
- }
943
- updateMatch(matchId, (prev) => {
944
- return {
945
- ...prev,
946
- __beforeLoadContext: beforeLoadContext,
947
- context: {
948
- ...parentMatchContext,
949
- ...prev.__routeContext,
950
- ...beforeLoadContext
951
- },
952
- abortController
953
- };
954
- });
955
- } catch (err) {
956
- handleSerialError(index, err, "BEFORE_LOAD");
957
- }
958
- updateMatch(matchId, (prev) => {
959
- var _a2;
960
- (_a2 = prev._nonReactive.beforeLoadPromise) == null ? void 0 : _a2.resolve();
961
- prev._nonReactive.beforeLoadPromise = void 0;
962
- return {
963
- ...prev,
964
- isFetching: false
965
- };
966
- });
967
- }
1285
+ for (let i = 0; i < innerLoadContext.matches.length; i++) {
1286
+ const beforeLoad = this.handleBeforeLoad(innerLoadContext, i);
1287
+ if (isPromise(beforeLoad)) await beforeLoad;
968
1288
  }
969
- const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
970
- const matchPromises = [];
971
- validResolvedMatches.forEach(({ id: matchId, routeId }, index) => {
972
- matchPromises.push(
973
- (async () => {
974
- var _a2, _b2;
975
- let loaderShouldRunAsync = false;
976
- let loaderIsRunningAsync = false;
977
- const route = this.looseRoutesById[routeId];
978
- const executeHead = () => {
979
- var _a3, _b3, _c2, _d2, _e, _f;
980
- const match = this.getMatch(matchId);
981
- if (!match) {
982
- return;
983
- }
984
- if (!route.options.head && !route.options.scripts && !route.options.headers) {
985
- return;
986
- }
987
- const assetContext = {
988
- matches,
989
- match,
990
- params: match.params,
991
- loaderData: match.loaderData
992
- };
993
- return Promise.all([
994
- (_b3 = (_a3 = route.options).head) == null ? void 0 : _b3.call(_a3, assetContext),
995
- (_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext),
996
- (_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext)
997
- ]).then(([headFnContent, scripts, headers]) => {
998
- const meta = headFnContent == null ? void 0 : headFnContent.meta;
999
- const links = headFnContent == null ? void 0 : headFnContent.links;
1000
- const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
1001
- const styles = headFnContent == null ? void 0 : headFnContent.styles;
1002
- return {
1003
- meta,
1004
- links,
1005
- headScripts,
1006
- headers,
1007
- scripts,
1008
- styles
1009
- };
1010
- });
1011
- };
1012
- const potentialPendingMinPromise = () => {
1013
- const latestMatch = this.getMatch(matchId);
1014
- return latestMatch._nonReactive.minPendingPromise;
1015
- };
1016
- const prevMatch = this.getMatch(matchId);
1017
- if (shouldSkipLoader(matchId)) {
1018
- if (this.isServer) {
1019
- const headResult = executeHead();
1020
- if (headResult) {
1021
- const head = await headResult;
1022
- updateMatch(matchId, (prev) => ({
1023
- ...prev,
1024
- ...head
1025
- }));
1026
- }
1027
- return this.getMatch(matchId);
1028
- }
1029
- } else if (prevMatch._nonReactive.loaderPromise) {
1030
- if (prevMatch.status === "success" && !sync && !prevMatch.preload) {
1031
- return this.getMatch(matchId);
1032
- }
1033
- await prevMatch._nonReactive.loaderPromise;
1034
- const match = this.getMatch(matchId);
1035
- if (match.error) {
1036
- handleRedirectAndNotFound(match, match.error);
1037
- }
1038
- } else {
1039
- const parentMatchPromise = matchPromises[index - 1];
1040
- const getLoaderContext = () => {
1041
- const {
1042
- params,
1043
- loaderDeps,
1044
- abortController,
1045
- context,
1046
- cause
1047
- } = this.getMatch(matchId);
1048
- const preload2 = resolvePreload(matchId);
1049
- return {
1050
- params,
1051
- deps: loaderDeps,
1052
- preload: !!preload2,
1053
- parentMatchPromise,
1054
- abortController,
1055
- context,
1056
- location,
1057
- navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
1058
- cause: preload2 ? "preload" : cause,
1059
- route
1060
- };
1061
- };
1062
- const age = Date.now() - this.getMatch(matchId).updatedAt;
1063
- const preload = resolvePreload(matchId);
1064
- const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0;
1065
- const shouldReloadOption = route.options.shouldReload;
1066
- const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(getLoaderContext()) : shouldReloadOption;
1067
- updateMatch(matchId, (prev) => {
1068
- prev._nonReactive.loaderPromise = createControlledPromise();
1069
- return {
1070
- ...prev,
1071
- preload: !!preload && !this.state.matches.some((d) => d.id === matchId)
1072
- };
1073
- });
1074
- const runLoader = async () => {
1075
- var _a3, _b3, _c2, _d2;
1076
- try {
1077
- try {
1078
- if (!this.isServer || this.getMatch(matchId).ssr === true) {
1079
- this.loadRouteChunk(route);
1080
- }
1081
- const loaderResult = (_b3 = (_a3 = route.options).loader) == null ? void 0 : _b3.call(_a3, getLoaderContext());
1082
- const loaderResultIsPromise = route.options.loader && isPromise(loaderResult);
1083
- const willLoadSomething = !!(loaderResultIsPromise || route._lazyPromise || route._componentsPromise || route.options.head || route.options.scripts || route.options.headers || this.getMatch(matchId)._nonReactive.minPendingPromise);
1084
- if (willLoadSomething) {
1085
- updateMatch(matchId, (prev) => ({
1086
- ...prev,
1087
- isFetching: "loader"
1088
- }));
1089
- }
1090
- if (route.options.loader) {
1091
- const loaderData = loaderResultIsPromise ? await loaderResult : loaderResult;
1092
- handleRedirectAndNotFound(
1093
- this.getMatch(matchId),
1094
- loaderData
1095
- );
1096
- updateMatch(matchId, (prev) => ({
1097
- ...prev,
1098
- loaderData
1099
- }));
1100
- }
1101
- if (route._lazyPromise) await route._lazyPromise;
1102
- const headResult = executeHead();
1103
- const head = headResult ? await headResult : void 0;
1104
- const pendingPromise = potentialPendingMinPromise();
1105
- if (pendingPromise) await pendingPromise;
1106
- if (route._componentsPromise)
1107
- await route._componentsPromise;
1108
- updateMatch(matchId, (prev) => ({
1109
- ...prev,
1110
- error: void 0,
1111
- status: "success",
1112
- isFetching: false,
1113
- updatedAt: Date.now(),
1114
- ...head
1115
- }));
1116
- } catch (e) {
1117
- let error = e;
1118
- await potentialPendingMinPromise();
1119
- handleRedirectAndNotFound(this.getMatch(matchId), e);
1120
- try {
1121
- (_d2 = (_c2 = route.options).onError) == null ? void 0 : _d2.call(_c2, e);
1122
- } catch (onErrorError) {
1123
- error = onErrorError;
1124
- handleRedirectAndNotFound(
1125
- this.getMatch(matchId),
1126
- onErrorError
1127
- );
1128
- }
1129
- const headResult = executeHead();
1130
- const head = headResult ? await headResult : void 0;
1131
- updateMatch(matchId, (prev) => ({
1132
- ...prev,
1133
- error,
1134
- status: "error",
1135
- isFetching: false,
1136
- ...head
1137
- }));
1138
- }
1139
- } catch (err) {
1140
- const match = this.getMatch(matchId);
1141
- if (match) {
1142
- const headResult = executeHead();
1143
- if (headResult) {
1144
- const head = await headResult;
1145
- updateMatch(matchId, (prev) => ({
1146
- ...prev,
1147
- ...head
1148
- }));
1149
- }
1150
- match._nonReactive.loaderPromise = void 0;
1151
- }
1152
- handleRedirectAndNotFound(match, err);
1153
- }
1154
- };
1155
- const { status, invalid } = this.getMatch(matchId);
1156
- loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
1157
- if (preload && route.options.preload === false) {
1158
- } else if (loaderShouldRunAsync && !sync) {
1159
- loaderIsRunningAsync = true;
1160
- (async () => {
1161
- var _a3, _b3;
1162
- try {
1163
- await runLoader();
1164
- const match = this.getMatch(matchId);
1165
- (_a3 = match._nonReactive.loaderPromise) == null ? void 0 : _a3.resolve();
1166
- (_b3 = match._nonReactive.loadPromise) == null ? void 0 : _b3.resolve();
1167
- match._nonReactive.loaderPromise = void 0;
1168
- } catch (err) {
1169
- if (isRedirect(err)) {
1170
- await this.navigate(err.options);
1171
- }
1172
- }
1173
- })();
1174
- } else if (status !== "success" || loaderShouldRunAsync && sync) {
1175
- await runLoader();
1176
- } else {
1177
- const headResult = executeHead();
1178
- if (headResult) {
1179
- const head = await headResult;
1180
- updateMatch(matchId, (prev) => ({
1181
- ...prev,
1182
- ...head
1183
- }));
1184
- }
1185
- }
1186
- }
1187
- if (!loaderIsRunningAsync) {
1188
- const match = this.getMatch(matchId);
1189
- (_a2 = match._nonReactive.loaderPromise) == null ? void 0 : _a2.resolve();
1190
- (_b2 = match._nonReactive.loadPromise) == null ? void 0 : _b2.resolve();
1191
- }
1192
- updateMatch(matchId, (prev) => {
1193
- clearTimeout(prev._nonReactive.pendingTimeout);
1194
- prev._nonReactive.pendingTimeout = void 0;
1195
- if (!loaderIsRunningAsync)
1196
- prev._nonReactive.loaderPromise = void 0;
1197
- prev._nonReactive.dehydrated = void 0;
1198
- return {
1199
- ...prev,
1200
- isFetching: loaderIsRunningAsync ? prev.isFetching : false,
1201
- invalid: false
1202
- };
1203
- });
1204
- return this.getMatch(matchId);
1205
- })()
1289
+ const max = innerLoadContext.firstBadMatchIndex ?? innerLoadContext.matches.length;
1290
+ for (let i = 0; i < max; i++) {
1291
+ innerLoadContext.matchPromises.push(
1292
+ this.loadRouteMatch(innerLoadContext, i)
1206
1293
  );
1207
- });
1208
- await Promise.all(matchPromises);
1294
+ }
1295
+ await Promise.all(innerLoadContext.matchPromises);
1209
1296
  resolveAll();
1210
1297
  } catch (err) {
1211
1298
  rejectAll(err);
1212
1299
  }
1213
1300
  })();
1214
1301
  });
1215
- await triggerOnReady();
1302
+ const readyPromise = this.triggerOnReady(innerLoadContext);
1303
+ if (isPromise(readyPromise)) await readyPromise;
1216
1304
  } catch (err) {
1217
- if (isRedirect(err) || isNotFound(err)) {
1218
- if (isNotFound(err) && !allPreload) {
1219
- await triggerOnReady();
1220
- }
1305
+ if (isNotFound(err) && !innerLoadContext.preload) {
1306
+ const readyPromise = this.triggerOnReady(innerLoadContext);
1307
+ if (isPromise(readyPromise)) await readyPromise;
1308
+ throw err;
1309
+ }
1310
+ if (isRedirect(err)) {
1221
1311
  throw err;
1222
1312
  }
1223
1313
  }
1224
- return matches;
1314
+ return innerLoadContext.matches;
1225
1315
  };
1226
1316
  this.invalidate = (opts) => {
1227
1317
  const invalidate = (d) => {
@@ -1419,11 +1509,11 @@ class RouterCore {
1419
1509
  }
1420
1510
  return match;
1421
1511
  };
1422
- this._handleNotFound = (matches, err, updateMatch = this.updateMatch) => {
1512
+ this._handleNotFound = (innerLoadContext, err) => {
1423
1513
  var _a;
1424
1514
  const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree;
1425
1515
  const matchesByRouteId = {};
1426
- for (const match of matches) {
1516
+ for (const match of innerLoadContext.matches) {
1427
1517
  matchesByRouteId[match.routeId] = match;
1428
1518
  }
1429
1519
  if (!routeCursor.options.notFoundComponent && ((_a = this.options) == null ? void 0 : _a.defaultNotFoundComponent)) {
@@ -1438,7 +1528,7 @@ class RouterCore {
1438
1528
  matchForRoute,
1439
1529
  "Could not find match for route: " + routeCursor.id
1440
1530
  );
1441
- updateMatch(matchForRoute.id, (prev) => ({
1531
+ innerLoadContext.updateMatch(matchForRoute.id, (prev) => ({
1442
1532
  ...prev,
1443
1533
  status: "notFound",
1444
1534
  error: err,
@@ -1446,7 +1536,7 @@ class RouterCore {
1446
1536
  }));
1447
1537
  if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) {
1448
1538
  err.routeId = routeCursor.parentRoute.id;
1449
- this._handleNotFound(matches, err, updateMatch);
1539
+ this._handleNotFound(innerLoadContext, err);
1450
1540
  }
1451
1541
  };
1452
1542
  this.hasNotFoundMatch = () => {
@@ -1685,6 +1775,12 @@ class SearchParamError extends Error {
1685
1775
  }
1686
1776
  class PathParamError extends Error {
1687
1777
  }
1778
+ function makeMaybe(value, error) {
1779
+ if (error) {
1780
+ return { status: "error", error };
1781
+ }
1782
+ return { status: "success", value };
1783
+ }
1688
1784
  const normalize = (str) => str.endsWith("/") && str.length > 1 ? str.slice(0, -1) : str;
1689
1785
  function comparePaths(a, b) {
1690
1786
  return normalize(a) === normalize(b);