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.
Files changed (175) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/development/dom-export.js +1 -1
  3. package/dist/development/index-react-server-client.js +1 -1
  4. package/dist/development/index-react-server.d.ts +114 -17
  5. package/dist/development/index-react-server.js +189 -54
  6. package/dist/development/index.js +1 -1
  7. package/dist/development/lib/actions.js +10 -5
  8. package/dist/development/lib/components.js +6 -3
  9. package/dist/development/lib/context.d.ts +1 -0
  10. package/dist/development/lib/context.js +1 -1
  11. package/dist/development/lib/dom/dom.d.ts +24 -24
  12. package/dist/development/lib/dom/dom.js +26 -26
  13. package/dist/development/lib/dom/lib.d.ts +2 -1
  14. package/dist/development/lib/dom/lib.js +23 -7
  15. package/dist/development/lib/dom/server.js +1 -1
  16. package/dist/development/lib/dom/ssr/components.js +2 -2
  17. package/dist/development/lib/dom/ssr/data.js +1 -1
  18. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  19. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  20. package/dist/development/lib/dom/ssr/fog-of-war.js +27 -21
  21. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  22. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  23. package/dist/development/lib/dom/ssr/links.js +1 -1
  24. package/dist/development/lib/dom/ssr/markup.js +1 -1
  25. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  26. package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  27. package/dist/development/lib/dom/ssr/routes-test-stub.js +14 -1
  28. package/dist/development/lib/dom/ssr/routes.js +1 -1
  29. package/dist/development/lib/dom/ssr/server.js +1 -1
  30. package/dist/development/lib/dom/ssr/single-fetch.js +5 -5
  31. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  32. package/dist/development/lib/dom-export/hydrated-router.js +1 -1
  33. package/dist/development/lib/errors.js +1 -1
  34. package/dist/development/lib/hooks.js +6 -3
  35. package/dist/development/lib/href.d.ts +24 -8
  36. package/dist/development/lib/href.js +28 -11
  37. package/dist/development/lib/router/history.d.ts +6 -0
  38. package/dist/development/lib/router/history.js +8 -2
  39. package/dist/development/lib/router/instrumentation.js +1 -1
  40. package/dist/development/lib/router/navigation.js +45 -0
  41. package/dist/development/lib/router/router.d.ts +8 -0
  42. package/dist/development/lib/router/router.js +31 -17
  43. package/dist/development/lib/router/url.js +1 -1
  44. package/dist/development/lib/router/utils.d.ts +12 -0
  45. package/dist/development/lib/router/utils.js +66 -8
  46. package/dist/development/lib/rsc/browser.js +37 -24
  47. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  48. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  49. package/dist/development/lib/rsc/html-stream/server.js +30 -11
  50. package/dist/development/lib/rsc/route-modules.js +1 -1
  51. package/dist/development/lib/rsc/server.rsc.d.ts +5 -1
  52. package/dist/development/lib/rsc/server.ssr.d.ts +29 -6
  53. package/dist/development/lib/rsc/server.ssr.js +28 -13
  54. package/dist/development/lib/server-runtime/cookies.d.ts +28 -2
  55. package/dist/development/lib/server-runtime/cookies.js +18 -4
  56. package/dist/development/lib/server-runtime/crypto.js +2 -2
  57. package/dist/development/lib/server-runtime/data.js +1 -1
  58. package/dist/development/lib/server-runtime/dev.js +2 -2
  59. package/dist/development/lib/server-runtime/entry.js +1 -1
  60. package/dist/development/lib/server-runtime/errors.js +1 -1
  61. package/dist/development/lib/server-runtime/headers.js +1 -1
  62. package/dist/development/lib/server-runtime/invariant.js +1 -1
  63. package/dist/development/lib/server-runtime/mode.js +1 -1
  64. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  65. package/dist/development/lib/server-runtime/routes.js +1 -1
  66. package/dist/development/lib/server-runtime/server.d.ts +12 -0
  67. package/dist/development/lib/server-runtime/server.js +14 -2
  68. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  69. package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  70. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +9 -1
  71. package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  72. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +12 -6
  73. package/dist/development/lib/server-runtime/sessions.d.ts +31 -2
  74. package/dist/development/lib/server-runtime/sessions.js +20 -3
  75. package/dist/development/lib/server-runtime/single-fetch.js +2 -2
  76. package/dist/development/lib/server-runtime/urls.js +1 -1
  77. package/dist/development/lib/server-runtime/warnings.js +1 -1
  78. package/dist/development/lib/types/internal.js +1 -1
  79. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  80. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +4 -4
  81. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  82. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  83. package/dist/production/dom-export.js +1 -1
  84. package/dist/production/index-react-server-client.js +1 -1
  85. package/dist/production/index-react-server.d.ts +114 -17
  86. package/dist/production/index-react-server.js +189 -54
  87. package/dist/production/index.js +1 -1
  88. package/dist/production/lib/actions.js +10 -5
  89. package/dist/production/lib/components.js +6 -3
  90. package/dist/production/lib/context.d.ts +1 -0
  91. package/dist/production/lib/context.js +1 -1
  92. package/dist/production/lib/dom/dom.d.ts +24 -24
  93. package/dist/production/lib/dom/dom.js +26 -26
  94. package/dist/production/lib/dom/lib.d.ts +2 -1
  95. package/dist/production/lib/dom/lib.js +23 -7
  96. package/dist/production/lib/dom/server.js +1 -1
  97. package/dist/production/lib/dom/ssr/components.js +2 -2
  98. package/dist/production/lib/dom/ssr/data.js +1 -1
  99. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  100. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  101. package/dist/production/lib/dom/ssr/fog-of-war.js +27 -21
  102. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  103. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  104. package/dist/production/lib/dom/ssr/links.js +1 -1
  105. package/dist/production/lib/dom/ssr/markup.js +1 -1
  106. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  107. package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  108. package/dist/production/lib/dom/ssr/routes-test-stub.js +14 -1
  109. package/dist/production/lib/dom/ssr/routes.js +1 -1
  110. package/dist/production/lib/dom/ssr/server.js +1 -1
  111. package/dist/production/lib/dom/ssr/single-fetch.js +5 -5
  112. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  113. package/dist/production/lib/dom-export/hydrated-router.js +1 -1
  114. package/dist/production/lib/errors.js +1 -1
  115. package/dist/production/lib/hooks.js +6 -3
  116. package/dist/production/lib/href.d.ts +24 -8
  117. package/dist/production/lib/href.js +28 -11
  118. package/dist/production/lib/router/history.d.ts +6 -0
  119. package/dist/production/lib/router/history.js +8 -2
  120. package/dist/production/lib/router/instrumentation.js +1 -1
  121. package/dist/production/lib/router/navigation.js +45 -0
  122. package/dist/production/lib/router/router.d.ts +8 -0
  123. package/dist/production/lib/router/router.js +31 -17
  124. package/dist/production/lib/router/url.js +1 -1
  125. package/dist/production/lib/router/utils.d.ts +12 -0
  126. package/dist/production/lib/router/utils.js +66 -8
  127. package/dist/production/lib/rsc/browser.js +37 -24
  128. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  129. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  130. package/dist/production/lib/rsc/html-stream/server.js +30 -11
  131. package/dist/production/lib/rsc/route-modules.js +1 -1
  132. package/dist/production/lib/rsc/server.rsc.d.ts +5 -1
  133. package/dist/production/lib/rsc/server.ssr.d.ts +29 -6
  134. package/dist/production/lib/rsc/server.ssr.js +28 -13
  135. package/dist/production/lib/server-runtime/cookies.d.ts +28 -2
  136. package/dist/production/lib/server-runtime/cookies.js +18 -4
  137. package/dist/production/lib/server-runtime/crypto.js +2 -2
  138. package/dist/production/lib/server-runtime/data.js +1 -1
  139. package/dist/production/lib/server-runtime/dev.js +2 -2
  140. package/dist/production/lib/server-runtime/entry.js +1 -1
  141. package/dist/production/lib/server-runtime/errors.js +1 -1
  142. package/dist/production/lib/server-runtime/headers.js +1 -1
  143. package/dist/production/lib/server-runtime/invariant.js +1 -1
  144. package/dist/production/lib/server-runtime/mode.js +1 -1
  145. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  146. package/dist/production/lib/server-runtime/routes.js +1 -1
  147. package/dist/production/lib/server-runtime/server.d.ts +12 -0
  148. package/dist/production/lib/server-runtime/server.js +14 -2
  149. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  150. package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  151. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +9 -1
  152. package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  153. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +12 -6
  154. package/dist/production/lib/server-runtime/sessions.d.ts +31 -2
  155. package/dist/production/lib/server-runtime/sessions.js +20 -3
  156. package/dist/production/lib/server-runtime/single-fetch.js +2 -2
  157. package/dist/production/lib/server-runtime/urls.js +1 -1
  158. package/dist/production/lib/server-runtime/warnings.js +1 -1
  159. package/dist/production/lib/types/internal.js +1 -1
  160. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  161. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +4 -4
  162. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  163. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  164. package/docs/explanation/sessions-and-cookies.md +13 -13
  165. package/docs/explanation/state-management.md +2 -2
  166. package/docs/how-to/presets.md +2 -2
  167. package/docs/how-to/react-server-components.md +53 -1
  168. package/docs/how-to/security.md +8 -1
  169. package/docs/how-to/server-bundles.md +2 -2
  170. package/docs/start/data/route-object.md +2 -2
  171. package/docs/start/data/routing.md +1 -1
  172. package/docs/start/framework/pending-ui.md +1 -1
  173. package/docs/start/framework/route-module.md +8 -8
  174. package/docs/start/framework/routing.md +1 -1
  175. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -30,30 +30,30 @@ function shouldProcessLinkClick(event, target) {
30
30
  return event.button === 0 && (!target || target === "_self") && !isModifiedEvent(event);
31
31
  }
