react-router 8.2.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 +78 -0
- 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 +114 -17
- package/dist/development/index-react-server.js +189 -54
- 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.d.ts +24 -24
- package/dist/development/lib/dom/dom.js +26 -26
- package/dist/development/lib/dom/lib.d.ts +2 -1
- package/dist/development/lib/dom/lib.js +23 -7
- 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 +27 -21
- 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.d.ts +13 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.js +14 -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.d.ts +24 -8
- package/dist/development/lib/href.js +28 -11
- package/dist/development/lib/router/history.d.ts +6 -0
- package/dist/development/lib/router/history.js +8 -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.d.ts +12 -0
- package/dist/development/lib/router/utils.js +66 -8
- package/dist/development/lib/rsc/browser.js +37 -24
- 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 +30 -11
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.rsc.d.ts +5 -1
- package/dist/development/lib/rsc/server.ssr.d.ts +29 -6
- package/dist/development/lib/rsc/server.ssr.js +28 -13
- package/dist/development/lib/server-runtime/cookies.d.ts +28 -2
- package/dist/development/lib/server-runtime/cookies.js +18 -4
- 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.d.ts +12 -0
- package/dist/development/lib/server-runtime/server.js +14 -2
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +9 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +12 -6
- package/dist/development/lib/server-runtime/sessions.d.ts +31 -2
- package/dist/development/lib/server-runtime/sessions.js +20 -3
- 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 +114 -17
- package/dist/production/index-react-server.js +189 -54
- 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.d.ts +24 -24
- package/dist/production/lib/dom/dom.js +26 -26
- package/dist/production/lib/dom/lib.d.ts +2 -1
- package/dist/production/lib/dom/lib.js +23 -7
- 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 +27 -21
- 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.d.ts +13 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.js +14 -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.d.ts +24 -8
- package/dist/production/lib/href.js +28 -11
- package/dist/production/lib/router/history.d.ts +6 -0
- package/dist/production/lib/router/history.js +8 -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.d.ts +12 -0
- package/dist/production/lib/router/utils.js +66 -8
- package/dist/production/lib/rsc/browser.js +37 -24
- 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 +30 -11
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.rsc.d.ts +5 -1
- package/dist/production/lib/rsc/server.ssr.d.ts +29 -6
- package/dist/production/lib/rsc/server.ssr.js +28 -13
- package/dist/production/lib/server-runtime/cookies.d.ts +28 -2
- package/dist/production/lib/server-runtime/cookies.js +18 -4
- 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.d.ts +12 -0
- package/dist/production/lib/server-runtime/server.js +14 -2
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +9 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +12 -6
- package/dist/production/lib/server-runtime/sessions.d.ts +31 -2
- package/dist/production/lib/server-runtime/sessions.js +20 -3
- 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/docs/explanation/sessions-and-cookies.md +13 -13
- package/docs/explanation/state-management.md +2 -2
- package/docs/how-to/presets.md +2 -2
- package/docs/how-to/react-server-components.md +53 -1
- package/docs/how-to/security.md +8 -1
- package/docs/how-to/server-bundles.md +2 -2
- package/docs/start/data/route-object.md +2 -2
- package/docs/start/data/routing.md +1 -1
- package/docs/start/framework/pending-ui.md +1 -1
- package/docs/start/framework/route-module.md +8 -8
- package/docs/start/framework/routing.md +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
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() {
|
|
@@ -231,7 +231,10 @@ function createLocation(current, to, state = null, key, mask) {
|
|
|
231
231
|
/**
|
|
232
232
|
* Creates a string URL path from the given pathname, search, and hash components.
|
|
233
233
|
*
|
|
234
|
+
* @public
|
|
234
235
|
* @category Utils
|
|
236
|
+
* @param path The pathname, search, and hash components to combine.
|
|
237
|
+
* @returns The combined URL path.
|
|
235
238
|
*/
|
|
236
239
|
function createPath({ pathname = "/", search = "", hash = "" }) {
|
|
237
240
|
if (search && search !== "?") pathname += search.charAt(0) === "?" ? search : "?" + search;
|
|
@@ -241,7 +244,10 @@ function createPath({ pathname = "/", search = "", hash = "" }) {
|
|
|
241
244
|
/**
|
|
242
245
|
* Parses a string URL path into its separate pathname, search, and hash components.
|
|
243
246
|
*
|
|
247
|
+
* @public
|
|
244
248
|
* @category Utils
|
|
249
|
+
* @param path The URL path to parse.
|
|
250
|
+
* @returns The parsed pathname, search, and hash components.
|
|
245
251
|
*/
|
|
246
252
|
function parsePath(path) {
|
|
247
253
|
let parsedPath = {};
|
|
@@ -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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -12,6 +12,7 @@ import { PROTOCOL_RELATIVE_URL_REGEX, normalizeProtocolRelativeUrl } from "./url
|
|
|
12
12
|
import { createBrowserURLImpl, createLocation, createPath, invariant, parsePath, warning } from "./history.js";
|
|
13
13
|
import { ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, flattenAndRankRoutes, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, matchRoutesImpl, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
|
|
14
14
|
import { consumeInstrumentationClientResultMetaReceiver, getRouteInstrumentationUpdates, instrumentClientSideRouter } from "./instrumentation.js";
|
|
15
|
+
import { validateNavigationTarget } from "./navigation.js";
|
|
15
16
|
//#region lib/router/router.ts
|
|
16
17
|
const validMutationMethodsArr = [
|
|
17
18
|
"POST",
|
|
@@ -412,21 +413,27 @@ function createRouter(init) {
|
|
|
412
413
|
let instrumentationNavigateMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
|
|
413
414
|
let { path, submission, error } = normalizeNavigateOptions(false, normalizeTo(state.location, state.matches, basename, to, opts?.fromRouteId, opts?.relative), opts);
|
|
414
415
|
let maskPath;
|
|
415
|
-
if (opts?.mask)
|
|
416
|
-
|
|
417
|
-
search: "",
|
|
418
|
-
hash: "",
|
|
419
|
-
...typeof opts.mask === "string" ? parsePath(opts.mask) : {
|
|
416
|
+
if (opts?.mask) {
|
|
417
|
+
let partialPath = typeof opts.mask === "string" ? parsePath(opts.mask) : {
|
|
420
418
|
...state.location.mask,
|
|
421
419
|
...opts.mask
|
|
422
|
-
}
|
|
423
|
-
|
|
420
|
+
};
|
|
421
|
+
maskPath = {
|
|
422
|
+
pathname: partialPath.pathname ?? "",
|
|
423
|
+
search: partialPath.search ?? "",
|
|
424
|
+
hash: partialPath.hash ?? ""
|
|
425
|
+
};
|
|
426
|
+
if (PROTOCOL_RELATIVE_URL_REGEX.test(maskPath.pathname)) throw new Error("External navigation is not allowed");
|
|
427
|
+
else if (maskPath.pathname.startsWith("\\")) maskPath.pathname = maskPath.pathname.replace(/^\\+/, "/");
|
|
428
|
+
validateNavigationTarget(typeof opts.mask === "string" ? opts.mask : createPath(opts.mask), createPath(maskPath), init.history.createURL("/"), "reject");
|
|
429
|
+
}
|
|
424
430
|
let currentLocation = state.location;
|
|
425
431
|
let nextLocation = createLocation(currentLocation, path, opts && opts.state, void 0, maskPath);
|
|
426
432
|
nextLocation = {
|
|
427
433
|
...nextLocation,
|
|
428
434
|
...init.history.encodeLocation(nextLocation)
|
|
429
435
|
};
|
|
436
|
+
validateNavigationTarget(to == null ? init.history.createHref(state.location) : typeof to === "string" ? to : createPath(to), init.history.createHref(nextLocation.mask || nextLocation), init.history.createURL("/"), "reject");
|
|
430
437
|
let userReplace = opts && opts.replace != null ? opts.replace : void 0;
|
|
431
438
|
let historyAction = "PUSH";
|
|
432
439
|
if (userReplace === true) historyAction = "REPLACE";
|
|
@@ -883,7 +890,10 @@ function createRouter(init) {
|
|
|
883
890
|
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
|
|
884
891
|
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
885
892
|
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext);
|
|
886
|
-
if (abortController.signal.aborted)
|
|
893
|
+
if (abortController.signal.aborted) {
|
|
894
|
+
if (fetchReloadIds.get(key) === loadId) fetchReloadIds.delete(key);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
887
897
|
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
888
898
|
fetchReloadIds.delete(key);
|
|
889
899
|
fetchControllers.delete(key);
|
|
@@ -1005,7 +1015,10 @@ function createRouter(init) {
|
|
|
1005
1015
|
if (redirect.response.headers.has("X-Remix-Revalidate")) isRevalidationRequired = true;
|
|
1006
1016
|
let location = redirect.response.headers.get("Location");
|
|
1007
1017
|
invariant(location, "Expected a Location header on the redirect Response");
|
|
1008
|
-
|
|
1018
|
+
let originalLocation = location;
|
|
1019
|
+
let currentUrl = new URL(request.url);
|
|
1020
|
+
location = normalizeRedirectLocation(location, currentUrl, basename, init.history);
|
|
1021
|
+
validateNavigationTarget(originalLocation, location, currentUrl, "allow-explicit");
|
|
1009
1022
|
let redirectLocation = createLocation(state.location, location, { _isRedirect: true });
|
|
1010
1023
|
if (isBrowser) {
|
|
1011
1024
|
let isDocumentReload = false;
|
|
@@ -1357,6 +1370,7 @@ function createRouter(init) {
|
|
|
1357
1370
|
fetch,
|
|
1358
1371
|
revalidate,
|
|
1359
1372
|
createHref: (to) => init.history.createHref(to),
|
|
1373
|
+
createURL: (to) => init.history.createURL(to),
|
|
1360
1374
|
encodeLocation: (to) => init.history.encodeLocation(to),
|
|
1361
1375
|
getFetcher,
|
|
1362
1376
|
resetFetcher,
|
|
@@ -1876,7 +1890,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1876
1890
|
text: void 0
|
|
1877
1891
|
}
|
|
1878
1892
|
};
|
|
1879
|
-
} catch
|
|
1893
|
+
} catch {
|
|
1880
1894
|
return getInvalidBodyError();
|
|
1881
1895
|
}
|
|
1882
1896
|
}
|
|
@@ -1899,7 +1913,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1899
1913
|
} else try {
|
|
1900
1914
|
searchParams = new URLSearchParams(opts.body);
|
|
1901
1915
|
formData = convertSearchParamsToFormData(searchParams);
|
|
1902
|
-
} catch
|
|
1916
|
+
} catch {
|
|
1903
1917
|
return getInvalidBodyError();
|
|
1904
1918
|
}
|
|
1905
1919
|
let submission = {
|
|
@@ -2415,7 +2429,7 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
|
|
|
2415
2429
|
});
|
|
2416
2430
|
try {
|
|
2417
2431
|
await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
|
|
2418
|
-
} catch
|
|
2432
|
+
} catch {}
|
|
2419
2433
|
return results;
|
|
2420
2434
|
}
|
|
2421
2435
|
async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
|
|
@@ -2598,7 +2612,7 @@ function normalizeRedirectLocation(location, currentUrl, basename, historyInstan
|
|
|
2598
2612
|
}
|
|
2599
2613
|
try {
|
|
2600
2614
|
if (hasInvalidProtocol(historyInstance.createURL(location).toString())) throw new Error("Invalid redirect location");
|
|
2601
|
-
} catch
|
|
2615
|
+
} catch {}
|
|
2602
2616
|
return location;
|
|
2603
2617
|
}
|
|
2604
2618
|
function createClientSideRequest(history, location, signal, submission) {
|
|
@@ -2948,7 +2962,7 @@ function restoreAppliedTransitions(_window, transitions) {
|
|
|
2948
2962
|
let json = JSON.parse(sessionPositions);
|
|
2949
2963
|
for (let [k, v] of Object.entries(json || {})) if (v && Array.isArray(v)) transitions.set(k, new Set(v || []));
|
|
2950
2964
|
}
|
|
2951
|
-
} catch
|
|
2965
|
+
} catch {}
|
|
2952
2966
|
}
|
|
2953
2967
|
function persistAppliedTransitions(_window, transitions) {
|
|
2954
2968
|
if (transitions.size > 0) {
|
|
@@ -2969,13 +2983,13 @@ function createDeferred() {
|
|
|
2969
2983
|
res(val);
|
|
2970
2984
|
try {
|
|
2971
2985
|
await promise;
|
|
2972
|
-
} catch
|
|
2986
|
+
} catch {}
|
|
2973
2987
|
};
|
|
2974
2988
|
reject = async (error) => {
|
|
2975
2989
|
rej(error);
|
|
2976
2990
|
try {
|
|
2977
2991
|
await promise;
|
|
2978
|
-
} catch
|
|
2992
|
+
} catch {}
|
|
2979
2993
|
};
|
|
2980
2994
|
});
|
|
2981
2995
|
return {
|
|
@@ -686,10 +686,22 @@ interface RouteBranch<RouteObjectType extends RouteObject = RouteObject> {
|
|
|
686
686
|
/**
|
|
687
687
|
* Returns a path with params interpolated.
|
|
688
688
|
*
|
|
689
|
+
* Param values are percent-encoded for use in a path segment: characters that
|
|
690
|
+
* would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
|
|
691
|
+
* are escaped, while characters that RFC 3986 allows literally in a path
|
|
692
|
+
* segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
|
|
693
|
+
* encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
|
|
694
|
+
* delimiters and must be escaped. Splat (`*`) values are encoded per segment,
|
|
695
|
+
* preserving `/` separators.
|
|
696
|
+
*
|
|
697
|
+
* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
|
|
698
|
+
*
|
|
689
699
|
* @example
|
|
690
700
|
* import { generatePath } from "react-router";
|
|
691
701
|
*
|
|
692
702
|
* generatePath("/users/:id", { id: "123" }); // "/users/123"
|
|
703
|
+
* generatePath("/files/:name", { name: "a b" }); // "/files/a%20b"
|
|
704
|
+
* generatePath("/releases/:v", { v: "1.0.0+1" }); // "/releases/1.0.0+1"
|
|
693
705
|
*
|
|
694
706
|
* @public
|
|
695
707
|
* @category Utils
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -375,12 +375,66 @@ function matchRouteBranch(branch, pathname, allowPartial = false) {
|
|
|
375
375
|
return matches;
|
|
376
376
|
}
|
|
377
377
|
/**
|
|
378
|
+
* Characters that `encodeURIComponent` escapes but that are valid literally in
|
|
379
|
+
* a URL path segment. Per RFC 3986 §3.3, a path segment is made of `pchar`:
|
|
380
|
+
*
|
|
381
|
+
* ```
|
|
382
|
+
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
383
|
+
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
|
384
|
+
* ```
|
|
385
|
+
*
|
|
386
|
+
* `encodeURIComponent` targets query-string values, where `$ & + , ; = : @`
|
|
387
|
+
* are delimiters and must be escaped — but in a path segment they carry no
|
|
388
|
+
* special meaning, and browsers keep them literal in `location.pathname`.
|
|
389
|
+
* (`! ' ( ) *` and the unreserved set are already left alone by
|
|
390
|
+
* `encodeURIComponent`, so they need no restoring.)
|
|
391
|
+
*/
|
|
392
|
+
const PATH_PARAM_OVERESCAPED = {
|
|
393
|
+
"%24": "$",
|
|
394
|
+
"%26": "&",
|
|
395
|
+
"%2B": "+",
|
|
396
|
+
"%2C": ",",
|
|
397
|
+
"%3A": ":",
|
|
398
|
+
"%3B": ";",
|
|
399
|
+
"%3D": "=",
|
|
400
|
+
"%40": "@"
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* Encodes a param value for interpolation into a single URL path segment.
|
|
404
|
+
*
|
|
405
|
+
* Escapes characters that would break the path (`/ ? # %`, whitespace,
|
|
406
|
+
* non-ASCII, …) while leaving characters that RFC 3986 permits literally in a
|
|
407
|
+
* path segment untouched. Escaping those would needlessly rewrite URLs — e.g.
|
|
408
|
+
* a semver build param `1.0.0+1` would become `1.0.0%2B1` even though browsers
|
|
409
|
+
* display and match the `+` literally in `location.pathname`.
|
|
410
|
+
*
|
|
411
|
+
* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3))
|
|
412
|
+
*
|
|
413
|
+
* @param value The param value to encode.
|
|
414
|
+
* @returns The encoded value, safe for use as a single path segment.
|
|
415
|
+
*/
|
|
416
|
+
function encodePathParam(value) {
|
|
417
|
+
return encodeURIComponent(value).replace(/%(?:24|26|2B|2C|3A|3B|3D|40)/g, (match) => PATH_PARAM_OVERESCAPED[match]);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
378
420
|
* Returns a path with params interpolated.
|
|
379
421
|
*
|
|
422
|
+
* Param values are percent-encoded for use in a path segment: characters that
|
|
423
|
+
* would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
|
|
424
|
+
* are escaped, while characters that RFC 3986 allows literally in a path
|
|
425
|
+
* segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
|
|
426
|
+
* encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
|
|
427
|
+
* delimiters and must be escaped. Splat (`*`) values are encoded per segment,
|
|
428
|
+
* preserving `/` separators.
|
|
429
|
+
*
|
|
430
|
+
* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
|
|
431
|
+
*
|
|
380
432
|
* @example
|
|
381
433
|
* import { generatePath } from "react-router";
|
|
382
434
|
*
|
|
383
435
|
* generatePath("/users/:id", { id: "123" }); // "/users/123"
|
|
436
|
+
* generatePath("/files/:name", { name: "a b" }); // "/files/a%20b"
|
|
437
|
+
* generatePath("/releases/:v", { v: "1.0.0+1" }); // "/releases/1.0.0+1"
|
|
384
438
|
*
|
|
385
439
|
* @public
|
|
386
440
|
* @category Utils
|
|
@@ -403,7 +457,7 @@ function generatePath(originalPath, params = {}) {
|
|
|
403
457
|
const [, key, optional, suffix] = keyMatch;
|
|
404
458
|
let param = params[key];
|
|
405
459
|
invariant(optional === "?" || param != null, `Missing ":${key}" param`);
|
|
406
|
-
return
|
|
460
|
+
return encodePathParam(stringify(param)) + suffix;
|
|
407
461
|
}
|
|
408
462
|
return segment.replace(/\?$/g, "");
|
|
409
463
|
}).filter((segment) => !!segment).join("/");
|
|
@@ -435,13 +489,13 @@ function matchPathImpl(pattern, pathname, matcher, compiledParams) {
|
|
|
435
489
|
let match = pathname.match(matcher);
|
|
436
490
|
if (!match) return null;
|
|
437
491
|
let matchedPathname = match[0];
|
|
438
|
-
let pathnameBase = matchedPathname
|
|
492
|
+
let pathnameBase = removeTrailingSlash(matchedPathname, 1);
|
|
439
493
|
let captureGroups = match.slice(1);
|
|
440
494
|
return {
|
|
441
495
|
params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
|
|
442
496
|
if (paramName === "*") {
|
|
443
497
|
let splatValue = captureGroups[index] || "";
|
|
444
|
-
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length)
|
|
498
|
+
pathnameBase = removeTrailingSlash(matchedPathname.slice(0, matchedPathname.length - splatValue.length), 1);
|
|
445
499
|
}
|
|
446
500
|
const value = captureGroups[index];
|
|
447
501
|
if (isOptional && !value) memo[paramName] = void 0;
|
|
@@ -510,7 +564,7 @@ function resolvePath(to, fromPathname = "/") {
|
|
|
510
564
|
let pathname;
|
|
511
565
|
if (toPathname) {
|
|
512
566
|
toPathname = removeDoubleSlashes(toPathname);
|
|
513
|
-
if (toPathname.startsWith("/")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
567
|
+
if (toPathname.startsWith("/") || toPathname.startsWith("\\")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
514
568
|
else pathname = resolvePathname(toPathname, fromPathname);
|
|
515
569
|
} else pathname = fromPathname;
|
|
516
570
|
return {
|
|
@@ -571,7 +625,11 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = fal
|
|
|
571
625
|
}
|
|
572
626
|
const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
|
|
573
627
|
const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
|
|
574
|
-
|
|
628
|
+
function removeTrailingSlash(path, minLength = 0) {
|
|
629
|
+
let end = path.length;
|
|
630
|
+
while (end > minLength && path.charCodeAt(end - 1) === 47) end--;
|
|
631
|
+
return end === path.length ? path : path.slice(0, end);
|
|
632
|
+
}
|
|
575
633
|
const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
|
|
576
634
|
const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
577
635
|
const normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
|
@@ -814,7 +872,7 @@ function parseToInfo(_to, basename) {
|
|
|
814
872
|
let path = stripBasename(targetUrl.pathname, basename);
|
|
815
873
|
if (targetUrl.origin === currentUrl.origin && path != null) to = path + targetUrl.search + targetUrl.hash;
|
|
816
874
|
else isExternal = true;
|
|
817
|
-
} catch
|
|
875
|
+
} catch {
|
|
818
876
|
warning(false, `<Link to="${to}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`);
|
|
819
877
|
}
|
|
820
878
|
return {
|
|
@@ -824,4 +882,4 @@ function parseToInfo(_to, basename) {
|
|
|
824
882
|
};
|
|
825
883
|
}
|
|
826
884
|
//#endregion
|
|
827
|
-
export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
|
|
885
|
+
export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
import { PROTOCOL_RELATIVE_URL_REGEX } from "../router/url.js";
|
|
12
|
-
import { createBrowserHistory, invariant } from "../router/history.js";
|
|
12
|
+
import { createBrowserHistory, createPath, invariant } from "../router/history.js";
|
|
13
13
|
import { ErrorResponseImpl, createContext, resolvePath } from "../router/utils.js";
|
|
14
|
+
import { validateNavigationTarget } from "../router/navigation.js";
|
|
14
15
|
import { createRouter, hasInvalidProtocol, isMutationMethod } from "../router/router.js";
|
|
15
16
|
import { RSCRouterContext } from "../context.js";
|
|
16
17
|
import { RouterProvider } from "../components.js";
|
|
17
18
|
import { createRequestInit } from "../dom/ssr/data.js";
|
|
18
19
|
import { getSingleFetchDataStrategyImpl, singleFetchUrl, stripIndexParam } from "../dom/ssr/single-fetch.js";
|
|
19
20
|
import { noActionDefinedError, shouldHydrateRouteLoader } from "../dom/ssr/routes.js";
|
|
20
|
-
import { getPathsWithAncestors } from "../dom/ssr/fog-of-war.js";
|
|
21
|
+
import { getPathsWithAncestors, handleClientVersionMismatch } from "../dom/ssr/fog-of-war.js";
|
|
21
22
|
import { FrameworkContext, setIsHydrated } from "../dom/ssr/components.js";
|
|
22
23
|
import { RSCRouterGlobalErrorBoundary } from "./errorBoundaries.js";
|
|
23
24
|
import { populateRSCRouteModules } from "./route-modules.js";
|
|
@@ -82,6 +83,7 @@ function createCallServer({ createFromReadableStream, createTemporaryReferenceSe
|
|
|
82
83
|
React$1.startTransition(() => Promise.resolve(payloadPromise).then(async (payload) => {
|
|
83
84
|
if (payload.type === "redirect") {
|
|
84
85
|
let location = normalizeRedirectLocation(payload.location);
|
|
86
|
+
validateNavigationTarget(payload.location, location, new URL(window.location.href), "allow-explicit");
|
|
85
87
|
if (payload.reload || isExternalLocation(location)) {
|
|
86
88
|
if (hasInvalidProtocol(location)) throw new Error("Invalid redirect location");
|
|
87
89
|
window.location.href = location;
|
|
@@ -97,6 +99,7 @@ function createCallServer({ createFromReadableStream, createTemporaryReferenceSe
|
|
|
97
99
|
if (rerender && landedActionId < actionId && globalVar.__routerActionID <= actionId) {
|
|
98
100
|
if (rerender.type === "redirect") {
|
|
99
101
|
let location = normalizeRedirectLocation(rerender.location);
|
|
102
|
+
validateNavigationTarget(rerender.location, location, new URL(window.location.href), "allow-explicit");
|
|
100
103
|
if (rerender.reload || isExternalLocation(location)) {
|
|
101
104
|
if (hasInvalidProtocol(location)) throw new Error("Invalid redirect location");
|
|
102
105
|
window.location.href = location;
|
|
@@ -133,6 +136,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
133
136
|
routeModules: globalVar.__reactRouterRouteModules
|
|
134
137
|
};
|
|
135
138
|
if (payload.type !== "render") throw new Error("Invalid payload type");
|
|
139
|
+
let { clientVersion } = payload;
|
|
136
140
|
globalVar.__reactRouterRouteModules = globalVar.__reactRouterRouteModules ?? {};
|
|
137
141
|
populateRSCRouteModules(globalVar.__reactRouterRouteModules, payload.matches);
|
|
138
142
|
let routes = payload.matches.reduceRight((previous, match) => {
|
|
@@ -167,7 +171,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
167
171
|
basename: payload.basename,
|
|
168
172
|
isSpaMode: false
|
|
169
173
|
}),
|
|
170
|
-
async patchRoutesOnNavigation({ path, signal }) {
|
|
174
|
+
async patchRoutesOnNavigation({ path, signal, fetcherKey }) {
|
|
171
175
|
if (payload.routeDiscovery.mode === "initial") {
|
|
172
176
|
if (!applyPatchesPromise) applyPatchesPromise = (async () => {
|
|
173
177
|
if (!payload.patches) return;
|
|
@@ -182,9 +186,10 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
182
186
|
return;
|
|
183
187
|
}
|
|
184
188
|
if (discoveredPaths.has(path)) return;
|
|
185
|
-
|
|
189
|
+
let { state } = globalVar.__reactRouterDataRouter;
|
|
190
|
+
await fetchAndApplyManifestPatches([path], createFromReadableStream, fetchImplementation, clientVersion, fetcherKey ? window.location.href : createPath(state.navigation.location || state.location), signal);
|
|
186
191
|
},
|
|
187
|
-
dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation)
|
|
192
|
+
dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation, clientVersion)
|
|
188
193
|
});
|
|
189
194
|
if (globalVar.__reactRouterDataRouter.state.initialized) {
|
|
190
195
|
globalVar.__routerInitialized = true;
|
|
@@ -237,19 +242,16 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
237
242
|
};
|
|
238
243
|
}
|
|
239
244
|
const renderedRoutesContext = createContext();
|
|
240
|
-
function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation) {
|
|
245
|
+
function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation, clientVersion) {
|
|
241
246
|
let dataStrategy = getSingleFetchDataStrategyImpl(getRouter, (match) => {
|
|
242
247
|
let M = match;
|
|
243
248
|
return {
|
|
244
249
|
hasLoader: M.route.hasLoader,
|
|
245
|
-
hasClientLoader: M.route.hasClientLoader
|
|
246
|
-
hasComponent: M.route.hasComponent,
|
|
247
|
-
hasAction: M.route.hasAction,
|
|
248
|
-
hasClientAction: M.route.hasClientAction
|
|
250
|
+
hasClientLoader: M.route.hasClientLoader
|
|
249
251
|
};
|
|
250
|
-
}, getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation), ssr, (match) => {
|
|
252
|
+
}, getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion), ssr, (match) => {
|
|
251
253
|
let M = match;
|
|
252
|
-
return M.route.hasComponent
|
|
254
|
+
return !M.route.hasComponent || M.route.element != null;
|
|
253
255
|
});
|
|
254
256
|
return async (args) => args.runClientMiddleware(async () => {
|
|
255
257
|
args.context.set(renderedRoutesContext, []);
|
|
@@ -268,7 +270,7 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream,
|
|
|
268
270
|
return results;
|
|
269
271
|
});
|
|
270
272
|
}
|
|
271
|
-
function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation) {
|
|
273
|
+
function getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion) {
|
|
272
274
|
return async (args, targetRoutes) => {
|
|
273
275
|
let { request, context } = args;
|
|
274
276
|
let url = singleFetchUrl(request.url, "rsc");
|
|
@@ -292,6 +294,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
|
|
|
292
294
|
} }
|
|
293
295
|
};
|
|
294
296
|
if (payload.type !== "render") throw new Error("Unexpected payload type");
|
|
297
|
+
if (clientVersion !== void 0 && await handleClientVersionMismatch(payload.clientVersion !== clientVersion, clientVersion, createPath(getRouter().state.navigation.location || getRouter().state.location))) return new Promise(() => {});
|
|
295
298
|
context.get(renderedRoutesContext).push(...payload.matches);
|
|
296
299
|
let results = { routes: {} };
|
|
297
300
|
const dataKey = isMutationMethod(request.method) ? "actionData" : "loaderData";
|
|
@@ -347,7 +350,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
|
|
|
347
350
|
*/
|
|
348
351
|
function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementation = fetch, payload, getContext }) {
|
|
349
352
|
if (payload.type !== "render") throw new Error("Invalid payload type");
|
|
350
|
-
let { routeDiscovery } = payload;
|
|
353
|
+
let { routeDiscovery, clientVersion } = payload;
|
|
351
354
|
let { router, routeModules } = React$1.useMemo(() => createRouterFromPayload({
|
|
352
355
|
payload,
|
|
353
356
|
fetchImplementation,
|
|
@@ -413,7 +416,7 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
|
|
|
413
416
|
});
|
|
414
417
|
if (paths.length === 0) return;
|
|
415
418
|
try {
|
|
416
|
-
await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation);
|
|
419
|
+
await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, null);
|
|
417
420
|
} catch (e) {
|
|
418
421
|
console.error("Failed to fetch manifest patches", e);
|
|
419
422
|
}
|
|
@@ -433,7 +436,8 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
|
|
|
433
436
|
}, [
|
|
434
437
|
routeDiscovery,
|
|
435
438
|
createFromReadableStream,
|
|
436
|
-
fetchImplementation
|
|
439
|
+
fetchImplementation,
|
|
440
|
+
clientVersion
|
|
437
441
|
]);
|
|
438
442
|
const frameworkContext = {
|
|
439
443
|
future: {},
|
|
@@ -506,6 +510,7 @@ function createRouteFromServerManifest(match, payload) {
|
|
|
506
510
|
shouldRevalidate: match.shouldRevalidate,
|
|
507
511
|
hasLoader: true,
|
|
508
512
|
hasClientLoader: match.clientLoader != null,
|
|
513
|
+
hasComponent: match.hasComponent,
|
|
509
514
|
hasAction: match.hasAction,
|
|
510
515
|
hasClientAction: match.clientAction != null
|
|
511
516
|
};
|
|
@@ -526,23 +531,31 @@ function preventInvalidServerHandlerCall(type, routeId, hasHandler) {
|
|
|
526
531
|
const nextPaths = /* @__PURE__ */ new Set();
|
|
527
532
|
const discoveredPathsMaxSize = 1e3;
|
|
528
533
|
const discoveredPaths = /* @__PURE__ */ new Set();
|
|
529
|
-
function getManifestUrl(paths) {
|
|
534
|
+
function getManifestUrl(paths, clientVersion) {
|
|
530
535
|
if (paths.length === 0) return null;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
536
|
+
let url;
|
|
537
|
+
if (paths.length === 1) url = new URL(`${paths[0]}.manifest`, window.location.origin);
|
|
538
|
+
else {
|
|
539
|
+
let basename = (window.__reactRouterDataRouter.basename ?? "").replace(/^\/|\/$/g, "");
|
|
540
|
+
url = new URL(`${basename}/.manifest`, window.location.origin);
|
|
541
|
+
url.searchParams.set("paths", paths.sort().join(","));
|
|
542
|
+
}
|
|
543
|
+
if (clientVersion !== void 0) url.searchParams.set("version", clientVersion);
|
|
535
544
|
return url;
|
|
536
545
|
}
|
|
537
|
-
async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, signal) {
|
|
546
|
+
async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, errorReloadPath, signal) {
|
|
538
547
|
paths = getPathsWithAncestors(paths);
|
|
539
|
-
let url = getManifestUrl(paths);
|
|
548
|
+
let url = getManifestUrl(paths, clientVersion);
|
|
540
549
|
if (url == null) return;
|
|
541
550
|
if (url.toString().length > 7680) {
|
|
542
551
|
nextPaths.clear();
|
|
543
552
|
return;
|
|
544
553
|
}
|
|
545
554
|
let response = await fetchImplementation(new Request(url, { signal }));
|
|
555
|
+
if (clientVersion !== void 0 && response.status === 204 && response.headers.has("X-Remix-Reload-Document")) {
|
|
556
|
+
await handleClientVersionMismatch(true, clientVersion, errorReloadPath);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
546
559
|
if (!response.body || response.status < 200 || response.status >= 300) throw new Error("Unable to fetch new route matches from the server");
|
|
547
560
|
let payload = await createFromReadableStream(response.body, { temporaryReferences: void 0 });
|
|
548
561
|
if (payload.type !== "manifest") throw new Error("Failed to patch routes");
|