@remix-run/router 0.0.0-experimental-2272fa73 → 0.0.0-experimental-cbcd94b7
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/index.d.ts +1 -1
- package/dist/router.cjs.js +149 -89
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +1 -0
- package/dist/router.js +146 -90
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +149 -89
- 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 +24 -4
- package/index.ts +1 -0
- package/package.json +1 -1
- package/router.ts +178 -106
- package/utils.ts +47 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyMatch, ErrorResponse, FormEncType, FormMethod, HTMLFormMethod, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathParam, PathPattern, RedirectFunction, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, TrackedPromise, UIMatch, V7_FormMethod, } from "./utils";
|
|
2
|
-
export { AbortedDeferredError, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, redirectDocument, resolvePath, resolveTo, stripBasename, } from "./utils";
|
|
2
|
+
export { AbortedDeferredError, DecodedResponse, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, redirectDocument, resolvePath, resolveTo, stripBasename, } from "./utils";
|
|
3
3
|
export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
|
|
4
4
|
export { Action, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, parsePath, } from "./history";
|
|
5
5
|
export * from "./router";
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v0.0.0-experimental-
|
|
2
|
+
* @remix-run/router v0.0.0-experimental-cbcd94b7
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1519,6 +1519,22 @@ class ErrorResponseImpl {
|
|
|
1519
1519
|
}
|
|
1520
1520
|
}
|
|
1521
1521
|
|
|
1522
|
+
/**
|
|
1523
|
+
* Utility class we use to hold unwrapped Responses while preserving status
|
|
1524
|
+
* codes and headers. This is most useful for dataStrategy implementations
|
|
1525
|
+
* where implementors want to use a custom decoding mechanism and return
|
|
1526
|
+
* pre-decoded data while also preserving response meta information
|
|
1527
|
+
*/
|
|
1528
|
+
class DecodedResponse {
|
|
1529
|
+
constructor(status, statusText, headers, data) {
|
|
1530
|
+
this._isDecodedResponse = true;
|
|
1531
|
+
this.status = status;
|
|
1532
|
+
this.statusText = statusText;
|
|
1533
|
+
this.headers = headers;
|
|
1534
|
+
this.data = data;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1522
1538
|
/**
|
|
1523
1539
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
1524
1540
|
* Response thrown from an action/loader
|
|
@@ -1527,6 +1543,13 @@ function isRouteErrorResponse(error) {
|
|
|
1527
1543
|
return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
|
|
1528
1544
|
}
|
|
1529
1545
|
|
|
1546
|
+
/**
|
|
1547
|
+
* Check if the given error is an DecodedResponse
|
|
1548
|
+
*/
|
|
1549
|
+
function isDecodedResponse(value) {
|
|
1550
|
+
return value != null && value._isDecodedResponse === true && typeof value.status === "number" && typeof value.statusText === "string" && value.headers != null && "data" in value;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1530
1553
|
////////////////////////////////////////////////////////////////////////////////
|
|
1531
1554
|
//#region Types and Constants
|
|
1532
1555
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1675,7 +1698,8 @@ function createRouter(init) {
|
|
|
1675
1698
|
v7_normalizeFormMethod: false,
|
|
1676
1699
|
v7_partialHydration: false,
|
|
1677
1700
|
v7_prependBasename: false,
|
|
1678
|
-
v7_relativeSplatPath: false
|
|
1701
|
+
v7_relativeSplatPath: false,
|
|
1702
|
+
v7_skipActionErrorRevalidation: true
|
|
1679
1703
|
}, init.future);
|
|
1680
1704
|
// Cleanup function for history
|
|
1681
1705
|
let unlistenHistory = null;
|
|
@@ -2257,34 +2281,31 @@ function createRouter(init) {
|
|
|
2257
2281
|
// Create a controller/Request for this navigation
|
|
2258
2282
|
pendingNavigationController = new AbortController();
|
|
2259
2283
|
let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
|
|
2260
|
-
let
|
|
2261
|
-
let pendingError;
|
|
2284
|
+
let pendingActionResult;
|
|
2262
2285
|
if (opts && opts.pendingError) {
|
|
2263
2286
|
// If we have a pendingError, it means the user attempted a GET submission
|
|
2264
2287
|
// with binary FormData so assign here and skip to handleLoaders. That
|
|
2265
2288
|
// way we handle calling loaders above the boundary etc. It's not really
|
|
2266
2289
|
// different from an actionError in that sense.
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2290
|
+
pendingActionResult = [findNearestBoundary(matches).route.id, {
|
|
2291
|
+
type: ResultType.error,
|
|
2292
|
+
error: opts.pendingError
|
|
2293
|
+
}];
|
|
2270
2294
|
} else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
|
|
2271
2295
|
// Call action if we received an action submission
|
|
2272
|
-
let
|
|
2296
|
+
let actionResult = await handleAction(request, location, opts.submission, matches, {
|
|
2273
2297
|
replace: opts.replace,
|
|
2274
2298
|
flushSync
|
|
2275
2299
|
});
|
|
2276
|
-
if (
|
|
2300
|
+
if (actionResult.shortCircuited) {
|
|
2277
2301
|
return;
|
|
2278
2302
|
}
|
|
2279
|
-
|
|
2280
|
-
pendingError = actionOutput.pendingActionError;
|
|
2303
|
+
pendingActionResult = actionResult.pendingActionResult;
|
|
2281
2304
|
loadingNavigation = getLoadingNavigation(location, opts.submission);
|
|
2282
2305
|
flushSync = false;
|
|
2283
2306
|
|
|
2284
2307
|
// Create a GET request for the loaders
|
|
2285
|
-
request =
|
|
2286
|
-
signal: request.signal
|
|
2287
|
-
});
|
|
2308
|
+
request = createClientSideRequest(init.history, request.url, request.signal);
|
|
2288
2309
|
}
|
|
2289
2310
|
|
|
2290
2311
|
// Call loaders
|
|
@@ -2292,7 +2313,7 @@ function createRouter(init) {
|
|
|
2292
2313
|
shortCircuited,
|
|
2293
2314
|
loaderData,
|
|
2294
2315
|
errors
|
|
2295
|
-
} = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync,
|
|
2316
|
+
} = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionResult);
|
|
2296
2317
|
if (shortCircuited) {
|
|
2297
2318
|
return;
|
|
2298
2319
|
}
|
|
@@ -2303,9 +2324,7 @@ function createRouter(init) {
|
|
|
2303
2324
|
pendingNavigationController = null;
|
|
2304
2325
|
completeNavigation(location, _extends({
|
|
2305
2326
|
matches
|
|
2306
|
-
},
|
|
2307
|
-
actionData: pendingActionData
|
|
2308
|
-
} : {}, {
|
|
2327
|
+
}, getActionDataForCommit(pendingActionResult), {
|
|
2309
2328
|
loaderData,
|
|
2310
2329
|
errors
|
|
2311
2330
|
}));
|
|
@@ -2366,6 +2385,11 @@ function createRouter(init) {
|
|
|
2366
2385
|
shortCircuited: true
|
|
2367
2386
|
};
|
|
2368
2387
|
}
|
|
2388
|
+
if (isDeferredResult(result)) {
|
|
2389
|
+
throw getInternalRouterError(400, {
|
|
2390
|
+
type: "defer-action"
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2369
2393
|
if (isErrorResult(result)) {
|
|
2370
2394
|
// Store off the pending error - we use it to determine which loaders
|
|
2371
2395
|
// to call and will commit it when we complete the navigation
|
|
@@ -2379,28 +2403,17 @@ function createRouter(init) {
|
|
|
2379
2403
|
pendingAction = Action.Push;
|
|
2380
2404
|
}
|
|
2381
2405
|
return {
|
|
2382
|
-
|
|
2383
|
-
pendingActionData: {},
|
|
2384
|
-
pendingActionError: {
|
|
2385
|
-
[boundaryMatch.route.id]: result.error
|
|
2386
|
-
}
|
|
2406
|
+
pendingActionResult: [boundaryMatch.route.id, result]
|
|
2387
2407
|
};
|
|
2388
2408
|
}
|
|
2389
|
-
if (isDeferredResult(result)) {
|
|
2390
|
-
throw getInternalRouterError(400, {
|
|
2391
|
-
type: "defer-action"
|
|
2392
|
-
});
|
|
2393
|
-
}
|
|
2394
2409
|
return {
|
|
2395
|
-
|
|
2396
|
-
[actionMatch.route.id]: result.data
|
|
2397
|
-
}
|
|
2410
|
+
pendingActionResult: [actionMatch.route.id, result]
|
|
2398
2411
|
};
|
|
2399
2412
|
}
|
|
2400
2413
|
|
|
2401
2414
|
// Call all applicable loaders for the given matches, handling redirects,
|
|
2402
2415
|
// errors, etc.
|
|
2403
|
-
async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync,
|
|
2416
|
+
async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult) {
|
|
2404
2417
|
// Figure out the right navigation we want to use for data loading
|
|
2405
2418
|
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
|
|
2406
2419
|
|
|
@@ -2408,7 +2421,7 @@ function createRouter(init) {
|
|
|
2408
2421
|
// we have it on the loading navigation so use that if available
|
|
2409
2422
|
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
|
|
2410
2423
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2411
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, future.v7_partialHydration && initialHydration === true, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename,
|
|
2424
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, future.v7_partialHydration && initialHydration === true, future.v7_skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult);
|
|
2412
2425
|
|
|
2413
2426
|
// Cancel pending deferreds for no-longer-matched routes or routes we're
|
|
2414
2427
|
// about to reload. Note that if this is an action reload we would have
|
|
@@ -2423,10 +2436,10 @@ function createRouter(init) {
|
|
|
2423
2436
|
matches,
|
|
2424
2437
|
loaderData: {},
|
|
2425
2438
|
// Commit pending error if we're short circuiting
|
|
2426
|
-
errors:
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
}
|
|
2439
|
+
errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? {
|
|
2440
|
+
[pendingActionResult[0]]: pendingActionResult[1].error
|
|
2441
|
+
} : null
|
|
2442
|
+
}, getActionDataForCommit(pendingActionResult), updatedFetchers ? {
|
|
2430
2443
|
fetchers: new Map(state.fetchers)
|
|
2431
2444
|
} : {}), {
|
|
2432
2445
|
flushSync
|
|
@@ -2448,12 +2461,24 @@ function createRouter(init) {
|
|
|
2448
2461
|
let revalidatingFetcher = getLoadingFetcher(undefined, fetcher ? fetcher.data : undefined);
|
|
2449
2462
|
state.fetchers.set(rf.key, revalidatingFetcher);
|
|
2450
2463
|
});
|
|
2451
|
-
let actionData
|
|
2464
|
+
let actionData;
|
|
2465
|
+
if (pendingActionResult && !isErrorResult(pendingActionResult[1])) {
|
|
2466
|
+
// This is cast to `any` currently because `RouteData`uses any and it
|
|
2467
|
+
// would be a breaking change to use any.
|
|
2468
|
+
// TODO: v7 - change `RouteData` to use `unknown` instead of `any`
|
|
2469
|
+
actionData = {
|
|
2470
|
+
[pendingActionResult[0]]: pendingActionResult[1].data
|
|
2471
|
+
};
|
|
2472
|
+
} else if (state.actionData) {
|
|
2473
|
+
if (Object.keys(state.actionData).length === 0) {
|
|
2474
|
+
actionData = null;
|
|
2475
|
+
} else {
|
|
2476
|
+
actionData = state.actionData;
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2452
2479
|
updateState(_extends({
|
|
2453
2480
|
navigation: loadingNavigation
|
|
2454
|
-
}, actionData
|
|
2455
|
-
actionData: null
|
|
2456
|
-
} : {
|
|
2481
|
+
}, actionData !== undefined ? {
|
|
2457
2482
|
actionData
|
|
2458
2483
|
} : {}, revalidatingFetchers.length > 0 ? {
|
|
2459
2484
|
fetchers: new Map(state.fetchers)
|
|
@@ -2518,7 +2543,7 @@ function createRouter(init) {
|
|
|
2518
2543
|
let {
|
|
2519
2544
|
loaderData,
|
|
2520
2545
|
errors
|
|
2521
|
-
} = processLoaderData(state, matches, matchesToLoad, loaderResults,
|
|
2546
|
+
} = processLoaderData(state, matches, matchesToLoad, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds);
|
|
2522
2547
|
|
|
2523
2548
|
// Wire up subscribers to update loaderData as promises settle
|
|
2524
2549
|
activeDeferreds.forEach((deferredData, routeId) => {
|
|
@@ -2677,10 +2702,7 @@ function createRouter(init) {
|
|
|
2677
2702
|
fetchReloadIds.set(key, loadId);
|
|
2678
2703
|
let loadFetcher = getLoadingFetcher(submission, actionResult.data);
|
|
2679
2704
|
state.fetchers.set(key, loadFetcher);
|
|
2680
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, false, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename,
|
|
2681
|
-
[match.route.id]: actionResult.data
|
|
2682
|
-
}, undefined // No need to send through errors since we short circuit above
|
|
2683
|
-
);
|
|
2705
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, false, future.v7_skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, [match.route.id, actionResult]);
|
|
2684
2706
|
|
|
2685
2707
|
// Put all revalidating fetchers into the loading state, except for the
|
|
2686
2708
|
// current fetcher which we want to keep in it's current loading state which
|
|
@@ -3597,16 +3619,14 @@ function createStaticHandler(routes, opts) {
|
|
|
3597
3619
|
// Store off the pending error - we use it to determine which loaders
|
|
3598
3620
|
// to call and will commit it when we complete the navigation
|
|
3599
3621
|
let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
|
|
3600
|
-
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, null,
|
|
3601
|
-
[boundaryMatch.route.id]: result.error
|
|
3602
|
-
});
|
|
3622
|
+
let context = await loadRouteData(loaderRequest, matches, requestContext, loadRouteIds, null, [boundaryMatch.route.id, result]);
|
|
3603
3623
|
|
|
3604
3624
|
// action status codes take precedence over loader status codes
|
|
3605
3625
|
return _extends({}, context, {
|
|
3606
3626
|
statusCode: isRouteErrorResponse(result.error) ? result.error.status : 500,
|
|
3607
3627
|
actionData: null,
|
|
3608
|
-
actionHeaders: _extends({}, result.
|
|
3609
|
-
[actionMatch.route.id]: result.
|
|
3628
|
+
actionHeaders: _extends({}, result.headers ? {
|
|
3629
|
+
[actionMatch.route.id]: result.headers
|
|
3610
3630
|
} : {})
|
|
3611
3631
|
});
|
|
3612
3632
|
}
|
|
@@ -3615,16 +3635,15 @@ function createStaticHandler(routes, opts) {
|
|
|
3615
3635
|
actionData: {
|
|
3616
3636
|
[actionMatch.route.id]: result.data
|
|
3617
3637
|
}
|
|
3618
|
-
}, result.
|
|
3619
|
-
statusCode: result.
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
actionHeaders: {}
|
|
3638
|
+
}, result.statusCode ? {
|
|
3639
|
+
statusCode: result.statusCode
|
|
3640
|
+
} : {}, {
|
|
3641
|
+
actionHeaders: result.headers ? {
|
|
3642
|
+
[actionMatch.route.id]: result.headers
|
|
3643
|
+
} : {}
|
|
3625
3644
|
});
|
|
3626
3645
|
}
|
|
3627
|
-
async function loadRouteData(request, matches, requestContext, loadRouteIds, routeMatch,
|
|
3646
|
+
async function loadRouteData(request, matches, requestContext, loadRouteIds, routeMatch, pendingActionResult) {
|
|
3628
3647
|
let isRouteRequest = routeMatch != null;
|
|
3629
3648
|
|
|
3630
3649
|
// Short circuit if we have no loaders to run (queryRoute())
|
|
@@ -3635,7 +3654,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3635
3654
|
routeId: routeMatch == null ? void 0 : routeMatch.route.id
|
|
3636
3655
|
});
|
|
3637
3656
|
}
|
|
3638
|
-
let requestMatches = routeMatch ? [routeMatch] : getLoaderMatchesUntilBoundary(matches,
|
|
3657
|
+
let requestMatches = routeMatch ? [routeMatch] : pendingActionResult && isErrorResult(pendingActionResult[1]) ? getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]) : matches;
|
|
3639
3658
|
let matchesToLoad = requestMatches.filter(m => m.route.loader || m.route.lazy);
|
|
3640
3659
|
if (loadRouteIds) {
|
|
3641
3660
|
matchesToLoad = matchesToLoad.filter(m => loadRouteIds.includes(m.route.id));
|
|
@@ -3649,7 +3668,9 @@ function createStaticHandler(routes, opts) {
|
|
|
3649
3668
|
loaderData: matches.reduce((acc, m) => Object.assign(acc, {
|
|
3650
3669
|
[m.route.id]: null
|
|
3651
3670
|
}), {}),
|
|
3652
|
-
errors:
|
|
3671
|
+
errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? {
|
|
3672
|
+
[pendingActionResult[0]]: pendingActionResult[1].error
|
|
3673
|
+
} : null,
|
|
3653
3674
|
statusCode: 200,
|
|
3654
3675
|
loaderHeaders: {},
|
|
3655
3676
|
activeDeferreds: null
|
|
@@ -3662,7 +3683,7 @@ function createStaticHandler(routes, opts) {
|
|
|
3662
3683
|
|
|
3663
3684
|
// Process and commit output from loaders
|
|
3664
3685
|
let activeDeferreds = new Map();
|
|
3665
|
-
let context = processRouteLoaderData(matches, matchesToLoad, results,
|
|
3686
|
+
let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds);
|
|
3666
3687
|
|
|
3667
3688
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
3668
3689
|
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
@@ -3915,14 +3936,19 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3915
3936
|
}
|
|
3916
3937
|
return boundaryMatches;
|
|
3917
3938
|
}
|
|
3918
|
-
function getMatchesToLoad(history, state, matches, submission, location, isInitialLoad, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename,
|
|
3919
|
-
let actionResult =
|
|
3939
|
+
function getMatchesToLoad(history, state, matches, submission, location, isInitialLoad, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {
|
|
3940
|
+
let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined;
|
|
3920
3941
|
let currentUrl = history.createURL(state.location);
|
|
3921
3942
|
let nextUrl = history.createURL(location);
|
|
3922
3943
|
|
|
3923
3944
|
// Pick navigation matches that are net-new or qualify for revalidation
|
|
3924
|
-
let boundaryId =
|
|
3925
|
-
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
3945
|
+
let boundaryId = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[0] : undefined;
|
|
3946
|
+
let boundaryMatches = boundaryId ? getLoaderMatchesUntilBoundary(matches, boundaryId) : matches;
|
|
3947
|
+
|
|
3948
|
+
// Don't revalidate loaders by default after action 4xx/5xx responses
|
|
3949
|
+
// when the flag is enabled. They can still opt-into revalidation via
|
|
3950
|
+
// `shouldRevalidate` via `actionResult`
|
|
3951
|
+
let shouldSkipRevalidation = skipActionErrorRevalidation && pendingActionResult && typeof pendingActionResult[1].statusCode === "number" && pendingActionResult[1].statusCode >= 400;
|
|
3926
3952
|
let navigationMatches = boundaryMatches.filter((match, index) => {
|
|
3927
3953
|
let {
|
|
3928
3954
|
route
|
|
@@ -3961,11 +3987,9 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
3961
3987
|
nextParams: nextRouteMatch.params
|
|
3962
3988
|
}, submission, {
|
|
3963
3989
|
actionResult,
|
|
3964
|
-
defaultShouldRevalidate:
|
|
3990
|
+
defaultShouldRevalidate: shouldSkipRevalidation ? false :
|
|
3965
3991
|
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3966
|
-
isRevalidationRequired ||
|
|
3967
|
-
// Clicked the same link, resubmitted a GET form
|
|
3968
|
-
currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search ||
|
|
3992
|
+
isRevalidationRequired || currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search ||
|
|
3969
3993
|
// Search params affect all loaders
|
|
3970
3994
|
currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3971
3995
|
}));
|
|
@@ -4027,7 +4051,7 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
4027
4051
|
nextParams: matches[matches.length - 1].params
|
|
4028
4052
|
}, submission, {
|
|
4029
4053
|
actionResult,
|
|
4030
|
-
defaultShouldRevalidate: isRevalidationRequired
|
|
4054
|
+
defaultShouldRevalidate: shouldSkipRevalidation ? false : isRevalidationRequired
|
|
4031
4055
|
}));
|
|
4032
4056
|
}
|
|
4033
4057
|
if (shouldRevalidate) {
|
|
@@ -4302,19 +4326,38 @@ async function convertHandlerResultToDataResult(handlerResult) {
|
|
|
4302
4326
|
return {
|
|
4303
4327
|
type,
|
|
4304
4328
|
error: new ErrorResponseImpl(result.status, result.statusText, data),
|
|
4305
|
-
|
|
4329
|
+
statusCode: result.status,
|
|
4330
|
+
headers: result.headers
|
|
4306
4331
|
};
|
|
4307
4332
|
}
|
|
4308
4333
|
return {
|
|
4309
4334
|
type: ResultType.data,
|
|
4310
4335
|
data,
|
|
4311
|
-
|
|
4336
|
+
statusCode: result.status,
|
|
4337
|
+
headers: result.headers
|
|
4338
|
+
};
|
|
4339
|
+
}
|
|
4340
|
+
if (isDecodedResponse(result)) {
|
|
4341
|
+
if (type === ResultType.error) {
|
|
4342
|
+
return {
|
|
4343
|
+
type,
|
|
4344
|
+
error: new ErrorResponseImpl(result.status, result.statusText, result.data),
|
|
4345
|
+
statusCode: result.status,
|
|
4346
|
+
headers: result.headers
|
|
4347
|
+
};
|
|
4348
|
+
}
|
|
4349
|
+
return {
|
|
4350
|
+
type: ResultType.data,
|
|
4351
|
+
data: result.data,
|
|
4352
|
+
statusCode: result.status,
|
|
4353
|
+
headers: result.headers
|
|
4312
4354
|
};
|
|
4313
4355
|
}
|
|
4314
4356
|
if (type === ResultType.error) {
|
|
4315
4357
|
return {
|
|
4316
4358
|
type,
|
|
4317
|
-
error: result
|
|
4359
|
+
error: result,
|
|
4360
|
+
statusCode: isRouteErrorResponse(result) ? result.status : undefined
|
|
4318
4361
|
};
|
|
4319
4362
|
}
|
|
4320
4363
|
if (isDeferredData(result)) {
|
|
@@ -4394,13 +4437,14 @@ function convertSearchParamsToFormData(searchParams) {
|
|
|
4394
4437
|
}
|
|
4395
4438
|
return formData;
|
|
4396
4439
|
}
|
|
4397
|
-
function processRouteLoaderData(matches, matchesToLoad, results,
|
|
4440
|
+
function processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds) {
|
|
4398
4441
|
// Fill in loaderData/errors from our loaders
|
|
4399
4442
|
let loaderData = {};
|
|
4400
4443
|
let errors = null;
|
|
4401
4444
|
let statusCode;
|
|
4402
4445
|
let foundError = false;
|
|
4403
4446
|
let loaderHeaders = {};
|
|
4447
|
+
let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : undefined;
|
|
4404
4448
|
|
|
4405
4449
|
// Process loader results into state.loaderData/state.errors
|
|
4406
4450
|
results.forEach((result, index) => {
|
|
@@ -4414,8 +4458,8 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
4414
4458
|
// If we have a pending action error, we report it at the highest-route
|
|
4415
4459
|
// that throws a loader error, and then clear it out to indicate that
|
|
4416
4460
|
// it was consumed
|
|
4417
|
-
if (pendingError) {
|
|
4418
|
-
error =
|
|
4461
|
+
if (pendingError !== undefined) {
|
|
4462
|
+
error = pendingError;
|
|
4419
4463
|
pendingError = undefined;
|
|
4420
4464
|
}
|
|
4421
4465
|
errors = errors || {};
|
|
@@ -4434,8 +4478,8 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
4434
4478
|
foundError = true;
|
|
4435
4479
|
statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
|
|
4436
4480
|
}
|
|
4437
|
-
if (result.
|
|
4438
|
-
loaderHeaders[id] = result.
|
|
4481
|
+
if (result.headers) {
|
|
4482
|
+
loaderHeaders[id] = result.headers;
|
|
4439
4483
|
}
|
|
4440
4484
|
} else {
|
|
4441
4485
|
if (isDeferredResult(result)) {
|
|
@@ -4453,11 +4497,11 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
4453
4497
|
loaderData[id] = result.data;
|
|
4454
4498
|
// Error status codes always override success status codes, but if all
|
|
4455
4499
|
// loaders are successful we take the deepest status code.
|
|
4456
|
-
if (result.
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
loaderHeaders[id] = result.
|
|
4500
|
+
if (result.statusCode && result.statusCode !== 200 && !foundError) {
|
|
4501
|
+
statusCode = result.statusCode;
|
|
4502
|
+
}
|
|
4503
|
+
if (result.headers) {
|
|
4504
|
+
loaderHeaders[id] = result.headers;
|
|
4461
4505
|
}
|
|
4462
4506
|
}
|
|
4463
4507
|
}
|
|
@@ -4466,9 +4510,11 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
4466
4510
|
// If we didn't consume the pending action error (i.e., all loaders
|
|
4467
4511
|
// resolved), then consume it here. Also clear out any loaderData for the
|
|
4468
4512
|
// throwing route
|
|
4469
|
-
if (pendingError) {
|
|
4470
|
-
errors =
|
|
4471
|
-
|
|
4513
|
+
if (pendingError !== undefined && pendingActionResult) {
|
|
4514
|
+
errors = {
|
|
4515
|
+
[pendingActionResult[0]]: pendingError
|
|
4516
|
+
};
|
|
4517
|
+
loaderData[pendingActionResult[0]] = undefined;
|
|
4472
4518
|
}
|
|
4473
4519
|
return {
|
|
4474
4520
|
loaderData,
|
|
@@ -4477,11 +4523,11 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
4477
4523
|
loaderHeaders
|
|
4478
4524
|
};
|
|
4479
4525
|
}
|
|
4480
|
-
function processLoaderData(state, matches, matchesToLoad, results,
|
|
4526
|
+
function processLoaderData(state, matches, matchesToLoad, results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) {
|
|
4481
4527
|
let {
|
|
4482
4528
|
loaderData,
|
|
4483
4529
|
errors
|
|
4484
|
-
} = processRouteLoaderData(matches, matchesToLoad, results,
|
|
4530
|
+
} = processRouteLoaderData(matches, matchesToLoad, results, pendingActionResult, activeDeferreds);
|
|
4485
4531
|
|
|
4486
4532
|
// Process results from our revalidating fetchers
|
|
4487
4533
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
@@ -4543,6 +4589,19 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
|
|
|
4543
4589
|
}
|
|
4544
4590
|
return mergedLoaderData;
|
|
4545
4591
|
}
|
|
4592
|
+
function getActionDataForCommit(pendingActionResult) {
|
|
4593
|
+
if (!pendingActionResult) {
|
|
4594
|
+
return {};
|
|
4595
|
+
}
|
|
4596
|
+
return isErrorResult(pendingActionResult[1]) ? {
|
|
4597
|
+
// Clear out prior actionData on errors
|
|
4598
|
+
actionData: {}
|
|
4599
|
+
} : {
|
|
4600
|
+
actionData: {
|
|
4601
|
+
[pendingActionResult[0]]: pendingActionResult[1].data
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4546
4605
|
|
|
4547
4606
|
// Find the nearest error boundary, looking upwards from the leaf route (or the
|
|
4548
4607
|
// route specified by routeId) for the closest ancestor error boundary,
|
|
@@ -4908,6 +4967,7 @@ function persistAppliedTransitions(_window, transitions) {
|
|
|
4908
4967
|
|
|
4909
4968
|
exports.AbortedDeferredError = AbortedDeferredError;
|
|
4910
4969
|
exports.Action = Action;
|
|
4970
|
+
exports.DecodedResponse = DecodedResponse;
|
|
4911
4971
|
exports.IDLE_BLOCKER = IDLE_BLOCKER;
|
|
4912
4972
|
exports.IDLE_FETCHER = IDLE_FETCHER;
|
|
4913
4973
|
exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
|