react-router 8.0.0-pre.0 → 8.0.0-pre.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 (168) hide show
  1. package/CHANGELOG.md +21 -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 +9 -2
  5. package/dist/development/index-react-server.js +91 -88
  6. package/dist/development/index.d.ts +1 -2
  7. package/dist/development/index.js +2 -3
  8. package/dist/development/lib/actions.js +6 -18
  9. package/dist/development/lib/components.d.ts +11 -3
  10. package/dist/development/lib/components.js +8 -2
  11. package/dist/development/lib/context.js +1 -1
  12. package/dist/development/lib/dom/dom.js +1 -1
  13. package/dist/development/lib/dom/lib.d.ts +12 -1
  14. package/dist/development/lib/dom/lib.js +18 -6
  15. package/dist/development/lib/dom/server.js +2 -2
  16. package/dist/development/lib/dom/ssr/components.d.ts +4 -2
  17. package/dist/development/lib/dom/ssr/components.js +13 -3
  18. package/dist/development/lib/dom/ssr/data.js +1 -1
  19. package/dist/development/lib/dom/ssr/entry.d.ts +1 -0
  20. package/dist/development/lib/dom/ssr/errorBoundaries.js +7 -3
  21. package/dist/development/lib/dom/ssr/fallback.js +8 -3
  22. package/dist/development/lib/dom/ssr/fog-of-war.js +12 -2
  23. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  24. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  25. package/dist/development/lib/dom/ssr/links.js +1 -1
  26. package/dist/development/lib/dom/ssr/markup.js +1 -1
  27. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  28. package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
  29. package/dist/development/lib/dom/ssr/routes.js +1 -1
  30. package/dist/development/lib/dom/ssr/server.d.ts +4 -1
  31. package/dist/development/lib/dom/ssr/server.js +2 -1
  32. package/dist/development/lib/dom/ssr/single-fetch.js +2 -3
  33. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  34. package/dist/development/lib/dom-export/hydrated-router.d.ts +1 -1
  35. package/dist/development/lib/dom-export/hydrated-router.js +14 -17
  36. package/dist/development/lib/errors.js +1 -1
  37. package/dist/development/lib/hooks.js +6 -4
  38. package/dist/development/lib/href.js +1 -1
  39. package/dist/development/lib/router/history.js +3 -2
  40. package/dist/development/lib/router/instrumentation.js +1 -1
  41. package/dist/development/lib/router/links.d.ts +3 -2
  42. package/dist/development/lib/router/router.js +13 -6
  43. package/dist/development/lib/router/url.js +18 -0
  44. package/dist/development/lib/router/utils.d.ts +6 -0
  45. package/dist/development/lib/router/utils.js +27 -8
  46. package/dist/development/lib/rsc/browser.js +21 -17
  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 +1 -1
  50. package/dist/development/lib/rsc/route-modules.js +1 -1
  51. package/dist/development/lib/rsc/server.ssr.js +27 -11
  52. package/dist/development/lib/server-runtime/cookies.js +1 -1
  53. package/dist/development/lib/server-runtime/crypto.js +1 -1
  54. package/dist/development/lib/server-runtime/data.js +1 -1
  55. package/dist/development/lib/server-runtime/dev.js +1 -1
  56. package/dist/development/lib/server-runtime/entry.js +1 -1
  57. package/dist/development/lib/server-runtime/errors.js +2 -22
  58. package/dist/development/lib/server-runtime/headers.js +1 -1
  59. package/dist/development/lib/server-runtime/invariant.js +1 -1
  60. package/dist/development/lib/server-runtime/mode.js +1 -1
  61. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  62. package/dist/development/lib/server-runtime/routes.js +1 -1
  63. package/dist/development/lib/server-runtime/server.js +17 -23
  64. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  65. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  66. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  67. package/dist/development/lib/server-runtime/sessions.js +1 -1
  68. package/dist/development/lib/server-runtime/single-fetch.js +4 -4
  69. package/dist/development/lib/server-runtime/urls.js +2 -5
  70. package/dist/development/lib/server-runtime/warnings.js +1 -1
  71. package/dist/development/lib/types/internal.js +1 -1
  72. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  73. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +2 -1
  74. package/dist/development/vendor/turbo-stream-v2/unflatten.js +3 -2
  75. package/dist/development/vendor/turbo-stream-v2/utils.js +2 -10
  76. package/dist/production/dom-export.js +1 -1
  77. package/dist/production/index-react-server-client.js +1 -1
  78. package/dist/production/index-react-server.d.ts +9 -2
  79. package/dist/production/index-react-server.js +91 -88
  80. package/dist/production/index.d.ts +1 -2
  81. package/dist/production/index.js +2 -3
  82. package/dist/production/lib/actions.js +6 -18
  83. package/dist/production/lib/components.d.ts +11 -3
  84. package/dist/production/lib/components.js +8 -2
  85. package/dist/production/lib/context.js +1 -1
  86. package/dist/production/lib/dom/dom.js +1 -1
  87. package/dist/production/lib/dom/lib.d.ts +12 -1
  88. package/dist/production/lib/dom/lib.js +18 -6
  89. package/dist/production/lib/dom/server.js +2 -2
  90. package/dist/production/lib/dom/ssr/components.d.ts +4 -2
  91. package/dist/production/lib/dom/ssr/components.js +13 -3
  92. package/dist/production/lib/dom/ssr/data.js +1 -1
  93. package/dist/production/lib/dom/ssr/entry.d.ts +1 -0
  94. package/dist/production/lib/dom/ssr/errorBoundaries.js +7 -3
  95. package/dist/production/lib/dom/ssr/fallback.js +3 -1
  96. package/dist/production/lib/dom/ssr/fog-of-war.js +12 -2
  97. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  98. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  99. package/dist/production/lib/dom/ssr/links.js +1 -1
  100. package/dist/production/lib/dom/ssr/markup.js +1 -1
  101. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  102. package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
  103. package/dist/production/lib/dom/ssr/routes.js +1 -1
  104. package/dist/production/lib/dom/ssr/server.d.ts +4 -1
  105. package/dist/production/lib/dom/ssr/server.js +2 -1
  106. package/dist/production/lib/dom/ssr/single-fetch.js +2 -3
  107. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  108. package/dist/production/lib/dom-export/hydrated-router.d.ts +1 -1
  109. package/dist/production/lib/dom-export/hydrated-router.js +14 -17
  110. package/dist/production/lib/errors.js +1 -1
  111. package/dist/production/lib/hooks.js +6 -4
  112. package/dist/production/lib/href.js +1 -1
  113. package/dist/production/lib/router/history.js +3 -2
  114. package/dist/production/lib/router/instrumentation.js +1 -1
  115. package/dist/production/lib/router/links.d.ts +3 -2
  116. package/dist/production/lib/router/router.js +13 -6
  117. package/dist/production/lib/router/url.js +18 -0
  118. package/dist/production/lib/router/utils.d.ts +6 -0
  119. package/dist/production/lib/router/utils.js +27 -8
  120. package/dist/production/lib/rsc/browser.js +21 -17
  121. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  122. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  123. package/dist/production/lib/rsc/html-stream/server.js +1 -1
  124. package/dist/production/lib/rsc/route-modules.js +1 -1
  125. package/dist/production/lib/rsc/server.ssr.js +27 -11
  126. package/dist/production/lib/server-runtime/cookies.js +1 -1
  127. package/dist/production/lib/server-runtime/crypto.js +1 -1
  128. package/dist/production/lib/server-runtime/data.js +1 -1
  129. package/dist/production/lib/server-runtime/dev.js +1 -1
  130. package/dist/production/lib/server-runtime/entry.js +1 -1
  131. package/dist/production/lib/server-runtime/errors.js +2 -22
  132. package/dist/production/lib/server-runtime/headers.js +1 -1
  133. package/dist/production/lib/server-runtime/invariant.js +1 -1
  134. package/dist/production/lib/server-runtime/mode.js +1 -1
  135. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  136. package/dist/production/lib/server-runtime/routes.js +1 -1
  137. package/dist/production/lib/server-runtime/server.js +17 -23
  138. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  139. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  140. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  141. package/dist/production/lib/server-runtime/sessions.js +1 -1
  142. package/dist/production/lib/server-runtime/single-fetch.js +4 -4
  143. package/dist/production/lib/server-runtime/urls.js +2 -5
  144. package/dist/production/lib/server-runtime/warnings.js +1 -1
  145. package/dist/production/lib/types/internal.js +1 -1
  146. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  147. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +2 -1
  148. package/dist/production/vendor/turbo-stream-v2/unflatten.js +3 -2
  149. package/dist/production/vendor/turbo-stream-v2/utils.js +2 -10
  150. package/docs/explanation/code-splitting.md +1 -1
  151. package/docs/explanation/index-query-param.md +2 -2
  152. package/docs/explanation/type-safety.md +1 -1
  153. package/docs/how-to/data-strategy.md +5 -5
  154. package/docs/how-to/error-reporting.md +10 -2
  155. package/docs/how-to/headers.md +2 -1
  156. package/docs/how-to/security.md +9 -7
  157. package/docs/start/data/installation.md +4 -0
  158. package/docs/start/data/route-object.md +20 -0
  159. package/docs/start/framework/actions.md +0 -1
  160. package/docs/start/framework/data-loading.md +1 -1
  161. package/docs/start/framework/deploying.md +4 -0
  162. package/docs/start/framework/installation.md +0 -1
  163. package/docs/upgrading/v6.md +3 -0
  164. package/package.json +2 -2
  165. package/dist/development/lib/dom/ssr/errors.d.ts +0 -7
  166. package/dist/development/lib/dom/ssr/errors.js +0 -36
  167. package/dist/production/lib/dom/ssr/errors.d.ts +0 -7
  168. package/dist/production/lib/dom/ssr/errors.js +0 -36