32
32
  /**
33
- Creates a URLSearchParams object using the given initializer.
34
-
35
- This is identical to `new URLSearchParams(init)` except it also
36
- supports arrays as values in the object form of the initializer
37
- instead of just strings. This is convenient when you need multiple
38
- values for a given key, but don't want to use an array initializer.
39
-
40
- For example, instead of:
41
-
42
- ```tsx
43
- let searchParams = new URLSearchParams([
44
- ['sort', 'name'],
45
- ['sort', 'price']
46
- ]);
47
- ```
48
- you can do:
49
-
50
- ```
51
- let searchParams = createSearchParams({
52
- sort: ['name', 'price']
53
- });
54
- ```
55
-
56
- @category Utils
33
+ * Creates a URLSearchParams object using the given initializer.
34
+ *
35
+ * This is identical to `new URLSearchParams(init)` except it also supports
36
+ * arrays as values in the object form of the initializer instead of just
37
+ * strings. This is convenient when you need multiple values for a given key,
38
+ * but don't want to use an array initializer.
39
+ *
40
+ * @example
41
+ * // Instead of:
42
+ * let searchParams = new URLSearchParams([
43
+ * ["sort", "name"],
44
+ * ["sort", "price"],
45
+ * ]);
46
+ *
47
+ * // You can do:
48
+ * let searchParams = createSearchParams({
49
+ * sort: ["name", "price"],
50
+ * });
51
+ *
52
+ * @public
53
+ * @category Utils
54
+ * @param init The value used to initialize the URL search parameters.
55
+ * @returns A URLSearchParams object containing the initialized search
56
+ * parameters.
57
57
  */
