@remix-run/router 0.0.0-experimental-8f9ef191 → 0.0.0-experimental-9463fb5e
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 +19 -0
- package/README.md +1 -1
- package/dist/router.cjs.js +106 -74
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +9 -0
- package/dist/router.js +97 -71
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +106 -74
- 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 +5 -3
- package/package.json +1 -1
- package/router.ts +102 -46
- package/utils.ts +20 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Revert the `useResolvedPath` fix for splat routes due to a large number of applications that were relying on the buggy behavior (see https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329). We plan to re-introduce this fix behind a future flag in the next minor version. ([#11078](https://github.com/remix-run/react-router/pull/11078))
|
|
8
|
+
|
|
9
|
+
## 1.13.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Export the `PathParam` type from the public API ([#10719](https://github.com/remix-run/react-router/pull/10719))
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Fix bug with `resolveTo` in splat routes ([#11045](https://github.com/remix-run/react-router/pull/11045))
|
|
18
|
+
- This is a follow up to [#10983](https://github.com/remix-run/react-router/pull/10983) to handle the few other code paths using `getPathContributingMatches`
|
|
19
|
+
- This removes the `UNSAFE_getPathContributingMatches` export from `@remix-run/router` since we no longer need this in the `react-router`/`react-router-dom` layers
|
|
20
|
+
- Do not revalidate unmounted fetchers when `v7_fetcherPersist` is enabled ([#11044](https://github.com/remix-run/react-router/pull/11044))
|
|
21
|
+
|
|
3
22
|
## 1.12.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The `@remix-run/router` package is a framework-agnostic routing package (sometim
|
|
|
4
4
|
|
|
5
5
|
If you're using React Router, you should never `import` anything directly from the `@remix-run/router` - you should have everything you need in `react-router-dom` (or `react-router`/`react-router-native` if you're not rendering in the browser). All of those packages should re-export everything you would otherwise need from `@remix-run/router`.
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> [!WARNING]
|
|
8
8
|
>
|
|
9
9
|
> This router is a low-level package intended to be consumed by UI layer routing libraries. You should very likely not be using this package directly unless you are authoring a routing library such as [`react-router-dom`][react-router-repo] or one of it's other [UI ports][remix-routers-repo].
|
|
10
10
|
|
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-9463fb5e
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1194,9 +1194,16 @@ function getPathContributingMatches(matches) {
|
|
|
1194
1194
|
|
|
1195
1195
|
// Return the array of pathnames for the current route matches - used to
|
|
1196
1196
|
// generate the routePathnames input for resolveTo()
|
|
1197
|
-
function getResolveToMatches(matches) {
|
|
1198
|
-
|
|
1199
|
-
|
|
1197
|
+
function getResolveToMatches(matches, v7_relativeSplatPath) {
|
|
1198
|
+
let pathMatches = getPathContributingMatches(matches);
|
|
1199
|
+
|
|
1200
|
+
// When v7_relativeSplatPath is enabled, use the full pathname for the leaf
|
|
1201
|
+
// match so we include splat values for "." links. See:
|
|
1202
|
+
// https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329
|
|
1203
|
+
if (v7_relativeSplatPath) {
|
|
1204
|
+
return pathMatches.map((match, idx) => idx === matches.length - 1 ? match.pathname : match.pathnameBase);
|
|
1205
|
+
}
|
|
1206
|
+
return pathMatches.map(match => match.pathnameBase);
|
|
1200
1207
|
}
|
|
1201
1208
|
|
|
1202
1209
|
/**
|
|
@@ -1230,37 +1237,21 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
|
|
|
1230
1237
|
// to the current location's pathname and *not* the route pathname.
|
|
1231
1238
|
if (toPathname == null) {
|
|
1232
1239
|
from = locationPathname;
|
|
1233
|
-
} else if (isPathRelative) {
|
|
1234
|
-
let fromSegments = routePathnames[routePathnames.length - 1].replace(/^\//, "").split("/");
|
|
1235
|
-
if (toPathname.startsWith("..")) {
|
|
1236
|
-
let toSegments = toPathname.split("/");
|
|
1237
|
-
|
|
1238
|
-
// With relative="path", each leading .. segment means "go up one URL segment"
|
|
1239
|
-
while (toSegments[0] === "..") {
|
|
1240
|
-
toSegments.shift();
|
|
1241
|
-
fromSegments.pop();
|
|
1242
|
-
}
|
|
1243
|
-
to.pathname = toSegments.join("/");
|
|
1244
|
-
}
|
|
1245
|
-
from = "/" + fromSegments.join("/");
|
|
1246
1240
|
} else {
|
|
1247
1241
|
let routePathnameIndex = routePathnames.length - 1;
|
|
1248
|
-
if (toPathname.startsWith("..")) {
|
|
1249
|
-
let toSegments = toPathname.split("/");
|
|
1250
1242
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1243
|
+
// With relative="route" (the default), each leading .. segment means
|
|
1244
|
+
// "go up one route" instead of "go up one URL segment". This is a key
|
|
1245
|
+
// difference from how <a href> works and a major reason we call this a
|
|
1246
|
+
// "to" value instead of a "href".
|
|
1247
|
+
if (!isPathRelative && toPathname.startsWith("..")) {
|
|
1248
|
+
let toSegments = toPathname.split("/");
|
|
1255
1249
|
while (toSegments[0] === "..") {
|
|
1256
1250
|
toSegments.shift();
|
|
1257
1251
|
routePathnameIndex -= 1;
|
|
1258
1252
|
}
|
|
1259
1253
|
to.pathname = toSegments.join("/");
|
|
1260
1254
|
}
|
|
1261
|
-
|
|
1262
|
-
// If there are more ".." segments than parent routes, resolve relative to
|
|
1263
|
-
// the root / URL.
|
|
1264
1255
|
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
1265
1256
|
}
|
|
1266
1257
|
let path = resolvePath(to, from);
|
|
@@ -1687,7 +1678,8 @@ function createRouter(init) {
|
|
|
1687
1678
|
v7_fetcherPersist: false,
|
|
1688
1679
|
v7_normalizeFormMethod: false,
|
|
1689
1680
|
v7_partialHydration: false,
|
|
1690
|
-
v7_prependBasename: false
|
|
1681
|
+
v7_prependBasename: false,
|
|
1682
|
+
v7_relativeSplatPath: false
|
|
1691
1683
|
}, init.future);
|
|
1692
1684
|
// Cleanup function for history
|
|
1693
1685
|
let unlistenHistory = null;
|
|
@@ -2093,7 +2085,7 @@ function createRouter(init) {
|
|
|
2093
2085
|
init.history.go(to);
|
|
2094
2086
|
return;
|
|
2095
2087
|
}
|
|
2096
|
-
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
|
|
2088
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, future.v7_relativeSplatPath, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
|
|
2097
2089
|
let {
|
|
2098
2090
|
path,
|
|
2099
2091
|
submission,
|
|
@@ -2342,7 +2334,7 @@ function createRouter(init) {
|
|
|
2342
2334
|
})
|
|
2343
2335
|
};
|
|
2344
2336
|
} else {
|
|
2345
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
|
|
2337
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
|
|
2346
2338
|
if (request.signal.aborted) {
|
|
2347
2339
|
return {
|
|
2348
2340
|
shortCircuited: true
|
|
@@ -2552,7 +2544,7 @@ function createRouter(init) {
|
|
|
2552
2544
|
if (fetchControllers.has(key)) abortFetcher(key);
|
|
2553
2545
|
let flushSync = (opts && opts.unstable_flushSync) === true;
|
|
2554
2546
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2555
|
-
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
|
|
2547
|
+
let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative);
|
|
2556
2548
|
let matches = matchRoutes(routesToUse, normalizedPath, basename);
|
|
2557
2549
|
if (!matches) {
|
|
2558
2550
|
setFetcherError(key, routeId, getInternalRouterError(404, {
|
|
@@ -2617,7 +2609,7 @@ function createRouter(init) {
|
|
|
2617
2609
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
2618
2610
|
fetchControllers.set(key, abortController);
|
|
2619
2611
|
let originatingLoadId = incrementingLoadId;
|
|
2620
|
-
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
|
|
2612
|
+
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
|
|
2621
2613
|
if (fetchRequest.signal.aborted) {
|
|
2622
2614
|
// We can delete this so long as we weren't aborted by our own fetcher
|
|
2623
2615
|
// re-submit which would have put _new_ controller is in fetchControllers
|
|
@@ -2626,32 +2618,40 @@ function createRouter(init) {
|
|
|
2626
2618
|
}
|
|
2627
2619
|
return;
|
|
2628
2620
|
}
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
if (
|
|
2634
|
-
|
|
2635
|
-
if (pendingNavigationLoadId > originatingLoadId) {
|
|
2636
|
-
// A new navigation was kicked off after our action started, so that
|
|
2637
|
-
// should take precedence over this redirect navigation. We already
|
|
2638
|
-
// set isRevalidationRequired so all loaders for the new route should
|
|
2639
|
-
// fire unless opted out via shouldRevalidate
|
|
2621
|
+
|
|
2622
|
+
// When using v7_fetcherPersist, we don't want errors bubbling up to the UI
|
|
2623
|
+
// or redirects processed for unmounted fetchers so we just revert them to
|
|
2624
|
+
// idle
|
|
2625
|
+
if (future.v7_fetcherPersist && deletedFetchers.has(key)) {
|
|
2626
|
+
if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
|
|
2640
2627
|
updateFetcherState(key, getDoneFetcher(undefined));
|
|
2641
2628
|
return;
|
|
2642
|
-
} else {
|
|
2643
|
-
fetchRedirectIds.add(key);
|
|
2644
|
-
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2645
|
-
return startRedirectNavigation(state, actionResult, {
|
|
2646
|
-
fetcherSubmission: submission
|
|
2647
|
-
});
|
|
2648
2629
|
}
|
|
2649
|
-
|
|
2630
|
+
// Let SuccessResult's fall through for revalidation
|
|
2631
|
+
} else {
|
|
2632
|
+
if (isRedirectResult(actionResult)) {
|
|
2633
|
+
fetchControllers.delete(key);
|
|
2634
|
+
if (pendingNavigationLoadId > originatingLoadId) {
|
|
2635
|
+
// A new navigation was kicked off after our action started, so that
|
|
2636
|
+
// should take precedence over this redirect navigation. We already
|
|
2637
|
+
// set isRevalidationRequired so all loaders for the new route should
|
|
2638
|
+
// fire unless opted out via shouldRevalidate
|
|
2639
|
+
updateFetcherState(key, getDoneFetcher(undefined));
|
|
2640
|
+
return;
|
|
2641
|
+
} else {
|
|
2642
|
+
fetchRedirectIds.add(key);
|
|
2643
|
+
updateFetcherState(key, getLoadingFetcher(submission));
|
|
2644
|
+
return startRedirectNavigation(state, actionResult, {
|
|
2645
|
+
fetcherSubmission: submission
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2650
2649
|
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2650
|
+
// Process any non-redirect errors thrown
|
|
2651
|
+
if (isErrorResult(actionResult)) {
|
|
2652
|
+
setFetcherError(key, routeId, actionResult.error);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
2655
|
}
|
|
2656
2656
|
if (isDeferredResult(actionResult)) {
|
|
2657
2657
|
throw getInternalRouterError(400, {
|
|
@@ -2770,7 +2770,7 @@ function createRouter(init) {
|
|
|
2770
2770
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
2771
2771
|
fetchControllers.set(key, abortController);
|
|
2772
2772
|
let originatingLoadId = incrementingLoadId;
|
|
2773
|
-
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename);
|
|
2773
|
+
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
|
|
2774
2774
|
|
|
2775
2775
|
// Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2776
2776
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
@@ -2788,6 +2788,9 @@ function createRouter(init) {
|
|
|
2788
2788
|
if (fetchRequest.signal.aborted) {
|
|
2789
2789
|
return;
|
|
2790
2790
|
}
|
|
2791
|
+
|
|
2792
|
+
// We don't want errors bubbling up or redirects followed for unmounted
|
|
2793
|
+
// fetchers, so short circuit here if it was removed from the UI
|
|
2791
2794
|
if (deletedFetchers.has(key)) {
|
|
2792
2795
|
updateFetcherState(key, getDoneFetcher(undefined));
|
|
2793
2796
|
return;
|
|
@@ -2918,9 +2921,9 @@ function createRouter(init) {
|
|
|
2918
2921
|
// Call all navigation loaders and revalidating fetcher loaders in parallel,
|
|
2919
2922
|
// then slice off the results into separate arrays so we can handle them
|
|
2920
2923
|
// accordingly
|
|
2921
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename)), ...fetchersToLoad.map(f => {
|
|
2924
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath)), ...fetchersToLoad.map(f => {
|
|
2922
2925
|
if (f.matches && f.match && f.controller) {
|
|
2923
|
-
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename);
|
|
2926
|
+
return callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, f.controller.signal), f.match, f.matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath);
|
|
2924
2927
|
} else {
|
|
2925
2928
|
let error = {
|
|
2926
2929
|
type: ResultType.error,
|
|
@@ -3239,6 +3242,11 @@ function createRouter(init) {
|
|
|
3239
3242
|
////////////////////////////////////////////////////////////////////////////////
|
|
3240
3243
|
|
|
3241
3244
|
const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
3245
|
+
|
|
3246
|
+
/**
|
|
3247
|
+
* Future flags to toggle new feature behavior
|
|
3248
|
+
*/
|
|
3249
|
+
|
|
3242
3250
|
function createStaticHandler(routes, opts) {
|
|
3243
3251
|
invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
|
|
3244
3252
|
let manifest = {};
|
|
@@ -3255,6 +3263,11 @@ function createStaticHandler(routes, opts) {
|
|
|
3255
3263
|
} else {
|
|
3256
3264
|
mapRouteProperties = defaultMapRouteProperties;
|
|
3257
3265
|
}
|
|
3266
|
+
// Config driven behavior flags
|
|
3267
|
+
let future = _extends({
|
|
3268
|
+
v7_relativeSplatPath: false,
|
|
3269
|
+
v7_throwAbortReason: false
|
|
3270
|
+
}, opts ? opts.future : null);
|
|
3258
3271
|
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
3259
3272
|
|
|
3260
3273
|
/**
|
|
@@ -3470,14 +3483,13 @@ function createStaticHandler(routes, opts) {
|
|
|
3470
3483
|
error
|
|
3471
3484
|
};
|
|
3472
3485
|
} else {
|
|
3473
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, {
|
|
3486
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath, {
|
|
3474
3487
|
isStaticRequest: true,
|
|
3475
3488
|
isRouteRequest,
|
|
3476
3489
|
requestContext
|
|
3477
3490
|
});
|
|
3478
3491
|
if (request.signal.aborted) {
|
|
3479
|
-
|
|
3480
|
-
throw new Error(method + "() call aborted: " + request.method + " " + request.url);
|
|
3492
|
+
throwStaticHandlerAbortedError(request, isRouteRequest, future);
|
|
3481
3493
|
}
|
|
3482
3494
|
}
|
|
3483
3495
|
if (isRedirectResult(result)) {
|
|
@@ -3589,14 +3601,13 @@ function createStaticHandler(routes, opts) {
|
|
|
3589
3601
|
activeDeferreds: null
|
|
3590
3602
|
};
|
|
3591
3603
|
}
|
|
3592
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, {
|
|
3604
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, future.v7_relativeSplatPath, {
|
|
3593
3605
|
isStaticRequest: true,
|
|
3594
3606
|
isRouteRequest,
|
|
3595
3607
|
requestContext
|
|
3596
3608
|
}))]);
|
|
3597
3609
|
if (request.signal.aborted) {
|
|
3598
|
-
|
|
3599
|
-
throw new Error(method + "() call aborted: " + request.method + " " + request.url);
|
|
3610
|
+
throwStaticHandlerAbortedError(request, isRouteRequest, future);
|
|
3600
3611
|
}
|
|
3601
3612
|
|
|
3602
3613
|
// Process and commit output from loaders
|
|
@@ -3641,10 +3652,18 @@ function getStaticContextFromError(routes, context, error) {
|
|
|
3641
3652
|
});
|
|
3642
3653
|
return newContext;
|
|
3643
3654
|
}
|
|
3655
|
+
function throwStaticHandlerAbortedError(request, isRouteRequest, future) {
|
|
3656
|
+
let method = isRouteRequest ? "queryRoute" : "query";
|
|
3657
|
+
if (future.v7_throwAbortReason && request.signal.reason !== undefined) {
|
|
3658
|
+
throw request.signal.reason;
|
|
3659
|
+
} else {
|
|
3660
|
+
throw new Error(method + "() call aborted: " + request.method + " " + request.url);
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3644
3663
|
function isSubmissionNavigation(opts) {
|
|
3645
3664
|
return opts != null && ("formData" in opts && opts.formData != null || "body" in opts && opts.body !== undefined);
|
|
3646
3665
|
}
|
|
3647
|
-
function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
|
|
3666
|
+
function normalizeTo(location, matches, basename, prependBasename, to, v7_relativeSplatPath, fromRouteId, relative) {
|
|
3648
3667
|
let contextualMatches;
|
|
3649
3668
|
let activeRouteMatch;
|
|
3650
3669
|
if (fromRouteId) {
|
|
@@ -3664,7 +3683,7 @@ function normalizeTo(location, matches, basename, prependBasename, to, fromRoute
|
|
|
3664
3683
|
}
|
|
3665
3684
|
|
|
3666
3685
|
// Resolve the relative path
|
|
3667
|
-
let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
|
|
3686
|
+
let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches, v7_relativeSplatPath), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
|
|
3668
3687
|
|
|
3669
3688
|
// When `to` is not specified we inherit search/hash from the current
|
|
3670
3689
|
// location, unlike when to="." and we just inherit the path.
|
|
@@ -3954,7 +3973,13 @@ function getMatchesToLoad(history, state, matches, submission, location, isIniti
|
|
|
3954
3973
|
// Is this route unhydrated (when v7_partialHydration=true) such that we need
|
|
3955
3974
|
// to call it's loader on the initial router creation
|
|
3956
3975
|
function isUnhydratedRoute(state, route) {
|
|
3957
|
-
|
|
3976
|
+
if (!route.loader) {
|
|
3977
|
+
return false;
|
|
3978
|
+
}
|
|
3979
|
+
if (route.loader.hydrate) {
|
|
3980
|
+
return true;
|
|
3981
|
+
}
|
|
3982
|
+
return state.loaderData[route.id] === undefined && (!state.errors ||
|
|
3958
3983
|
// Loader ran but errored - don't re-run
|
|
3959
3984
|
state.errors[route.id] === undefined);
|
|
3960
3985
|
}
|
|
@@ -4044,7 +4069,7 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
4044
4069
|
lazy: undefined
|
|
4045
4070
|
}));
|
|
4046
4071
|
}
|
|
4047
|
-
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, opts) {
|
|
4072
|
+
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, v7_relativeSplatPath, opts) {
|
|
4048
4073
|
if (opts === void 0) {
|
|
4049
4074
|
opts = {};
|
|
4050
4075
|
}
|
|
@@ -4134,7 +4159,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
4134
4159
|
|
|
4135
4160
|
// Support relative routing in internal redirects
|
|
4136
4161
|
if (!ABSOLUTE_URL_REGEX.test(location)) {
|
|
4137
|
-
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
|
|
4162
|
+
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location, v7_relativeSplatPath);
|
|
4138
4163
|
} else if (!opts.isStaticRequest) {
|
|
4139
4164
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
4140
4165
|
// redirects. If this is a static request, we can let it go back to the
|
|
@@ -4175,13 +4200,20 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
4175
4200
|
throw queryRouteResponse;
|
|
4176
4201
|
}
|
|
4177
4202
|
let data;
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4203
|
+
try {
|
|
4204
|
+
let contentType = result.headers.get("Content-Type");
|
|
4205
|
+
// Check between word boundaries instead of startsWith() due to the last
|
|
4206
|
+
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
|
|
4207
|
+
if (contentType && /\bapplication\/json\b/.test(contentType)) {
|
|
4208
|
+
data = await result.json();
|
|
4209
|
+
} else {
|
|
4210
|
+
data = await result.text();
|
|
4211
|
+
}
|
|
4212
|
+
} catch (e) {
|
|
4213
|
+
return {
|
|
4214
|
+
type: ResultType.error,
|
|
4215
|
+
error: e
|
|
4216
|
+
};
|
|
4185
4217
|
}
|
|
4186
4218
|
if (resultType === ResultType.error) {
|
|
4187
4219
|
return {
|