@@ -668,6 +668,8 @@ interface RouteMeta<RouteObjectType extends RouteObject = RouteObject> {
668
668
  caseSensitive: boolean;
669
669
  childrenIndex: number;
670
670
  route: RouteObjectType;
671
+ matcher?: RegExp;
672
+ compiledParams?: CompiledPathParam[];
671
673
  }
672
674
  /**
673
675
  * @private
@@ -752,6 +754,10 @@ interface PathMatch<ParamKey extends string = string> {
752
754
  * or `null` if it does not match.
753
755
  */
754
756
  declare function matchPath<Path extends string>(pattern: PathPattern<Path> | Path, pathname: string): PathMatch<ParamParseKey<Path>> | null;
757
+ type CompiledPathParam = {
758
+ paramName: string;
759
+ isOptional?: boolean;
760
+ };
755
761
  /**
756
762
  * Returns a resolved {@link Path} object relative to the given pathname.
757
763
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ import { ABSOLUTE_URL_REGEX, PROTOCOL_RELATIVE_URL_REGEX, normalizeProtocolRelativeUrl } from "./url.js";
11
12
  import { invariant, parsePath, warning } from "./history.js";
12
13
  import * as React$1 from "react";
13
14
  //#region lib/router/utils.ts
@@ -289,7 +290,14 @@ function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "",
289
290
  branches.push({
290
291
  path,
291
292
  score: computeScore(path, route.index),
292
- routesMeta
293
+ routesMeta: routesMeta.map((meta, i) => {
294
+ let [matcher, params] = compilePath(meta.relativePath, meta.caseSensitive, i === routesMeta.length - 1);
295
+ return {
296
+ ...meta,
297
+ matcher,
298
+ compiledParams: params
299
+ };
300
+ })
293
301
  });
294
302
  };
295
303
  routes.forEach((route, index) => {
@@ -340,11 +348,12 @@ function matchRouteBranch(branch, pathname, allowPartial = false) {
340
348
  let meta = routesMeta[i];
341
349
  let end = i === routesMeta.length - 1;
342
350
  let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
343
- let match = matchPath({
351
+ let pattern = {
344
352
  path: meta.relativePath,
345
353
  caseSensitive: meta.caseSensitive,
346
354
  end
347
- }, remainingPathname);
355
+ };
356
+ let match = meta.matcher && meta.compiledParams ? matchPathImpl(pattern, remainingPathname, meta.matcher, meta.compiledParams) : matchPath(pattern, remainingPathname);
348
357
  let route = meta.route;
349
358
  if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) match = matchPath({
350
359
  path: meta.relativePath,
@@ -418,6 +427,9 @@ function matchPath(pattern, pathname) {
418
427
  end: true
419
428
  };
420
429
  let [matcher, compiledParams] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
430
+ return matchPathImpl(pattern, pathname, matcher, compiledParams);
431
+ }
432
+ function matchPathImpl(pattern, pathname, matcher, compiledParams) {
421
433
  let match = pathname.match(matcher);
422
434
  if (!match) return null;
423
435
  let matchedPathname = match[0];
@@ -480,7 +492,6 @@ function stripBasename(pathname, basename) {
480
492
  function prependBasename({ basename, pathname }) {
481
493
  return pathname === "/" ? basename : joinPaths([basename, pathname]);
482
494
  }
483
- const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
484
495
  const isAbsoluteUrl = (url) => ABSOLUTE_URL_REGEX.test(url);
485
496
  /**
486
497
  * Returns a resolved {@link Path} object relative to the given pathname.
@@ -556,7 +567,7 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = fal
556
567
  if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) path.pathname += "/";
557
568
  return path;
558
569
  }
559
- const removeDoubleSlashes = (path) => path.replace(/\/\/+/g, "/");
570
+ const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
560
571
  const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
561
572
  const removeTrailingSlash = (path) => path.replace(/\/+$/, "");
562
573
  const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
@@ -709,6 +720,14 @@ const replace = (url, init) => {
709
720
  response.headers.set("X-Remix-Replace", "true");
710
721
  return response;
711
722
  };
723
+ const SUPPORTED_ERROR_TYPES = [
724
+ "EvalError",
725
+ "RangeError",
726
+ "ReferenceError",
727
+ "SyntaxError",
728
+ "TypeError",
729
+ "URIError"
730
+ ];
712
731
  var ErrorResponseImpl = class {
713
732
  status;
714
733
  statusText;
@@ -774,7 +793,7 @@ function parseToInfo(_to, basename) {
774
793
  let isExternal = false;
775
794
  if (isBrowser) try {
776
795
  let currentUrl = new URL(window.location.href);
777
- let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to);
796
+ let targetUrl = PROTOCOL_RELATIVE_URL_REGEX.test(to) ? new URL(normalizeProtocolRelativeUrl(to, currentUrl.protocol)) : new URL(to);
778
797
  let path = stripBasename(targetUrl.pathname, basename);
779
798
  if (targetUrl.origin === currentUrl.origin && path != null) to = path + targetUrl.search + targetUrl.hash;
780
799
  else isExternal = true;
@@ -788,4 +807,4 @@ function parseToInfo(_to, basename) {
788
807
  };
789
808
  }
790
809
  //#endregion
791
- export { ErrorResponseImpl, RouterContextProvider, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, data, decodePath, defaultMapRouteProperties, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, replace, resolvePath, resolveTo, stripBasename };
810
+ export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, 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 };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,15 +8,16 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ import { PROTOCOL_RELATIVE_URL_REGEX } from "../router/url.js";
11
12
  import { createBrowserHistory, invariant } from "../router/history.js";
12
- import { ErrorResponseImpl, createContext } from "../router/utils.js";
13
- import { createRouter, invalidProtocols, isMutationMethod } from "../router/router.js";
13
+ import { ErrorResponseImpl, createContext, resolvePath } from "../router/utils.js";
14
+ import { createRouter, hasInvalidProtocol, isMutationMethod } from "../router/router.js";
14
15
  import { RSCRouterContext } from "../context.js";
15
16
  import { RouterProvider } from "../components.js";
16
17
  import { createRequestInit } from "../dom/ssr/data.js";
17
18
  import { getSingleFetchDataStrategyImpl, singleFetchUrl, stripIndexParam } from "../dom/ssr/single-fetch.js";
18
19
  import { noActionDefinedError, shouldHydrateRouteLoader } from "../dom/ssr/routes.js";
19
- import "../dom/ssr/fog-of-war.js";
20
+ import { getPathsWithAncestors } from "../dom/ssr/fog-of-war.js";
20
21
  import { FrameworkContext, setIsHydrated } from "../dom/ssr/components.js";
21
22
  import { RSCRouterGlobalErrorBoundary } from "./errorBoundaries.js";
22
23
  import { populateRSCRouteModules } from "./route-modules.js";
@@ -80,13 +81,14 @@ function createCallServer({ createFromReadableStream, createTemporaryReferenceSe
80
81
  });
81
82
  React$1.startTransition(() => Promise.resolve(payloadPromise).then(async (payload) => {
82
83
  if (payload.type === "redirect") {
83
- if (payload.reload || isExternalLocation(payload.location)) {
84
- if (hasInvalidProtocol(payload.location)) throw new Error("Invalid redirect location");
85
- window.location.href = payload.location;
84
+ let location = normalizeRedirectLocation(payload.location);
85
+ if (payload.reload || isExternalLocation(location)) {
86
+ if (hasInvalidProtocol(location)) throw new Error("Invalid redirect location");
87
+ window.location.href = location;
86
88
  return;
87
89
  }
88
90
  React$1.startTransition(() => {
89
- globalVar.__reactRouterDataRouter.navigate(payload.location, { replace: payload.replace });
91
+ globalVar.__reactRouterDataRouter.navigate(location, { replace: payload.replace });
90
92
  });
91
93
  return;
92
94
  }
@@ -94,13 +96,14 @@ function createCallServer({ createFromReadableStream, createTemporaryReferenceSe
94
96
  const rerender = await payload.rerender;
95
97
  if (rerender && landedActionId < actionId && globalVar.__routerActionID <= actionId) {
96
98
  if (rerender.type === "redirect") {
97
- if (rerender.reload || isExternalLocation(rerender.location)) {
98
- if (hasInvalidProtocol(rerender.location)) throw new Error("Invalid redirect location");
99
- window.location.href = rerender.location;
99
+ let location = normalizeRedirectLocation(rerender.location);
100
+ if (rerender.reload || isExternalLocation(location)) {
101
+ if (hasInvalidProtocol(location)) throw new Error("Invalid redirect location");
102
+ window.location.href = location;
100
103
  return;
101
104
  }
102
105
  React$1.startTransition(() => {
103
- globalVar.__reactRouterDataRouter.navigate(rerender.location, { replace: rerender.replace });
106
+ globalVar.__reactRouterDataRouter.navigate(location, { replace: rerender.replace });
104
107
  });
105
108
  return;
106
109
  }
@@ -533,6 +536,7 @@ function getManifestUrl(paths) {
533
536
  return url;
534
537
  }
535
538
  async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, signal) {
539
+ paths = getPathsWithAncestors(paths);
536
540
  let url = getManifestUrl(paths);
537
541
  if (url == null) return;
538
542
  if (url.toString().length > 7680) {
@@ -568,12 +572,12 @@ function debounce(callback, wait) {
568
572
  function isExternalLocation(location) {
569
573
  return new URL(location, window.location.href).origin !== window.location.origin;
570
574
  }
571
- function hasInvalidProtocol(location) {
572
- try {
573
- return invalidProtocols.includes(new URL(location).protocol);
574
- } catch {
575
- return false;
575
+ function normalizeRedirectLocation(location) {
576
+ if (PROTOCOL_RELATIVE_URL_REGEX.test(location)) {
577
+ let path = resolvePath(location);
578
+ return path.pathname + path.search + path.hash;
576
579
  }
580
+ return location;
577
581
  }
578
582
  function cloneRoutes(routes) {
579
583
  if (!routes) return void 0;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -9,6 +9,7 @@
9
9
  * @license MIT
10
10
  */
