react-router 8.3.0 → 8.3.1
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 +13 -2
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +1 -1
- package/dist/development/index-react-server.d.ts +8 -0
- package/dist/development/index-react-server.js +22 -13
- package/dist/development/index.js +1 -1
- package/dist/development/lib/actions.js +10 -5
- package/dist/development/lib/components.js +6 -3
- package/dist/development/lib/context.d.ts +1 -0
- package/dist/development/lib/context.js +1 -1
- package/dist/development/lib/dom/dom.js +2 -2
- package/dist/development/lib/dom/lib.js +20 -5
- package/dist/development/lib/dom/server.js +1 -1
- package/dist/development/lib/dom/ssr/components.js +2 -2
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/development/lib/dom/ssr/fallback.js +1 -1
- package/dist/development/lib/dom/ssr/fog-of-war.js +2 -1
- package/dist/development/lib/dom/ssr/hydration.js +1 -1
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +1 -1
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/development/lib/dom/ssr/routes.js +1 -1
- package/dist/development/lib/dom/ssr/server.js +1 -1
- package/dist/development/lib/dom/ssr/single-fetch.js +5 -5
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.js +1 -1
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.js +6 -3
- package/dist/development/lib/href.js +1 -1
- package/dist/development/lib/router/history.js +2 -2
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/navigation.js +45 -0
- package/dist/development/lib/router/router.d.ts +8 -0
- package/dist/development/lib/router/router.js +31 -17
- package/dist/development/lib/router/url.js +1 -1
- package/dist/development/lib/router/utils.js +10 -6
- package/dist/development/lib/rsc/browser.js +4 -1
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +2 -2
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.ssr.js +2 -2
- package/dist/development/lib/server-runtime/cookies.js +2 -2
- package/dist/development/lib/server-runtime/crypto.js +2 -2
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +2 -2
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +1 -1
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +1 -1
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.js +2 -2
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions.js +1 -1
- package/dist/development/lib/server-runtime/single-fetch.js +2 -2
- package/dist/development/lib/server-runtime/urls.js +1 -1
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +4 -4
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +1 -1
- package/dist/production/index-react-server.d.ts +8 -0
- package/dist/production/index-react-server.js +22 -13
- package/dist/production/index.js +1 -1
- package/dist/production/lib/actions.js +10 -5
- package/dist/production/lib/components.js +6 -3
- package/dist/production/lib/context.d.ts +1 -0
- package/dist/production/lib/context.js +1 -1
- package/dist/production/lib/dom/dom.js +2 -2
- package/dist/production/lib/dom/lib.js +20 -5
- package/dist/production/lib/dom/server.js +1 -1
- package/dist/production/lib/dom/ssr/components.js +2 -2
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/production/lib/dom/ssr/fallback.js +1 -1
- package/dist/production/lib/dom/ssr/fog-of-war.js +2 -1
- package/dist/production/lib/dom/ssr/hydration.js +1 -1
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +1 -1
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/production/lib/dom/ssr/routes.js +1 -1
- package/dist/production/lib/dom/ssr/server.js +1 -1
- package/dist/production/lib/dom/ssr/single-fetch.js +5 -5
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.js +1 -1
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.js +6 -3
- package/dist/production/lib/href.js +1 -1
- package/dist/production/lib/router/history.js +2 -2
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/navigation.js +45 -0
- package/dist/production/lib/router/router.d.ts +8 -0
- package/dist/production/lib/router/router.js +31 -17
- package/dist/production/lib/router/url.js +1 -1
- package/dist/production/lib/router/utils.js +10 -6
- package/dist/production/lib/rsc/browser.js +4 -1
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +2 -2
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.ssr.js +2 -2
- package/dist/production/lib/server-runtime/cookies.js +2 -2
- package/dist/production/lib/server-runtime/crypto.js +2 -2
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +2 -2
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +1 -1
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +1 -1
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.js +2 -2
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions.js +1 -1
- package/dist/production/lib/server-runtime/single-fetch.js +2 -2
- package/dist/production/lib/server-runtime/urls.js +1 -1
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +4 -4
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -24,7 +24,7 @@ function warning(cond, message) {
|
|
|
24
24
|
if (typeof console !== "undefined") console.warn(message);
|
|
25
25
|
try {
|
|
26
26
|
throw new Error(message);
|
|
27
|
-
} catch
|
|
27
|
+
} catch {}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
function createKey$1() {
|
|
@@ -506,13 +506,13 @@ function matchPathImpl(pattern, pathname, matcher, compiledParams) {
|
|
|
506
506
|
let match = pathname.match(matcher);
|
|
507
507
|
if (!match) return null;
|
|
508
508
|
let matchedPathname = match[0];
|
|
509
|
-
let pathnameBase = matchedPathname
|
|
509
|
+
let pathnameBase = removeTrailingSlash(matchedPathname, 1);
|
|
510
510
|
let captureGroups = match.slice(1);
|
|
511
511
|
return {
|
|
512
512
|
params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
|
|
513
513
|
if (paramName === "*") {
|
|
514
514
|
let splatValue = captureGroups[index] || "";
|
|
515
|
-
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length)
|
|
515
|
+
pathnameBase = removeTrailingSlash(matchedPathname.slice(0, matchedPathname.length - splatValue.length), 1);
|
|
516
516
|
}
|
|
517
517
|
const value = captureGroups[index];
|
|
518
518
|
if (isOptional && !value) memo[paramName] = void 0;
|
|
@@ -581,7 +581,7 @@ function resolvePath(to, fromPathname = "/") {
|
|
|
581
581
|
let pathname;
|
|
582
582
|
if (toPathname) {
|
|
583
583
|
toPathname = removeDoubleSlashes(toPathname);
|
|
584
|
-
if (toPathname.startsWith("/")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
584
|
+
if (toPathname.startsWith("/") || toPathname.startsWith("\\")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
585
585
|
else pathname = resolvePathname(toPathname, fromPathname);
|
|
586
586
|
} else pathname = fromPathname;
|
|
587
587
|
return {
|
|
@@ -642,7 +642,11 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = fal
|
|
|
642
642
|
}
|
|
643
643
|
const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
|
|
644
644
|
const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
|
|
645
|
-
|
|
645
|
+
function removeTrailingSlash(path, minLength = 0) {
|
|
646
|
+
let end = path.length;
|
|
647
|
+
while (end > minLength && path.charCodeAt(end - 1) === 47) end--;
|
|
648
|
+
return end === path.length ? path : path.slice(0, end);
|
|
649
|
+
}
|
|
646
650
|
const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
|
|
647
651
|
const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
648
652
|
const normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
|
@@ -1807,7 +1811,7 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
|
|
|
1807
1811
|
});
|
|
1808
1812
|
try {
|
|
1809
1813
|
await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
|
|
1810
|
-
} catch
|
|
1814
|
+
} catch {}
|
|
1811
1815
|
return results;
|
|
1812
1816
|
}
|
|
1813
1817
|
async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
|
|
@@ -2208,14 +2212,19 @@ function getPathsWithAncestors(paths) {
|
|
|
2208
2212
|
function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
|
|
2209
2213
|
let originHeader = request.headers.get("origin");
|
|
2210
2214
|
let originDomain = null;
|
|
2215
|
+
let originUrl = null;
|
|
2211
2216
|
try {
|
|
2212
|
-
|
|
2217
|
+
if (typeof originHeader === "string" && originHeader !== "null") {
|
|
2218
|
+
originUrl = new URL(originHeader);
|
|
2219
|
+
originDomain = originUrl.host;
|
|
2220
|
+
} else originDomain = originHeader;
|
|
2213
2221
|
} catch {
|
|
2214
2222
|
throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
|
|
2215
2223
|
}
|
|
2216
|
-
let
|
|
2217
|
-
|
|
2218
|
-
|
|
2224
|
+
let requestUrl = new URL(request.url);
|
|
2225
|
+
let originMatchesRequest = originUrl ? originUrl.origin === requestUrl.origin : originDomain === requestUrl.host;
|
|
2226
|
+
if (originDomain && !originMatchesRequest) {
|
|
2227
|
+
if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` origin does not match `origin` header from a forwarded action request. Aborting the action.");
|
|
2219
2228
|
}
|
|
2220
2229
|
}
|
|
2221
2230
|
function matchWildcardDomain(domain, pattern) {
|
|
@@ -2939,7 +2948,7 @@ const unsign = async (cookie, secret) => {
|
|
|
2939
2948
|
try {
|
|
2940
2949
|
let signature = byteStringToUint8Array(atob(hash));
|
|
2941
2950
|
return await crypto.subtle.verify("HMAC", key, signature, data) ? value : false;
|
|
2942
|
-
} catch
|
|
2951
|
+
} catch {
|
|
2943
2952
|
return false;
|
|
2944
2953
|
}
|
|
2945
2954
|
};
|
|
@@ -3037,7 +3046,7 @@ function encodeData(value) {
|
|
|
3037
3046
|
function decodeData(value) {
|
|
3038
3047
|
try {
|
|
3039
3048
|
return JSON.parse(decodeURIComponent(myEscape(atob(value))));
|
|
3040
|
-
} catch
|
|
3049
|
+
} catch {
|
|
3041
3050
|
return {};
|
|
3042
3051
|
}
|
|
3043
3052
|
}
|
package/dist/production/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -12,14 +12,19 @@
|
|
|
12
12
|
function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
|
|
13
13
|
let originHeader = request.headers.get("origin");
|
|
14
14
|
let originDomain = null;
|
|
15
|
+
let originUrl = null;
|
|
15
16
|
try {
|
|
16
|
-
|
|
17
|
+
if (typeof originHeader === "string" && originHeader !== "null") {
|
|
18
|
+
originUrl = new URL(originHeader);
|
|
19
|
+
originDomain = originUrl.host;
|
|
20
|
+
} else originDomain = originHeader;
|
|
17
21
|
} catch {
|
|
18
22
|
throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
|
|
19
23
|
}
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
let requestUrl = new URL(request.url);
|
|
25
|
+
let originMatchesRequest = originUrl ? originUrl.origin === requestUrl.origin : originDomain === requestUrl.host;
|
|
26
|
+
if (originDomain && !originMatchesRequest) {
|
|
27
|
+
if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` origin does not match `origin` header from a forwarded action request. Aborting the action.");
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
function matchWildcardDomain(domain, pattern) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { createMemoryHistory, invariant, parsePath, warning } from "./router/history.js";
|
|
11
|
+
import { createMemoryHistory, createPath, invariant, parsePath, warning } from "./router/history.js";
|
|
12
12
|
import { defaultMapRouteProperties, getResolveToMatches, getRoutePattern, resolveTo, stripBasename } from "./router/utils.js";
|
|
13
|
+
import { getNavigatorCurrentUrl, validateNavigationTarget } from "./router/navigation.js";
|
|
13
14
|
import { createRouter } from "./router/router.js";
|
|
14
15
|
import { AwaitContext, DataRouterContext, DataRouterStateContext, FetchersContext, LocationContext, NavigationContext, RouteContext, ViewTransitionContext, useIsRSCRouterContext } from "./context.js";
|
|
15
16
|
import { _renderMatches, useActionData, useAsyncValue, useInRouterContext, useLoaderData, useLocation, useMatches, useNavigate, useOutlet, useParams, useRouteError, useRoutes, useRoutesImpl } from "./hooks.js";
|
|
@@ -256,6 +257,7 @@ function RouterProvider({ router, flushSync: reactDomFlushSyncImpl, onError, use
|
|
|
256
257
|
let navigator = React$1.useMemo(() => {
|
|
257
258
|
return {
|
|
258
259
|
createHref: router.createHref,
|
|
260
|
+
createURL: router.createURL,
|
|
259
261
|
encodeLocation: router.encodeLocation,
|
|
260
262
|
go: (n) => router.navigate(n),
|
|
261
263
|
push: (to, state, opts) => router.navigate(to, {
|
|
@@ -379,12 +381,13 @@ function MemoryRouter({ basename, children, initialEntries, initialIndex, useTra
|
|
|
379
381
|
*/
|
|
380
382
|
function Navigate({ to, replace, state, relative }) {
|
|
381
383
|
invariant(useInRouterContext(), `<Navigate> may be used only in the context of a <Router> component.`);
|
|
382
|
-
let { static: isStatic } = React$1.useContext(NavigationContext);
|
|
384
|
+
let { static: isStatic, navigator } = React$1.useContext(NavigationContext);
|
|
383
385
|
warning(!isStatic, "<Navigate> must not be used on the initial render in a <StaticRouter>. This is a no-op, but you should modify your code so the <Navigate> is only ever rendered in response to some user interaction or state change.");
|
|
384
386
|
let { matches } = React$1.useContext(RouteContext);
|
|
385
387
|
let { pathname: locationPathname } = useLocation();
|
|
386
388
|
let navigate = useNavigate();
|
|
387
389
|
let path = resolveTo(to, getResolveToMatches(matches), locationPathname, relative === "path");
|
|
390
|
+
validateNavigationTarget(typeof to === "string" ? to : createPath(to), navigator.createHref(path), getNavigatorCurrentUrl(navigator), "reject");
|
|
388
391
|
let jsonPath = JSON.stringify(path);
|
|
389
392
|
React$1.useEffect(() => {
|
|
390
393
|
navigate(JSON.parse(jsonPath), {
|
|
@@ -55,6 +55,7 @@ interface NavigateOptions {
|
|
|
55
55
|
*/
|
|
56
56
|
interface Navigator {
|
|
57
57
|
createHref: History["createHref"];
|
|
58
|
+
createURL?: History["createURL"];
|
|
58
59
|
encodeLocation?: History["encodeLocation"];
|
|
59
60
|
go: History["go"];
|
|
60
61
|
push(to: To, state?: any, opts?: NavigateOptions): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -75,7 +75,7 @@ function isFormDataSubmitterSupported() {
|
|
|
75
75
|
if (_formDataSupportsSubmitter === null) try {
|
|
76
76
|
new FormData(document.createElement("form"), 0);
|
|
77
77
|
_formDataSupportsSubmitter = false;
|
|
78
|
-
} catch
|
|
78
|
+
} catch {
|
|
79
79
|
_formDataSupportsSubmitter = true;
|
|
80
80
|
}
|
|
81
81
|
return _formDataSupportsSubmitter;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -22,8 +22,8 @@ import * as React$1 from "react";
|
|
|
22
22
|
//#region lib/dom/lib.tsx
|
|
23
23
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
24
24
|
try {
|
|
25
|
-
if (isBrowser) window.__reactRouterVersion = "8
|
|
26
|
-
} catch
|
|
25
|
+
if (isBrowser) window.__reactRouterVersion = "8";
|
|
26
|
+
} catch {}
|
|
27
27
|
/**
|
|
28
28
|
* Create a new {@link DataRouter| data router} that manages the application
|
|
29
29
|
* path via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
|
|
@@ -123,7 +123,7 @@ function deserializeErrors(errors) {
|
|
|
123
123
|
let error = new ErrorConstructor(val.message);
|
|
124
124
|
error.stack = "";
|
|
125
125
|
serialized[key] = error;
|
|
126
|
-
} catch
|
|
126
|
+
} catch {}
|
|
127
127
|
}
|
|
128
128
|
if (serialized[key] == null) {
|
|
129
129
|
let error = new Error(val.message);
|
|
@@ -796,6 +796,7 @@ function useSubmit() {
|
|
|
796
796
|
if (options.navigate === false) await routerFetch(options.fetcherKey || getUniqueFetcherId(), currentRouteId, options.action || action, {
|
|
797
797
|
defaultShouldRevalidate: options.defaultShouldRevalidate,
|
|
798
798
|
preventScrollReset: options.preventScrollReset,
|
|
799
|
+
relative: options.relative,
|
|
799
800
|
formData,
|
|
800
801
|
body,
|
|
801
802
|
formMethod: options.method || method,
|
|
@@ -805,6 +806,7 @@ function useSubmit() {
|
|
|
805
806
|
else await routerNavigate(options.action || action, {
|
|
806
807
|
defaultShouldRevalidate: options.defaultShouldRevalidate,
|
|
807
808
|
preventScrollReset: options.preventScrollReset,
|
|
809
|
+
relative: options.relative,
|
|
808
810
|
formData,
|
|
809
811
|
body,
|
|
810
812
|
formMethod: options.method || method,
|
|
@@ -1087,6 +1089,9 @@ function useScrollRestoration({ getKey, storageKey } = {}) {
|
|
|
1087
1089
|
window.history.scrollRestoration = "auto";
|
|
1088
1090
|
};
|
|
1089
1091
|
}, []);
|
|
1092
|
+
usePageShow(React$1.useCallback((event) => {
|
|
1093
|
+
if (event.persisted) window.history.scrollRestoration = "manual";
|
|
1094
|
+
}, []));
|
|
1090
1095
|
usePageHide(React$1.useCallback(() => {
|
|
1091
1096
|
if (navigation.state === "idle") {
|
|
1092
1097
|
let key = getScrollRestorationKey(location, matches, basename, getKey);
|
|
@@ -1111,7 +1116,7 @@ function useScrollRestoration({ getKey, storageKey } = {}) {
|
|
|
1111
1116
|
try {
|
|
1112
1117
|
let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY);
|
|
1113
1118
|
if (sessionPositions) savedScrollPositions = JSON.parse(sessionPositions);
|
|
1114
|
-
} catch
|
|
1119
|
+
} catch {}
|
|
1115
1120
|
}, [storageKey]);
|
|
1116
1121
|
React$1.useLayoutEffect(() => {
|
|
1117
1122
|
let disableScrollRestoration = router?.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey ? (location, matches) => getScrollRestorationKey(location, matches, basename, getKey) : void 0);
|
|
@@ -1179,6 +1184,16 @@ function usePageHide(callback, options) {
|
|
|
1179
1184
|
};
|
|
1180
1185
|
}, [callback, capture]);
|
|
1181
1186
|
}
|
|
1187
|
+
function usePageShow(callback, options) {
|
|
1188
|
+
let { capture } = options || {};
|
|
1189
|
+
React$1.useEffect(() => {
|
|
1190
|
+
let opts = capture != null ? { capture } : void 0;
|
|
1191
|
+
window.addEventListener("pageshow", callback, opts);
|
|
1192
|
+
return () => {
|
|
1193
|
+
window.removeEventListener("pageshow", callback, opts);
|
|
1194
|
+
};
|
|
1195
|
+
}, [callback, capture]);
|
|
1196
|
+
}
|
|
1182
1197
|
/**
|
|
1183
1198
|
* Wrapper around {@link useBlocker} to show a [`window.confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
|
|
1184
1199
|
* prompt to users instead of building a custom UI with {@link useBlocker}.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -425,7 +425,7 @@ function Meta() {
|
|
|
425
425
|
type: "application/ld+json",
|
|
426
426
|
dangerouslySetInnerHTML: { __html: escapeHtml(json) }
|
|
427
427
|
});
|
|
428
|
-
} catch
|
|
428
|
+
} catch {
|
|
429
429
|
return null;
|
|
430
430
|
}
|
|
431
431
|
return /* @__PURE__ */ React$1.createElement("meta", {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -154,6 +154,7 @@ async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, ro
|
|
|
154
154
|
if (signal?.aborted) return;
|
|
155
155
|
throw e;
|
|
156
156
|
}
|
|
157
|
+
if (signal?.aborted) return;
|
|
157
158
|
let knownRoutes = new Set(Object.keys(manifest.routes));
|
|
158
159
|
let patches = Object.values(serverPatches).reduce((acc, route) => {
|
|
159
160
|
if (route && !knownRoutes.has(route.id)) acc[route.id] = route;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -205,7 +205,7 @@ async function bubbleMiddlewareErrors(singleFetchPromise, matches, routesParams,
|
|
|
205
205
|
if (middlewareError !== void 0) Array.from(routesParams.values()).forEach((routeId) => {
|
|
206
206
|
if (results[routeId].result instanceof SingleFetchNoResultError) results[routeId].result = middlewareError;
|
|
207
207
|
});
|
|
208
|
-
} catch
|
|
208
|
+
} catch {}
|
|
209
209
|
}
|
|
210
210
|
async function singleFetchLoaderFetcherStrategy(args, fetchAndDecode) {
|
|
211
211
|
let fetcherMatch = args.matches.find((m) => m.shouldCallHandler());
|
|
@@ -277,7 +277,7 @@ async function fetchAndDecodeViaTurboStream(args, targetRoutes) {
|
|
|
277
277
|
status: res.status,
|
|
278
278
|
data
|
|
279
279
|
};
|
|
280
|
-
} catch
|
|
280
|
+
} catch {
|
|
281
281
|
throw new Error("Unable to decode turbo-stream response");
|
|
282
282
|
}
|
|
283
283
|
}
|
|
@@ -326,13 +326,13 @@ function createDeferred() {
|
|
|
326
326
|
res(val);
|
|
327
327
|
try {
|
|
328
328
|
await promise;
|
|
329
|
-
} catch
|
|
329
|
+
} catch {}
|
|
330
330
|
};
|
|
331
331
|
reject = async (error) => {
|
|
332
332
|
rej(error);
|
|
333
333
|
try {
|
|
334
334
|
await promise;
|
|
335
|
-
} catch
|
|
335
|
+
} catch {}
|
|
336
336
|
};
|
|
337
337
|
});
|
|
338
338
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { invariant, parsePath, warning } from "./router/history.js";
|
|
11
|
+
import { createPath, invariant, parsePath, warning } from "./router/history.js";
|
|
12
12
|
import { convertRouteMatchToUiMatch, decodePath, getResolveToMatches, getRoutePattern, isBrowser, isRouteErrorResponse, joinPaths, matchPath, matchRoutes, parseToInfo, resolveTo, stripBasename } from "./router/utils.js";
|
|
13
|
+
import { getNavigatorCurrentUrl, validateNavigationTarget } from "./router/navigation.js";
|
|
13
14
|
import { IDLE_BLOCKER, hasInvalidProtocol } from "./router/router.js";
|
|
14
15
|
import { AwaitContext, DataRouterContext, DataRouterStateContext, LocationContext, NavigationContext, RSCRouterContext, RouteContext, RouteErrorContext } from "./context.js";
|
|
15
16
|
import { decodeRedirectErrorDigest, decodeRouteErrorResponseDigest } from "./errors.js";
|
|
@@ -291,6 +292,7 @@ function useNavigateUnstable() {
|
|
|
291
292
|
}
|
|
292
293
|
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
|
|
293
294
|
if (dataRouterContext == null && basename !== "/") path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
295
|
+
validateNavigationTarget(typeof to === "string" ? to : createPath(to), navigator.createHref(path), getNavigatorCurrentUrl(navigator), "reject");
|
|
294
296
|
(!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
|
|
295
297
|
}, [
|
|
296
298
|
basename,
|
|
@@ -672,7 +674,7 @@ var RenderErrorBoundary = class extends React$1.Component {
|
|
|
672
674
|
};
|
|
673
675
|
const errorRedirectHandledMap = /* @__PURE__ */ new WeakMap();
|
|
674
676
|
function RSCErrorHandler({ children, error }) {
|
|
675
|
-
let { basename } = React$1.useContext(NavigationContext);
|
|
677
|
+
let { basename, navigator } = React$1.useContext(NavigationContext);
|
|
676
678
|
if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
|
|
677
679
|
let redirect = decodeRedirectErrorDigest(error.digest);
|
|
678
680
|
if (redirect) {
|
|
@@ -680,6 +682,7 @@ function RSCErrorHandler({ children, error }) {
|
|
|
680
682
|
if (existingRedirect) throw existingRedirect;
|
|
681
683
|
let parsed = parseToInfo(redirect.location, basename);
|
|
682
684
|
let target = parsed.absoluteURL || parsed.to;
|
|
685
|
+
validateNavigationTarget(redirect.location, target, getNavigatorCurrentUrl(navigator), "allow-explicit");
|
|
683
686
|
if (hasInvalidProtocol(target)) throw new Error("Invalid redirect location");
|
|
684
687
|
if (isBrowser && !errorRedirectHandledMap.get(error)) if (parsed.isExternal || redirect.reloadDocument) window.location.href = target;
|
|
685
688
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.3.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -193,7 +193,7 @@ function warning(cond, message) {
|
|
|
193
193
|
if (typeof console !== "undefined") console.warn(message);
|
|
194
194
|
try {
|
|
195
195
|
throw new Error(message);
|
|
196
|
-
} catch
|
|
196
|
+
} catch {}
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
function createKey() {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-router v8.3.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
//#region lib/router/navigation.ts
|
|
12
|
+
const DEFAULT_NAVIGATION_URL = new URL("http://localhost");
|
|
13
|
+
function getNavigatorCurrentUrl(navigator) {
|
|
14
|
+
if (navigator.createURL) return navigator.createURL("/");
|
|
15
|
+
try {
|
|
16
|
+
return new URL(navigator.createHref("/"), DEFAULT_NAVIGATION_URL);
|
|
17
|
+
} catch {
|
|
18
|
+
return DEFAULT_NAVIGATION_URL;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isSameOrigin(a, b) {
|
|
22
|
+
return a.origin === b.origin && (a.origin !== "null" || a.protocol === b.protocol && a.host === b.host);
|
|
23
|
+
}
|
|
24
|
+
function isExplicitUrl(destination, target) {
|
|
25
|
+
if (destination.startsWith("//")) return true;
|
|
26
|
+
let protocol = target.protocol.toLowerCase();
|
|
27
|
+
if (!destination.toLowerCase().startsWith(protocol)) return false;
|
|
28
|
+
return target.host === "" || destination.slice(protocol.length).startsWith("//");
|
|
29
|
+
}
|
|
30
|
+
function validateNavigationTarget(original, resolved, currentUrl, externalPolicy) {
|
|
31
|
+
let originalUrl = null;
|
|
32
|
+
try {
|
|
33
|
+
originalUrl = original == null ? null : new URL(original, currentUrl);
|
|
34
|
+
} catch {}
|
|
35
|
+
let resolvedUrl = new URL(resolved, currentUrl);
|
|
36
|
+
let originalIsExternal = originalUrl != null && !isSameOrigin(originalUrl, currentUrl);
|
|
37
|
+
let resolvedIsExternal = !isSameOrigin(resolvedUrl, currentUrl);
|
|
38
|
+
if (externalPolicy === "reject") {
|
|
39
|
+
if (originalIsExternal || resolvedIsExternal) throw new Error("External navigation is not allowed");
|
|
40
|
+
} else if (resolvedIsExternal) {
|
|
41
|
+
if (originalUrl == null || !isExplicitUrl(original, originalUrl) || !isSameOrigin(originalUrl, resolvedUrl)) throw new Error("External navigation is not allowed");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { getNavigatorCurrentUrl, validateNavigationTarget };
|
|
@@ -128,6 +128,14 @@ interface Router {
|
|
|
128
128
|
* @param location
|
|
129
129
|
*/
|
|
130
130
|
createHref(location: Location | URL): string;
|
|
131
|
+
/**
|
|
132
|
+
* @private
|
|
133
|
+
* PRIVATE - DO NOT USE
|
|
134
|
+
*
|
|
135
|
+
* Utility function to create a URL for the given location
|
|
136
|
+
* @param location
|
|
137
|
+
*/
|
|
138
|
+
createURL?(to: To): URL;
|
|
131
139
|
/**
|
|
132
140
|
* @private
|
|
133
141
|
* PRIVATE - DO NOT USE
|