58
58
  function createSearchParams(init = "") {
59
59
  return new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo, key) => {
@@ -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 (e) {
78
+ } catch {
79
79
  _formDataSupportsSubmitter = true;
80
80
  }
81
81
  return _formDataSupportsSubmitter;
@@ -1409,7 +1409,8 @@ declare namespace ScrollRestoration {
1409
1409
  * for this navigation. To apply specific styles during the transition, see
1410
1410
  * {@link useViewTransitionState}. Defaults to `false`.
1411
1411
  * @param options.defaultShouldRevalidate Specify the default revalidation
1412
- * behavior for the navigation. Defaults to `true`.
1412
+ * behavior for the navigation. When not specified, loaders revalidate
1413
+ * according to the router's standard revalidation behavior.
1413
1414
  * @param options.mask Masked location to display in the browser instead
1414
1415
  * of the router location. Defaults to `undefined`.
1415
1416
  * @param options.useTransitions Wraps the navigation in
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
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.2.0";
26
- } catch (e) {}
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 (e) {}
126
+ } catch {}
127
127
  }
128
128
  if (serialized[key] == null) {
129
129
  let error = new Error(val.message);
@@ -386,7 +386,7 @@ const NavLink = React$1.forwardRef(function NavLinkWithRef({ "aria-current": ari
386
386
  if (nextLocationPathname && basename) nextLocationPathname = stripBasename(nextLocationPathname, basename) || nextLocationPathname;
387
387
  const endSlashPosition = toPathname !== "/" && toPathname.endsWith("/") ? toPathname.length - 1 : toPathname.length;
388
388
  let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(endSlashPosition) === "/";
389
- let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/");
389
+ let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(endSlashPosition) === "/");
390
390
  let renderProps = {
391
391
  isActive,
392
392
  isPending,
@@ -609,7 +609,8 @@ function useDataRouterState(hookName) {
609
609
  * for this navigation. To apply specific styles during the transition, see
610
610
  * {@link useViewTransitionState}. Defaults to `false`.
611
611
  * @param options.defaultShouldRevalidate Specify the default revalidation
612
- * behavior for the navigation. Defaults to `true`.
612
+ * behavior for the navigation. When not specified, loaders revalidate
613
+ * according to the router's standard revalidation behavior.
613
614
  * @param options.mask Masked location to display in the browser instead
614
615
  * of the router location. Defaults to `undefined`.
615
616
  * @param options.useTransitions Wraps the navigation in
@@ -795,6 +796,7 @@ function useSubmit() {
795
796
  if (options.navigate === false) await routerFetch(options.fetcherKey || getUniqueFetcherId(), currentRouteId, options.action || action, {
796
797
  defaultShouldRevalidate: options.defaultShouldRevalidate,
797
798
  preventScrollReset: options.preventScrollReset,
799
+ relative: options.relative,
798
800
  formData,
799
801
  body,
800
802
  formMethod: options.method || method,
@@ -804,6 +806,7 @@ function useSubmit() {
804
806
  else await routerNavigate(options.action || action, {
805
807
  defaultShouldRevalidate: options.defaultShouldRevalidate,
806
808
  preventScrollReset: options.preventScrollReset,
809
+ relative: options.relative,
807
810
  formData,
808
811
  body,
809
812
  formMethod: options.method || method,
@@ -1086,6 +1089,9 @@ function useScrollRestoration({ getKey, storageKey } = {}) {
1086
1089
  window.history.scrollRestoration = "auto";
1087
1090
  };
1088
1091
  }, []);
1092
+ usePageShow(React$1.useCallback((event) => {
1093
+ if (event.persisted) window.history.scrollRestoration = "manual";
1094
+ }, []));
1089
1095
  usePageHide(React$1.useCallback(() => {
1090
1096
  if (navigation.state === "idle") {
1091
1097
  let key = getScrollRestorationKey(location, matches, basename, getKey);
@@ -1110,7 +1116,7 @@ function useScrollRestoration({ getKey, storageKey } = {}) {
1110
1116
  try {
1111
1117
  let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY);
1112
1118
  if (sessionPositions) savedScrollPositions = JSON.parse(sessionPositions);
1113
- } catch (e) {}
1119
+ } catch {}
1114
1120
  }, [storageKey]);
1115
1121
  React$1.useLayoutEffect(() => {
1116
1122
  let disableScrollRestoration = router?.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey ? (location, matches) => getScrollRestorationKey(location, matches, basename, getKey) : void 0);
@@ -1178,6 +1184,16 @@ function usePageHide(callback, options) {
1178
1184
  };
1179
1185
  }, [callback, capture]);
1180
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
+ }
1181
1197
  /**
1182
1198
  * Wrapper around {@link useBlocker} to show a [`window.confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
1183
1199
  * prompt to users instead of building a custom UI with {@link useBlocker}.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
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 (e) {
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.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -110,6 +110,29 @@ function getManifestPath(_manifestPath, basename) {
110
110
  return basename == null ? manifestPath : joinPaths([basename, manifestPath]);
111
111
  }
112
112
  const MANIFEST_VERSION_STORAGE_KEY = "react-router-manifest-version";
113
+ async function handleClientVersionMismatch(needsReload, version, errorReloadPath) {
114
+ if (!needsReload) {
115
+ try {
116
+ sessionStorage.removeItem(MANIFEST_VERSION_STORAGE_KEY);
117
+ } catch {}
118
+ return false;
119
+ }
120
+ if (!errorReloadPath) {
121
+ console.warn("Detected a manifest version mismatch during eager route discovery. The next navigation/fetch to an undiscovered route will result in a new document navigation to sync up with the latest manifest.");
122
+ return true;
123
+ }
124
+ try {
125
+ if (sessionStorage.getItem(MANIFEST_VERSION_STORAGE_KEY) === version) {
126
+ console.error("Unable to discover routes due to manifest version mismatch.");
127
+ return true;
128
+ }
129
+ sessionStorage.setItem(MANIFEST_VERSION_STORAGE_KEY, version);
130
+ } catch {}
131
+ window.location.href = errorReloadPath;
132
+ console.warn("Detected manifest version mismatch, reloading...");
133
+ await new Promise(() => {});
134
+ return true;
135
+ }
113
136
  async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, routeModules, ssr, isSpaMode, basename, manifestPath, patchRoutes, signal) {
114
137
  paths = getPathsWithAncestors(paths);
115
138
  const searchParams = new URLSearchParams();
@@ -125,30 +148,13 @@ async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, ro
125
148
  try {
126
149
  let res = await fetch(url, { signal });
127
150
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
128
- else if (res.status === 204 && res.headers.has("X-Remix-Reload-Document")) {
129
- if (!errorReloadPath) {
130
- console.warn("Detected a manifest version mismatch during eager route discovery. The next navigation/fetch to an undiscovered route will result in a new document navigation to sync up with the latest manifest.");
131
- return;
132
- }
133
- try {
134
- if (sessionStorage.getItem(MANIFEST_VERSION_STORAGE_KEY) === manifest.version) {
135
- console.error("Unable to discover routes due to manifest version mismatch.");
136
- return;
137
- }
138
- sessionStorage.setItem(MANIFEST_VERSION_STORAGE_KEY, manifest.version);
139
- } catch {}
140
- window.location.href = errorReloadPath;
141
- console.warn("Detected manifest version mismatch, reloading...");
142
- await new Promise(() => {});
143
- } else if (res.status >= 400) throw new Error(await res.text());
144
- try {
145
- sessionStorage.removeItem(MANIFEST_VERSION_STORAGE_KEY);
146
- } catch {}
151
+ if (await handleClientVersionMismatch(res.status === 204 && res.headers.has("X-Remix-Reload-Document"), manifest.version, errorReloadPath)) return;
147
152
  serverPatches = await res.json();
148
153
  } catch (e) {
149
154
  if (signal?.aborted) return;
150
155
  throw e;
151
156
  }
157
+ if (signal?.aborted) return;
152
158
  let knownRoutes = new Set(Object.keys(manifest.routes));
153
159
  let patches = Object.values(serverPatches).reduce((acc, route) => {
154
160
  if (route && !knownRoutes.has(route.id)) acc[route.id] = route;
@@ -177,4 +183,4 @@ function debounce(callback, wait) {
177
183
  };
178
184
  }
179
185
  //#endregion
180
- export { URL_LIMIT, getManifestPath, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, isFogOfWarEnabled, useFogOFWarDiscovery };
186
+ export { URL_LIMIT, getManifestPath, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled, useFogOFWarDiscovery };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -50,7 +50,20 @@ interface RoutesTestStubProps {
50
50
  future?: Partial<FutureConfig>;
51
51
  }
52
52
  /**
53
+ * Creates a React component that renders the provided routes in a test-friendly
54
+ * React Router context.
55
+ *
56
+ * Use this to unit test components that rely on router context, such as
57
+ * `loaderData`, `actionData`, and route matches.
58
+ *
59
+ * @public
53
60
  * @category Utils
61
+ * @mode framework
62
+ * @mode data
63
+ * @param routes The route objects to render in the test router.
64
+ * @param _context An optional {@link RouterContextProvider} for supplying
65
+ * application context values to route middleware, loaders, and actions.
66
+ * @returns A React component that renders the test router.
54
67
  */
55
68
  declare function createRoutesStub(routes: StubRouteObject[], _context?: RouterContextProvider): ({
56
69
  initialEntries,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,7 +14,20 @@ import { FrameworkContext } from "./components.js";
14
14
  import * as React$1 from "react";
15
15
  //#region lib/dom/ssr/routes-test-stub.tsx
16
16
  /**
17
+ * Creates a React component that renders the provided routes in a test-friendly
18
+ * React Router context.
19
+ *
20
+ * Use this to unit test components that rely on router context, such as
21
+ * `loaderData`, `actionData`, and route matches.
22
+ *
23
+ * @public
17
24
  * @category Utils
25
+ * @mode framework
26
+ * @mode data
27
+ * @param routes The route objects to render in the test router.
28
+ * @param _context An optional {@link RouterContextProvider} for supplying
29
+ * application context values to route middleware, loaders, and actions.
30
+ * @returns A React component that renders the test router.
18
31
  */
19
32
  function createRoutesStub(routes, _context) {
20
33
  return function RoutesTestStub({ initialEntries, initialIndex, hydrationData, future }) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
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 (e) {}
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 (e) {
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 (e) {}
329
+ } catch {}
330
330
  };
331
331
  reject = async (error) => {
332
332
  rej(error);
333
333
  try {
334
334
  await promise;
335
- } catch (e) {}
335
+ } catch {}
336
336
  };
337
337
  });
338
338
  return {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
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,
@@ -687,7 +689,7 @@ var RenderErrorBoundary = class extends React$1.Component {
687
689
  };
688
690
  const errorRedirectHandledMap = /* @__PURE__ */ new WeakMap();
689
691
  function RSCErrorHandler({ children, error }) {
690
- let { basename } = React$1.useContext(NavigationContext);
692
+ let { basename, navigator } = React$1.useContext(NavigationContext);
691
693
  if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
692
694
  let redirect = decodeRedirectErrorDigest(error.digest);
693
695
  if (redirect) {
@@ -695,6 +697,7 @@ function RSCErrorHandler({ children, error }) {
695
697
  if (existingRedirect) throw existingRedirect;
696
698
  let parsed = parseToInfo(redirect.location, basename);
697
699
  let target = parsed.absoluteURL || parsed.to;
700
+ validateNavigationTarget(redirect.location, target, getNavigatorCurrentUrl(navigator), "allow-explicit");
698
701
  if (hasInvalidProtocol(target)) throw new Error("Invalid redirect location");
699
702
  if (isBrowser && !errorRedirectHandledMap.get(error)) if (parsed.isExternal || redirect.reloadDocument) window.location.href = target;
700
703
  else {
@@ -6,14 +6,30 @@ import { Pages } from "./types/register.js";
6
6
  type Args = { [K in keyof Pages]: ToArgs<Pages[K]["params"]> };
7
7
  type ToArgs<Params extends Record<string, string | undefined>> = Equal<Params, {}> extends true ? [] : Partial<Params> extends Params ? [Params] | [] : [Params];
8
8
  /**
9
- Returns a resolved URL path for the specified route.
10
-
11
- ```tsx
12
- const h = href("/:lang?/about", { lang: "en" })
13
- // -> `/en/about`
14
-
15
- <Link to={href("/products/:id", { id: "abc123" })} />
16
- ```
9
+ * Returns a resolved URL path for the specified route.
10
+ *
11
+ * Param values are percent-encoded for use in a path segment: characters that
12
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
13
+ * are escaped, while characters that RFC 3986 allows literally in a path
14
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
15
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
16
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
17
+ * preserving `/` separators.
18
+ *
19
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
20
+ *
21
+ * @example
22
+ * const h = href("/:lang?/about", { lang: "en" })
23
+ * // -> `/en/about`
24
+ *
25
+ * <Link to={href("/products/:id", { id: "abc123" })} />
26
+ *
27
+ * @public
28
+ * @category Utils
29
+ * @mode framework
30
+ * @param path The route path to resolve
31
+ * @param args The route params to use when resolving the path
32
+ * @returns The resolved URL path
17
33
  */
18
34
  declare function href<Path extends keyof Args>(path: Path, ...args: Args[Path]): string;
19
35
  //#endregion
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,19 +8,36 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ import { encodePathParam } from "./router/utils.js";
11
12
  //#region lib/href.ts
12
13
  function stringify(p) {
13
14
  return p == null ? "" : typeof p === "string" ? p : String(p);
14
15
  }
15
16
  /**
16
- Returns a resolved URL path for the specified route.
17
-
18
- ```tsx
19
- const h = href("/:lang?/about", { lang: "en" })
20
- // -> `/en/about`
21
-
22
- <Link to={href("/products/:id", { id: "abc123" })} />
23
- ```
17
+ * Returns a resolved URL path for the specified route.
18
+ *
19
+ * Param values are percent-encoded for use in a path segment: characters that
20
+ * would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
21
+ * are escaped, while characters that RFC 3986 allows literally in a path
22
+ * segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
23
+ * encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
24
+ * delimiters and must be escaped. Splat (`*`) values are encoded per segment,
25
+ * preserving `/` separators.
26
+ *
27
+ * See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
28
+ *
29
+ * @example
30
+ * const h = href("/:lang?/about", { lang: "en" })
31
+ * // -> `/en/about`
32
+ *
33
+ * <Link to={href("/products/:id", { id: "abc123" })} />
34
+ *
35
+ * @public
36
+ * @category Utils
37
+ * @mode framework
38
+ * @param path The route path to resolve
39
+ * @param args The route params to use when resolving the path
40
+ * @returns The resolved URL path
24
41
  */
25
42
  function href(path, ...args) {
26
43
  let params = args[0];
@@ -28,11 +45,11 @@ function href(path, ...args) {
28
45
  const isRequired = questionMark === void 0;
29
46
  const value = params?.[param];
30
47
  if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
31
- return value == null ? "" : "/" + encodeURIComponent(stringify(value));
48
+ return value == null ? "" : "/" + encodePathParam(stringify(value));
32
49
  });
33
50
  if (path.endsWith("*")) {
34
51
  const value = params?.["*"];
35
- if (value !== void 0) result += "/" + stringify(value).split("/").map(encodeURIComponent).join("/");
52
+ if (value !== void 0) result += "/" + stringify(value).split("/").map(encodePathParam).join("/");
36
53
  }
37
54
  return result || "/";
38
55
  }
@@ -236,7 +236,10 @@ declare function invariant<T>(value: T | null | undefined, message?: string): as
236
236
  /**
237
237
  * Creates a string URL path from the given pathname, search, and hash components.
238
238
  *
239
+ * @public
239
240
  * @category Utils
241
+ * @param path The pathname, search, and hash components to combine.
242
+ * @returns The combined URL path.
240
243
  */
241
244
  declare function createPath({
242
245
  pathname,
@@ -246,7 +249,10 @@ declare function createPath({
246
249
  /**
247
250
  * Parses a string URL path into its separate pathname, search, and hash components.
248
251
  *
252
+ * @public
249
253
  * @category Utils
254
+ * @param path The URL path to parse.
255
+ * @returns The parsed pathname, search, and hash components.
250
256
  */
251
257
  declare function parsePath(path: string): Partial<Path>;
252
258
  interface UrlHistory extends History {}