11
11
  import { isRouteErrorResponse } from "../router/utils.js";
12
+ import { hasInvalidProtocol } from "../router/router.js";
12
13
  import { RSCRouterContext } from "../context.js";
13
14
  import { decodeRedirectErrorDigest, decodeRouteErrorResponseDigest } from "../errors.js";
14
15
  import { escapeHtml } from "../dom/ssr/markup.js";
@@ -122,6 +123,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
122
123
  if (!detectRedirectResponse.body) throw new Error("Failed to clone server response");
123
124
  const payload = await createFromReadableStream(detectRedirectResponse.body);
124
125
  if (serverResponse.status === 202 && payload.type === "redirect") {
126
+ if (hasInvalidProtocol(payload.location)) throw new Error("Invalid redirect location");
125
127
  const headers = new Headers(serverResponse.headers);
126
128
  headers.delete("Content-Encoding");
127
129
  headers.delete("Content-Length");
@@ -159,6 +161,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
159
161
  for (const [key, value] of serverResponse.headers) headers.append(key, value);
160
162
  headers.set("Content-Type", "text/html; charset=utf-8");
161
163
  if (renderRedirect) {
164
+ if (hasInvalidProtocol(renderRedirect.location)) throw new Error("Invalid redirect location");
162
165
  headers.set("Location", renderRedirect.location);
163
166
  return new Response(html, {
164
167
  status: renderRedirect.status,
@@ -166,7 +169,10 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
166
169
  });
167
170
  }
168
171
  const redirectTransform = new TransformStream({ flush(controller) {
169
- if (renderRedirect) controller.enqueue(new TextEncoder().encode(`<meta http-equiv="refresh" content="0;url=${escapeHtml(renderRedirect.location)}"/>`));
172
+ if (renderRedirect) {
173
+ if (hasInvalidProtocol(renderRedirect.location)) return;
174
+ controller.enqueue(new TextEncoder().encode(`<meta http-equiv="refresh" content="0;url=${escapeHtml(renderRedirect.location)}"/>`));
175
+ }
170
176
  } });
171
177
  if (!hydrate) return new Response(html.pipeThrough(redirectTransform), {
172
178
  status,
@@ -182,10 +188,13 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
182
188
  });
183
189
  } catch (error) {
184
190
  if (error instanceof Response) return error;
185
- if (renderRedirect) return new Response(`Redirect: ${renderRedirect.location}`, {
186
- status: renderRedirect.status,
187
- headers: { Location: renderRedirect.location }
188
- });
191
+ if (renderRedirect) {
192
+ if (hasInvalidProtocol(renderRedirect.location)) throw new Error("Invalid redirect location");
193
+ return new Response(`Redirect: ${renderRedirect.location}`, {
194
+ status: renderRedirect.status,
195
+ headers: { Location: renderRedirect.location }
196
+ });
197
+ }
189
198
  try {
190
199
  let normalizedError = renderError ?? error;
191
200
  let [status, statusText] = isRouteErrorResponse(normalizedError) ? [normalizedError.status, normalizedError.statusText] : [500, ""];
@@ -230,6 +239,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
230
239
  for (const [key, value] of serverResponse.headers) headers.append(key, value);
231
240
  headers.set("Content-Type", "text/html; charset=utf-8");
232
241
  if (retryRedirect) {
242
+ if (hasInvalidProtocol(retryRedirect.location)) throw new Error("Invalid redirect location");
233
243
  headers.set("Location", retryRedirect.location);
234
244
  return new Response(html, {
235
245
  status: retryRedirect.status,
@@ -237,7 +247,10 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
237
247
  });
238
248
  }
239
249
  const retryRedirectTransform = new TransformStream({ flush(controller) {
240
- if (retryRedirect) controller.enqueue(new TextEncoder().encode(`<meta http-equiv="refresh" content="0;url=${escapeHtml(retryRedirect.location)}"/>`));
250
+ if (retryRedirect) {
251
+ if (hasInvalidProtocol(retryRedirect.location)) return;
252
+ controller.enqueue(new TextEncoder().encode(`<meta http-equiv="refresh" content="0;url=${escapeHtml(retryRedirect.location)}"/>`));
253
+ }
241
254
  } });
242
255
  if (!hydrate) return new Response(html.pipeThrough(retryRedirectTransform), {
243
256
  status,
@@ -295,10 +308,13 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
295
308
  function RSCStaticRouter({ getPayload }) {
296
309
  const decoded = getPayload();
297
310
  const payload = React$1.use(decoded);
298
- if (payload.type === "redirect") throw new Response(null, {
299
- status: payload.status,
300
- headers: { Location: payload.location }
301
- });
311
+ if (payload.type === "redirect") {
312
+ if (hasInvalidProtocol(payload.location)) throw new Error("Invalid redirect location");
313
+ throw new Response(null, {
314
+ status: payload.status,
315
+ headers: { Location: payload.location }
316
+ });
317
+ }
302
318
  if (payload.type !== "render") return null;
303
319
  let patchedLoaderData = { ...payload.loaderData };
304
320
  for (const match of payload.matches) if (shouldHydrateRouteLoader(match.id, match.clientLoader, match.hasLoader, false) && (match.hydrateFallbackElement || !match.hasLoader)) delete patchedLoaderData[match.id];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,7 +8,6 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { isRouteErrorResponse } from "../router/utils.js";
12
11
  import "./mode.js";
13
12
  //#region lib/server-runtime/errors.ts
14
13
  /**
@@ -72,24 +71,5 @@ function serializeError(error, serverMode) {
72
71
  stack: sanitized.stack
73
72
  };
74
73
  }
75
- function serializeErrors(errors, serverMode) {
76
- if (!errors) return null;
77
- let entries = Object.entries(errors);
78
- let serialized = {};
79
- for (let [key, val] of entries) if (isRouteErrorResponse(val)) serialized[key] = {
80
- ...val,
81
- __type: "RouteErrorResponse"
82
- };
83
- else if (val instanceof Error) {
84
- let sanitized = sanitizeError(val, serverMode);
85
- serialized[key] = {
86
- message: sanitized.message,
87
- stack: sanitized.stack,
88
- __type: "Error",
89
- ...sanitized.name !== "Error" ? { __subType: sanitized.name } : {}
90
- };
91
- } else serialized[key] = val;
92
- return serialized;
93
- }
94
74
  //#endregion
95
- export { sanitizeError, sanitizeErrors, serializeError, serializeErrors };
75
+ export { sanitizeError, sanitizeErrors, serializeError };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,13 +8,13 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { ErrorResponseImpl, RouterContextProvider, defaultMapRouteProperties, isRouteErrorResponse, stripBasename } from "../router/utils.js";
11
+ import { ErrorResponseImpl, RouterContextProvider, defaultMapRouteProperties, isRouteErrorResponse, removeTrailingSlash, stripBasename } from "../router/utils.js";
12
12
  import { instrumentHandler } from "../router/instrumentation.js";
13
13
  import { createStaticHandler, getStaticContextFromError, isMutationMethod, isRedirectResponse, isResponse } from "../router/router.js";
14
14
  import { getManifestPath } from "../dom/ssr/fog-of-war.js";
15
15
  import { createEntryRouteModules } from "./entry.js";
16
16
  import { isServerMode } from "./mode.js";
17
- import { sanitizeErrors, serializeError, serializeErrors } from "./errors.js";
17
+ import { sanitizeErrors, serializeError } from "./errors.js";
18
18
  import { matchServerRoutes } from "./routeMatching.js";
19
19
  import { getBuildTimeHeader, getDevServerHooks } from "./dev.js";
20
20
  import { createStaticHandlerDataRoutes } from "./routes.js";
@@ -54,7 +54,7 @@ function derive(build, mode) {
54
54
  }
55
55
  loadContext = initialContext || new RouterContextProvider();
56
56
  let requestUrl = new URL(request.url);
57
- let normalizedPathname = getNormalizedPath(request, build.basename).pathname;
57
+ let normalizedPathname = getNormalizedPath(request).pathname;
58
58
  let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
59
59
  if (!build.ssr) {
60
60
  let decodedPath = decodeURI(normalizedPathname);
@@ -74,7 +74,7 @@ function derive(build, mode) {
74
74
  decodedPath = strippedPath;
75
75
  }
76
76
  if (build.prerender.length === 0) isSpaMode = true;
77
- else if (!build.prerender.includes(decodedPath) && !build.prerender.includes(decodedPath + "/")) if (requestUrl.pathname.endsWith(".data")) {
77
+ else if (!build.prerender.some((p) => removeTrailingSlash(p) === removeTrailingSlash(decodedPath))) if (requestUrl.pathname.endsWith(".data")) {
78
78
  errorHandler(new ErrorResponseImpl(404, "Not Found", `Refusing to SSR the path \`${decodedPath}\` because \`ssr:false\` is set and the path is not included in the \`prerender\` config, so in production the path will be a 404.`), {
79
79
  context: loadContext,
80
80
  params,
@@ -155,26 +155,20 @@ const createRequestHandler = (build, mode) => {
155
155
  };
156
156
  };
157
157
  async function handleManifestRequest(build, dataRoutes, branches, url) {
158
- if (build.assets.version !== url.searchParams.get("version")) return new Response(null, {
159
- status: 204,
160
- headers: { "X-Remix-Reload-Document": "true" }
161
- });
162
158
  if (url.toString().length > 7680) return new Response(null, {
163
159
  statusText: "Bad Request",
164
160
  status: 400
165
161
  });
162
+ if (build.assets.version !== url.searchParams.get("version")) return new Response(null, {
163
+ status: 204,
164
+ headers: { "X-Remix-Reload-Document": "true" }
165
+ });
166
166
  let patches = {};
167
167
  if (url.searchParams.has("paths")) {
168
- let paths = /* @__PURE__ */ new Set();
169
- (url.searchParams.get("paths") || "").split(",").filter(Boolean).forEach((path) => {
170
- if (!path.startsWith("/")) path = `/${path}`;
171
- let segments = path.split("/").slice(1);
172
- segments.forEach((_, i) => {
173
- let partialPath = segments.slice(0, i + 1).join("/");
174
- paths.add(`/${partialPath}`);
175
- });
176
- });
168
+ let pathParam = url.searchParams.get("paths") || "";
169
+ let paths = new Set(pathParam.split(",").filter(Boolean));
177
170
  for (let path of paths) {
171
+ if (!path.startsWith("/")) path = `/${path}`;
178
172
  let matches = matchServerRoutes(build.routes, dataRoutes, branches, path, build.basename);
179
173
  if (matches) for (let match of matches) {
180
174
  let routeId = match.route.id;
@@ -192,7 +186,7 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
192
186
  async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
193
187
  try {
194
188
  if (isMutationMethod(request.method)) try {
195
- throwIfPotentialCSRFAttack(request.headers, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
189
+ throwIfPotentialCSRFAttack(request, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
196
190
  } catch (e) {
197
191
  handleError(e);
198
192
  return new Response("Bad Request", { status: 400 });
@@ -209,7 +203,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
209
203
  return new Response(null, { status: 500 });
210
204
  }
211
205
  },
212
- normalizePath: (r) => getNormalizedPath(r, build.basename)
206
+ normalizePath: (r) => getNormalizedPath(r)
213
207
  });
214
208
  if (!isResponse(result)) result = await renderHtml(result, isSpaMode);
215
209
  return result;
@@ -232,7 +226,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
232
226
  let state = {
233
227
  loaderData: context.loaderData,
234
228
  actionData: context.actionData,
235
- errors: serializeErrors(context.errors, serverMode)
229
+ errors: context.errors
236
230
  };
237
231
  let baseServerHandoff = {
238
232
  basename: build.basename,
@@ -274,7 +268,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
274
268
  let state = {
275
269
  loaderData: context.loaderData,
276
270
  actionData: context.actionData,
277
- errors: serializeErrors(context.errors, serverMode)
271
+ errors: context.errors
278
272
  };
279
273
  entryContext = {
280
274
  ...entryContext,
@@ -304,7 +298,7 @@ async function handleResourceRequest(serverMode, build, staticHandler, routeId,
304
298
  return handleQueryRouteError(error);
305
299
  }
306
300
  },
307
- normalizePath: (r) => getNormalizedPath(r, build.basename)
301
+ normalizePath: (r) => getNormalizedPath(r)
308
302
  }));
309
303
  } catch (error) {
310
304
  return handleQueryRouteError(error);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.0.0-pre.0
2
+ * react-router v8.0.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -22,7 +22,7 @@ const SERVER_NO_BODY_STATUS_CODES = new Set([...NO_BODY_STATUS_CODES, 304]);
22
22
  async function singleFetchAction(build, serverMode, staticHandler, request, loadContext, handleError) {
23
23
  try {
24
24
  try {
25
- throwIfPotentialCSRFAttack(request.headers, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
25
+ throwIfPotentialCSRFAttack(request, Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []);
26
26
  } catch (e) {
27
27
  return handleQueryError(/* @__PURE__ */ new Error("Bad Request"), 400);
28
28
  }
@@ -37,7 +37,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, load
37
37
  return handleQueryError(error);
38
38
  }
39
39
  },
40
- normalizePath: (r) => getNormalizedPath(r, build.basename)
40
+ normalizePath: (r) => getNormalizedPath(r)
41
41
  }));
42
42
  } catch (error) {
43
43
  return handleQueryError(error);
@@ -90,7 +90,7 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, loa
90
90
  return handleQueryError(error);
91
91
  }
92
92
  },
93
- normalizePath: (r) => getNormalizedPath(r, build.basename)
93
+ normalizePath: (r) => getNormalizedPath(r)
94
94
  }));
95
95
  } catch (error) {
96
96
  return handleQueryError(error);