@remix-run/router 1.3.0 → 1.3.1-pre.0
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/CHANGELOG.md +11 -0
- package/dist/router.cjs.js +111 -102
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.js +111 -102
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +111 -102
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/history.ts +4 -8
- package/package.json +1 -1
- package/router.ts +121 -134
- package/utils.ts +14 -3
package/dist/utils.d.ts
CHANGED
|
@@ -383,7 +383,7 @@ export declare class ErrorResponse {
|
|
|
383
383
|
}
|
|
384
384
|
/**
|
|
385
385
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
386
|
-
* Response
|
|
386
|
+
* Response thrown from an action/loader
|
|
387
387
|
*/
|
|
388
|
-
export declare function isRouteErrorResponse(
|
|
388
|
+
export declare function isRouteErrorResponse(error: any): error is ErrorResponse;
|
|
389
389
|
export {};
|
package/history.ts
CHANGED
|
@@ -625,14 +625,10 @@ function getUrlBasedHistory(
|
|
|
625
625
|
} else {
|
|
626
626
|
warning(
|
|
627
627
|
false,
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
`created by @remix-run/router. The block will fail silently in ` +
|
|
633
|
-
`production, but in general you should do all navigation with the ` +
|
|
634
|
-
`router (instead of using window.history.pushState directly) ` +
|
|
635
|
-
`to avoid this situation.`
|
|
628
|
+
`You are trying to perform a POP navigation to a location that was not ` +
|
|
629
|
+
`created by @remix-run/router. This will fail silently in production. ` +
|
|
630
|
+
`You should navigate via the router to avoid this situation (instead of ` +
|
|
631
|
+
`using window.history.pushState/window.location.hash).`
|
|
636
632
|
);
|
|
637
633
|
}
|
|
638
634
|
}
|
package/package.json
CHANGED
package/router.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
SuccessResult,
|
|
22
22
|
AgnosticRouteMatch,
|
|
23
23
|
MutationFormMethod,
|
|
24
|
+
ShouldRevalidateFunction,
|
|
24
25
|
} from "./utils";
|
|
25
26
|
import {
|
|
26
27
|
DeferredData,
|
|
@@ -549,25 +550,22 @@ interface HandleLoadersResult extends ShortCircuitable {
|
|
|
549
550
|
}
|
|
550
551
|
|
|
551
552
|
/**
|
|
552
|
-
*
|
|
553
|
-
*
|
|
553
|
+
* Cached info for active fetcher.load() instances so they can participate
|
|
554
|
+
* in revalidation
|
|
554
555
|
*/
|
|
555
|
-
|
|
556
|
-
string
|
|
557
|
-
string
|
|
558
|
-
AgnosticDataRouteMatch
|
|
559
|
-
AgnosticDataRouteMatch[]
|
|
560
|
-
|
|
556
|
+
interface FetchLoadMatch {
|
|
557
|
+
routeId: string;
|
|
558
|
+
path: string;
|
|
559
|
+
match: AgnosticDataRouteMatch;
|
|
560
|
+
matches: AgnosticDataRouteMatch[];
|
|
561
|
+
}
|
|
561
562
|
|
|
562
563
|
/**
|
|
563
|
-
*
|
|
564
|
-
* fetcher.load()
|
|
564
|
+
* Identified fetcher.load() calls that need to be revalidated
|
|
565
565
|
*/
|
|
566
|
-
|
|
567
|
-
string
|
|
568
|
-
|
|
569
|
-
AgnosticDataRouteMatch[]
|
|
570
|
-
];
|
|
566
|
+
interface RevalidatingFetcher extends FetchLoadMatch {
|
|
567
|
+
key: string;
|
|
568
|
+
}
|
|
571
569
|
|
|
572
570
|
/**
|
|
573
571
|
* Wrapper object to allow us to throw any response out from callLoaderOrAction
|
|
@@ -1121,8 +1119,13 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1121
1119
|
return;
|
|
1122
1120
|
}
|
|
1123
1121
|
|
|
1124
|
-
// Short circuit if it's only a hash change
|
|
1125
|
-
|
|
1122
|
+
// Short circuit if it's only a hash change and not a mutation submission
|
|
1123
|
+
// For example, on /page#hash and submit a <Form method="post"> which will
|
|
1124
|
+
// default to a navigation to /page
|
|
1125
|
+
if (
|
|
1126
|
+
isHashChangeOnly(state.location, location) &&
|
|
1127
|
+
!(opts && opts.submission && isMutationMethod(opts.submission.formMethod))
|
|
1128
|
+
) {
|
|
1126
1129
|
completeNavigation(location, { matches });
|
|
1127
1130
|
return;
|
|
1128
1131
|
}
|
|
@@ -1380,8 +1383,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1380
1383
|
// preserving any new action data or existing action data (in the case of
|
|
1381
1384
|
// a revalidation interrupting an actionReload)
|
|
1382
1385
|
if (!isUninterruptedRevalidation) {
|
|
1383
|
-
revalidatingFetchers.forEach((
|
|
1384
|
-
let fetcher = state.fetchers.get(key);
|
|
1386
|
+
revalidatingFetchers.forEach((rf) => {
|
|
1387
|
+
let fetcher = state.fetchers.get(rf.key);
|
|
1385
1388
|
let revalidatingFetcher: FetcherStates["Loading"] = {
|
|
1386
1389
|
state: "loading",
|
|
1387
1390
|
data: fetcher && fetcher.data,
|
|
@@ -1391,7 +1394,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1391
1394
|
formData: undefined,
|
|
1392
1395
|
" _hasFetcherDoneAnything ": true,
|
|
1393
1396
|
};
|
|
1394
|
-
state.fetchers.set(key, revalidatingFetcher);
|
|
1397
|
+
state.fetchers.set(rf.key, revalidatingFetcher);
|
|
1395
1398
|
});
|
|
1396
1399
|
let actionData = pendingActionData || state.actionData;
|
|
1397
1400
|
updateState({
|
|
@@ -1408,8 +1411,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1408
1411
|
}
|
|
1409
1412
|
|
|
1410
1413
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
1411
|
-
revalidatingFetchers.forEach((
|
|
1412
|
-
fetchControllers.set(key, pendingNavigationController!)
|
|
1414
|
+
revalidatingFetchers.forEach((rf) =>
|
|
1415
|
+
fetchControllers.set(rf.key, pendingNavigationController!)
|
|
1413
1416
|
);
|
|
1414
1417
|
|
|
1415
1418
|
let { results, loaderResults, fetcherResults } =
|
|
@@ -1428,7 +1431,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1428
1431
|
// Clean up _after_ loaders have completed. Don't clean up if we short
|
|
1429
1432
|
// circuited because fetchControllers would have been aborted and
|
|
1430
1433
|
// reassigned to new controllers for the next navigation
|
|
1431
|
-
revalidatingFetchers.forEach((
|
|
1434
|
+
revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
|
|
1432
1435
|
|
|
1433
1436
|
// If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
1434
1437
|
let redirect = findRedirect(results);
|
|
@@ -1507,6 +1510,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1507
1510
|
let { path, submission } = normalizeNavigateOptions(href, opts, true);
|
|
1508
1511
|
let match = getTargetMatch(matches, path);
|
|
1509
1512
|
|
|
1513
|
+
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1514
|
+
|
|
1510
1515
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
1511
1516
|
handleFetcherAction(key, routeId, path, match, matches, submission);
|
|
1512
1517
|
return;
|
|
@@ -1514,7 +1519,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1514
1519
|
|
|
1515
1520
|
// Store off the match so we can call it's shouldRevalidate on subsequent
|
|
1516
1521
|
// revalidations
|
|
1517
|
-
fetchLoadMatches.set(key,
|
|
1522
|
+
fetchLoadMatches.set(key, { routeId, path, match, matches });
|
|
1518
1523
|
handleFetcherLoader(key, routeId, path, match, matches, submission);
|
|
1519
1524
|
}
|
|
1520
1525
|
|
|
@@ -1651,8 +1656,9 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1651
1656
|
// current fetcher which we want to keep in it's current loading state which
|
|
1652
1657
|
// contains it's action submission info + action data
|
|
1653
1658
|
revalidatingFetchers
|
|
1654
|
-
.filter((
|
|
1655
|
-
.forEach((
|
|
1659
|
+
.filter((rf) => rf.key !== key)
|
|
1660
|
+
.forEach((rf) => {
|
|
1661
|
+
let staleKey = rf.key;
|
|
1656
1662
|
let existingFetcher = state.fetchers.get(staleKey);
|
|
1657
1663
|
let revalidatingFetcher: FetcherStates["Loading"] = {
|
|
1658
1664
|
state: "loading",
|
|
@@ -1684,9 +1690,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1684
1690
|
|
|
1685
1691
|
fetchReloadIds.delete(key);
|
|
1686
1692
|
fetchControllers.delete(key);
|
|
1687
|
-
revalidatingFetchers.forEach((
|
|
1688
|
-
fetchControllers.delete(staleKey)
|
|
1689
|
-
);
|
|
1693
|
+
revalidatingFetchers.forEach((r) => fetchControllers.delete(r.key));
|
|
1690
1694
|
|
|
1691
1695
|
let redirect = findRedirect(results);
|
|
1692
1696
|
if (redirect) {
|
|
@@ -1980,12 +1984,12 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1980
1984
|
...matchesToLoad.map((match) =>
|
|
1981
1985
|
callLoaderOrAction("loader", request, match, matches, router.basename)
|
|
1982
1986
|
),
|
|
1983
|
-
...fetchersToLoad.map((
|
|
1987
|
+
...fetchersToLoad.map((f) =>
|
|
1984
1988
|
callLoaderOrAction(
|
|
1985
1989
|
"loader",
|
|
1986
|
-
createClientSideRequest(init.history,
|
|
1987
|
-
match,
|
|
1988
|
-
|
|
1990
|
+
createClientSideRequest(init.history, f.path, request.signal),
|
|
1991
|
+
f.match,
|
|
1992
|
+
f.matches,
|
|
1989
1993
|
router.basename
|
|
1990
1994
|
)
|
|
1991
1995
|
),
|
|
@@ -2004,7 +2008,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2004
2008
|
),
|
|
2005
2009
|
resolveDeferredResults(
|
|
2006
2010
|
currentMatches,
|
|
2007
|
-
fetchersToLoad.map((
|
|
2011
|
+
fetchersToLoad.map((f) => f.match),
|
|
2008
2012
|
fetcherResults,
|
|
2009
2013
|
request.signal,
|
|
2010
2014
|
true
|
|
@@ -2845,25 +2849,14 @@ function normalizeNavigateOptions(
|
|
|
2845
2849
|
|
|
2846
2850
|
// Flatten submission onto URLSearchParams for GET submissions
|
|
2847
2851
|
let parsedPath = parsePath(path);
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
isFetcher &&
|
|
2855
|
-
parsedPath.search &&
|
|
2856
|
-
hasNakedIndexQuery(parsedPath.search)
|
|
2857
|
-
) {
|
|
2858
|
-
searchParams.append("index", "");
|
|
2859
|
-
}
|
|
2860
|
-
parsedPath.search = `?${searchParams}`;
|
|
2861
|
-
} catch (e) {
|
|
2862
|
-
return {
|
|
2863
|
-
path,
|
|
2864
|
-
error: getInternalRouterError(400),
|
|
2865
|
-
};
|
|
2852
|
+
let searchParams = convertFormDataToSearchParams(opts.formData);
|
|
2853
|
+
// Since fetcher GET submissions only run a single loader (as opposed to
|
|
2854
|
+
// navigation GET submissions which run all loaders), we need to preserve
|
|
2855
|
+
// any incoming ?index params
|
|
2856
|
+
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
2857
|
+
searchParams.append("index", "");
|
|
2866
2858
|
}
|
|
2859
|
+
parsedPath.search = `?${searchParams}`;
|
|
2867
2860
|
|
|
2868
2861
|
return { path: createPath(parsedPath), submission };
|
|
2869
2862
|
}
|
|
@@ -2903,47 +2896,81 @@ function getMatchesToLoad(
|
|
|
2903
2896
|
? Object.values(pendingActionData)[0]
|
|
2904
2897
|
: undefined;
|
|
2905
2898
|
|
|
2899
|
+
let currentUrl = history.createURL(state.location);
|
|
2900
|
+
let nextUrl = history.createURL(location);
|
|
2901
|
+
|
|
2902
|
+
let defaultShouldRevalidate =
|
|
2903
|
+
// Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
2904
|
+
isRevalidationRequired ||
|
|
2905
|
+
// Clicked the same link, resubmitted a GET form
|
|
2906
|
+
currentUrl.toString() === nextUrl.toString() ||
|
|
2907
|
+
// Search params affect all loaders
|
|
2908
|
+
currentUrl.search !== nextUrl.search;
|
|
2909
|
+
|
|
2906
2910
|
// Pick navigation matches that are net-new or qualify for revalidation
|
|
2907
2911
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
2908
2912
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2913
|
+
|
|
2914
|
+
let navigationMatches = boundaryMatches.filter((match, index) => {
|
|
2915
|
+
if (match.route.loader == null) {
|
|
2916
|
+
return false;
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
// Always call the loader on new route instances and pending defer cancellations
|
|
2920
|
+
if (
|
|
2921
|
+
isNewLoader(state.loaderData, state.matches[index], match) ||
|
|
2922
|
+
cancelledDeferredRoutes.some((id) => id === match.route.id)
|
|
2923
|
+
) {
|
|
2924
|
+
return true;
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// This is the default implementation for when we revalidate. If the route
|
|
2928
|
+
// provides it's own implementation, then we give them full control but
|
|
2929
|
+
// provide this value so they can leverage it if needed after they check
|
|
2930
|
+
// their own specific use cases
|
|
2931
|
+
let currentRouteMatch = state.matches[index];
|
|
2932
|
+
let nextRouteMatch = match;
|
|
2933
|
+
|
|
2934
|
+
return shouldRevalidateLoader(match, {
|
|
2935
|
+
currentUrl,
|
|
2936
|
+
currentParams: currentRouteMatch.params,
|
|
2937
|
+
nextUrl,
|
|
2938
|
+
nextParams: nextRouteMatch.params,
|
|
2939
|
+
...submission,
|
|
2940
|
+
actionResult,
|
|
2941
|
+
defaultShouldRevalidate:
|
|
2942
|
+
defaultShouldRevalidate ||
|
|
2943
|
+
isNewRouteInstance(currentRouteMatch, nextRouteMatch),
|
|
2944
|
+
});
|
|
2945
|
+
});
|
|
2926
2946
|
|
|
2927
2947
|
// Pick fetcher.loads that need to be revalidated
|
|
2928
2948
|
let revalidatingFetchers: RevalidatingFetcher[] = [];
|
|
2929
2949
|
fetchLoadMatches &&
|
|
2930
|
-
fetchLoadMatches.forEach((
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2950
|
+
fetchLoadMatches.forEach((f, key) => {
|
|
2951
|
+
if (!matches.some((m) => m.route.id === f.routeId)) {
|
|
2952
|
+
// This fetcher is not going to be present in the subsequent render so
|
|
2953
|
+
// there's no need to revalidate it
|
|
2954
|
+
return;
|
|
2955
|
+
} else if (cancelledFetcherLoads.includes(key)) {
|
|
2956
|
+
// This fetcher was cancelled from a prior action submission - force reload
|
|
2957
|
+
revalidatingFetchers.push({ key, ...f });
|
|
2958
|
+
} else {
|
|
2959
|
+
// Revalidating fetchers are decoupled from the route matches since they
|
|
2960
|
+
// hit a static href, so they _always_ check shouldRevalidate and the
|
|
2961
|
+
// default is strictly if a revalidation is explicitly required (action
|
|
2962
|
+
// submissions, useRevalidator, X-Remix-Revalidate).
|
|
2963
|
+
let shouldRevalidate = shouldRevalidateLoader(f.match, {
|
|
2964
|
+
currentUrl,
|
|
2965
|
+
currentParams: state.matches[state.matches.length - 1].params,
|
|
2966
|
+
nextUrl,
|
|
2967
|
+
nextParams: matches[matches.length - 1].params,
|
|
2968
|
+
...submission,
|
|
2969
|
+
actionResult,
|
|
2970
|
+
defaultShouldRevalidate,
|
|
2971
|
+
});
|
|
2945
2972
|
if (shouldRevalidate) {
|
|
2946
|
-
revalidatingFetchers.push(
|
|
2973
|
+
revalidatingFetchers.push({ key, ...f });
|
|
2947
2974
|
}
|
|
2948
2975
|
}
|
|
2949
2976
|
});
|
|
@@ -2980,58 +3007,24 @@ function isNewRouteInstance(
|
|
|
2980
3007
|
currentMatch.pathname !== match.pathname ||
|
|
2981
3008
|
// splat param changed, which is not present in match.path
|
|
2982
3009
|
// e.g. /files/images/avatar.jpg -> files/finances.xls
|
|
2983
|
-
(currentPath &&
|
|
3010
|
+
(currentPath != null &&
|
|
2984
3011
|
currentPath.endsWith("*") &&
|
|
2985
3012
|
currentMatch.params["*"] !== match.params["*"])
|
|
2986
3013
|
);
|
|
2987
3014
|
}
|
|
2988
3015
|
|
|
2989
3016
|
function shouldRevalidateLoader(
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
currentMatch: AgnosticDataRouteMatch,
|
|
2993
|
-
submission: Submission | undefined,
|
|
2994
|
-
location: string | Location,
|
|
2995
|
-
match: AgnosticDataRouteMatch,
|
|
2996
|
-
isRevalidationRequired: boolean,
|
|
2997
|
-
actionResult: DataResult | undefined
|
|
3017
|
+
loaderMatch: AgnosticDataRouteMatch,
|
|
3018
|
+
arg: Parameters<ShouldRevalidateFunction>[0]
|
|
2998
3019
|
) {
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
let nextUrl = history.createURL(location);
|
|
3002
|
-
let nextParams = match.params;
|
|
3003
|
-
|
|
3004
|
-
// This is the default implementation as to when we revalidate. If the route
|
|
3005
|
-
// provides it's own implementation, then we give them full control but
|
|
3006
|
-
// provide this value so they can leverage it if needed after they check
|
|
3007
|
-
// their own specific use cases
|
|
3008
|
-
// Note that fetchers always provide the same current/next locations so the
|
|
3009
|
-
// URL-based checks here don't apply to fetcher shouldRevalidate calls
|
|
3010
|
-
let defaultShouldRevalidate =
|
|
3011
|
-
isNewRouteInstance(currentMatch, match) ||
|
|
3012
|
-
// Clicked the same link, resubmitted a GET form
|
|
3013
|
-
currentUrl.toString() === nextUrl.toString() ||
|
|
3014
|
-
// Search params affect all loaders
|
|
3015
|
-
currentUrl.search !== nextUrl.search ||
|
|
3016
|
-
// Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3017
|
-
isRevalidationRequired;
|
|
3018
|
-
|
|
3019
|
-
if (match.route.shouldRevalidate) {
|
|
3020
|
-
let routeChoice = match.route.shouldRevalidate({
|
|
3021
|
-
currentUrl,
|
|
3022
|
-
currentParams,
|
|
3023
|
-
nextUrl,
|
|
3024
|
-
nextParams,
|
|
3025
|
-
...submission,
|
|
3026
|
-
actionResult,
|
|
3027
|
-
defaultShouldRevalidate,
|
|
3028
|
-
});
|
|
3020
|
+
if (loaderMatch.route.shouldRevalidate) {
|
|
3021
|
+
let routeChoice = loaderMatch.route.shouldRevalidate(arg);
|
|
3029
3022
|
if (typeof routeChoice === "boolean") {
|
|
3030
3023
|
return routeChoice;
|
|
3031
3024
|
}
|
|
3032
3025
|
}
|
|
3033
3026
|
|
|
3034
|
-
return defaultShouldRevalidate;
|
|
3027
|
+
return arg.defaultShouldRevalidate;
|
|
3035
3028
|
}
|
|
3036
3029
|
|
|
3037
3030
|
async function callLoaderOrAction(
|
|
@@ -3222,12 +3215,8 @@ function convertFormDataToSearchParams(formData: FormData): URLSearchParams {
|
|
|
3222
3215
|
let searchParams = new URLSearchParams();
|
|
3223
3216
|
|
|
3224
3217
|
for (let [key, value] of formData.entries()) {
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
'File inputs are not supported with encType "application/x-www-form-urlencoded", ' +
|
|
3228
|
-
'please use "multipart/form-data" instead.'
|
|
3229
|
-
);
|
|
3230
|
-
searchParams.append(key, value);
|
|
3218
|
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
|
|
3219
|
+
searchParams.append(key, value instanceof File ? value.name : value);
|
|
3231
3220
|
}
|
|
3232
3221
|
|
|
3233
3222
|
return searchParams;
|
|
@@ -3355,7 +3344,7 @@ function processLoaderData(
|
|
|
3355
3344
|
|
|
3356
3345
|
// Process results from our revalidating fetchers
|
|
3357
3346
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
3358
|
-
let
|
|
3347
|
+
let { key, match } = revalidatingFetchers[index];
|
|
3359
3348
|
invariant(
|
|
3360
3349
|
fetcherResults !== undefined && fetcherResults[index] !== undefined,
|
|
3361
3350
|
"Did not find corresponding fetcher result"
|
|
@@ -3490,8 +3479,6 @@ function getInternalRouterError(
|
|
|
3490
3479
|
`so there is no way to handle the request.`;
|
|
3491
3480
|
} else if (type === "defer-action") {
|
|
3492
3481
|
errorMessage = "defer() is not supported in actions";
|
|
3493
|
-
} else {
|
|
3494
|
-
errorMessage = "Cannot submit binary form data using GET";
|
|
3495
3482
|
}
|
|
3496
3483
|
} else if (status === 403) {
|
|
3497
3484
|
statusText = "Forbidden";
|
package/utils.ts
CHANGED
|
@@ -1192,6 +1192,11 @@ export class DeferredData {
|
|
|
1192
1192
|
{}
|
|
1193
1193
|
);
|
|
1194
1194
|
|
|
1195
|
+
if (this.done) {
|
|
1196
|
+
// All incoming values were resolved
|
|
1197
|
+
this.unlistenAbortSignal();
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1195
1200
|
this.init = responseInit;
|
|
1196
1201
|
}
|
|
1197
1202
|
|
|
@@ -1395,8 +1400,14 @@ export class ErrorResponse {
|
|
|
1395
1400
|
|
|
1396
1401
|
/**
|
|
1397
1402
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
1398
|
-
* Response
|
|
1403
|
+
* Response thrown from an action/loader
|
|
1399
1404
|
*/
|
|
1400
|
-
export function isRouteErrorResponse(
|
|
1401
|
-
return
|
|
1405
|
+
export function isRouteErrorResponse(error: any): error is ErrorResponse {
|
|
1406
|
+
return (
|
|
1407
|
+
error != null &&
|
|
1408
|
+
typeof error.status === "number" &&
|
|
1409
|
+
typeof error.statusText === "string" &&
|
|
1410
|
+
typeof error.internal === "boolean" &&
|
|
1411
|
+
"data" in error
|
|
1412
|
+
);
|
|
1402
1413
|
}
|