react-router 7.17.0 → 7.18.0

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 (77) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/development/{browser-D3uq9sI1.d.ts → browser-B2PdsXXH.d.ts} +2 -2
  3. package/dist/development/{browser-CGcs-0pD.d.mts → browser-DBmQ1yAR.d.mts} +2 -2
  4. package/dist/development/{chunk-6CSD65Y2.mjs → chunk-4ZMWKKQ3.mjs} +115 -38
  5. package/dist/{production/chunk-5TQZEVD5.mjs → development/chunk-E4MTK73K.mjs} +45 -113
  6. package/dist/development/{chunk-KFNXW4AL.js → chunk-U7ORXROY.js} +113 -35
  7. package/dist/development/{chunk-PBLBZ3QU.js → chunk-WW7PN6QI.js} +7 -7
  8. package/dist/development/{chunk-PULC7NLK.js → chunk-YL5M26XI.js} +111 -108
  9. package/dist/{production/context-CmHpk1Ws.d.mts → development/context-CeD5LmaF.d.mts} +12 -4
  10. package/dist/{production/data-D4xhSy90.d.ts → development/data-CjO11-hU.d.ts} +9 -1
  11. package/dist/development/{data-U8FS-wNn.d.mts → data-DEjBmEfD.d.mts} +9 -1
  12. package/dist/development/dom-export.d.mts +3 -3
  13. package/dist/development/dom-export.d.ts +3 -3
  14. package/dist/development/dom-export.js +46 -44
  15. package/dist/development/dom-export.mjs +23 -21
  16. package/dist/development/{index-react-server-client-CwU9bE5R.d.ts → index-react-server-client-3ykjivgQ.d.ts} +29 -7
  17. package/dist/development/{index-react-server-client-DPrDrCew.d.mts → index-react-server-client-CACgcj2J.d.mts} +19 -5
  18. package/dist/development/index-react-server-client.d.mts +3 -3
  19. package/dist/development/index-react-server-client.d.ts +3 -3
  20. package/dist/development/index-react-server-client.js +4 -4
  21. package/dist/development/index-react-server-client.mjs +2 -2
  22. package/dist/development/index-react-server.d.mts +9 -1
  23. package/dist/development/index-react-server.d.ts +9 -1
  24. package/dist/development/index-react-server.js +144 -121
  25. package/dist/development/index-react-server.mjs +143 -120
  26. package/dist/development/index.d.mts +15 -14
  27. package/dist/development/index.d.ts +15 -14
  28. package/dist/development/index.js +137 -205
  29. package/dist/development/index.mjs +3 -5
  30. package/dist/{production/instrumentation-1q4YhLGP.d.ts → development/instrumentation-Dkmpzd13.d.ts} +2 -2
  31. package/dist/development/lib/types/internal.d.mts +2 -2
  32. package/dist/development/lib/types/internal.d.ts +2 -2
  33. package/dist/development/lib/types/internal.js +1 -1
  34. package/dist/development/lib/types/internal.mjs +1 -1
  35. package/dist/development/{register-CqK96Zfk.d.mts → register-CmkRspdl.d.mts} +1 -1
  36. package/dist/development/{register-CNAx3TXj.d.ts → register-roq_0qYo.d.ts} +1 -1
  37. package/dist/production/{browser-D3uq9sI1.d.ts → browser-B2PdsXXH.d.ts} +2 -2
  38. package/dist/production/{browser-CGcs-0pD.d.mts → browser-DBmQ1yAR.d.mts} +2 -2
  39. package/dist/production/{chunk-CTIXC7EV.js → chunk-3Z6WS2WZ.js} +7 -7
  40. package/dist/production/{chunk-EN242BO4.js → chunk-BIP66BKV.js} +111 -108
  41. package/dist/{development/chunk-ASILSGTR.mjs → production/chunk-EGOTSXNH.mjs} +45 -113
  42. package/dist/production/{chunk-RTRY3JFT.js → chunk-IUPBOWYO.js} +113 -35
  43. package/dist/production/{chunk-OSYEOCBT.mjs → chunk-M7NGGUU6.mjs} +115 -38
  44. package/dist/{development/context-CmHpk1Ws.d.mts → production/context-CeD5LmaF.d.mts} +12 -4
  45. package/dist/{development/data-D4xhSy90.d.ts → production/data-CjO11-hU.d.ts} +9 -1
  46. package/dist/production/{data-U8FS-wNn.d.mts → data-DEjBmEfD.d.mts} +9 -1
  47. package/dist/production/dom-export.d.mts +3 -3
  48. package/dist/production/dom-export.d.ts +3 -3
  49. package/dist/production/dom-export.js +46 -44
  50. package/dist/production/dom-export.mjs +23 -21
  51. package/dist/production/{index-react-server-client-CwU9bE5R.d.ts → index-react-server-client-3ykjivgQ.d.ts} +29 -7
  52. package/dist/production/{index-react-server-client-DPrDrCew.d.mts → index-react-server-client-CACgcj2J.d.mts} +19 -5
  53. package/dist/production/index-react-server-client.d.mts +3 -3
  54. package/dist/production/index-react-server-client.d.ts +3 -3
  55. package/dist/production/index-react-server-client.js +4 -4
  56. package/dist/production/index-react-server-client.mjs +2 -2
  57. package/dist/production/index-react-server.d.mts +9 -1
  58. package/dist/production/index-react-server.d.ts +9 -1
  59. package/dist/production/index-react-server.js +144 -121
  60. package/dist/production/index-react-server.mjs +143 -120
  61. package/dist/production/index.d.mts +15 -14
  62. package/dist/production/index.d.ts +15 -14
  63. package/dist/production/index.js +137 -205
  64. package/dist/production/index.mjs +3 -5
  65. package/dist/{development/instrumentation-1q4YhLGP.d.ts → production/instrumentation-Dkmpzd13.d.ts} +2 -2
  66. package/dist/production/lib/types/internal.d.mts +2 -2
  67. package/dist/production/lib/types/internal.d.ts +2 -2
  68. package/dist/production/lib/types/internal.js +1 -1
  69. package/dist/production/lib/types/internal.mjs +1 -1
  70. package/dist/production/{register-CqK96Zfk.d.mts → register-CmkRspdl.d.mts} +1 -1
  71. package/dist/production/{register-CNAx3TXj.d.ts → register-roq_0qYo.d.ts} +1 -1
  72. package/docs/explanation/type-safety.md +1 -1
  73. package/docs/how-to/headers.md +2 -1
  74. package/docs/how-to/security.md +8 -6
  75. package/docs/start/data/installation.md +4 -0
  76. package/docs/start/framework/deploying.md +4 -0
  77. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.17.0
2
+ * react-router v7.18.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -35,6 +35,7 @@ import {
35
35
  escapeHtml,
36
36
  getManifestPath,
37
37
  getStaticContextFromError,
38
+ hasInvalidProtocol,
38
39
  instrumentHandler,
39
40
  isDataWithResponseInit,
40
41
  isMutationMethod,
@@ -54,7 +55,7 @@ import {
54
55
  withComponentProps,
55
56
  withErrorBoundaryProps,
56
57
  withHydrateFallbackProps
57
- } from "./chunk-OSYEOCBT.mjs";
58
+ } from "./chunk-4ZMWKKQ3.mjs";
58
59
 
59
60
  // lib/dom/ssr/server.tsx
60
61
  import * as React from "react";
@@ -104,6 +105,7 @@ function ServerRouter({
104
105
  ssr: context.ssr,
105
106
  isSpaMode: context.isSpaMode,
106
107
  routeDiscovery: context.routeDiscovery,
108
+ nonce,
107
109
  serializeError: context.serializeError,
108
110
  renderMeta: context.renderMeta
109
111
  }
@@ -466,33 +468,6 @@ function serializeError(error, serverMode) {
466
468
  stack: sanitized.stack
467
469
  };
468
470
  }
469
- function serializeErrors(errors, serverMode) {
470
- if (!errors) return null;
471
- let entries = Object.entries(errors);
472
- let serialized = {};
473
- for (let [key, val] of entries) {
474
- if (isRouteErrorResponse(val)) {
475
- serialized[key] = { ...val, __type: "RouteErrorResponse" };
476
- } else if (val instanceof Error) {
477
- let sanitized = sanitizeError(val, serverMode);
478
- serialized[key] = {
479
- message: sanitized.message,
480
- stack: sanitized.stack,
481
- __type: "Error",
482
- // If this is a subclass (i.e., ReferenceError), send up the type so we
483
- // can re-create the same type during hydration. This will only apply
484
- // in dev mode since all production errors are sanitized to normal
485
- // Error instances
486
- ...sanitized.name !== "Error" ? {
487
- __subType: sanitized.name
488
- } : {}
489
- };
490
- } else {
491
- serialized[key] = val;
492
- }
493
- }
494
- return serialized;
495
- }
496
471
 
497
472
  // lib/server-runtime/invariant.ts
498
473
  function invariant(value, message) {
@@ -769,8 +744,8 @@ function prependCookies(parentHeaders, childHeaders) {
769
744
  }
770
745
 
771
746
  // lib/actions.ts
772
- function throwIfPotentialCSRFAttack(headers, allowedActionOrigins) {
773
- let originHeader = headers.get("origin");
747
+ function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
748
+ let originHeader = request.headers.get("origin");
774
749
  let originDomain = null;
775
750
  try {
776
751
  originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
@@ -779,18 +754,12 @@ function throwIfPotentialCSRFAttack(headers, allowedActionOrigins) {
779
754
  `\`origin\` header is not a valid URL. Aborting the action.`
780
755
  );
781
756
  }
782
- let host = parseHostHeader(headers);
783
- if (originDomain && (!host || originDomain !== host.value)) {
757
+ let host = new URL(request.url).host;
758
+ if (originDomain && originDomain !== host) {
784
759
  if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
785
- if (host) {
786
- throw new Error(
787
- `${host.type} header does not match \`origin\` header from a forwarded action request. Aborting the action.`
788
- );
789
- } else {
790
- throw new Error(
791
- "`x-forwarded-host` or `host` headers are not provided. One of these is needed to compare the `origin` header from a forwarded action request. Aborting the action."
792
- );
793
- }
760
+ throw new Error(
761
+ "The `request.url` host does not match `origin` header from a forwarded action request. Aborting the action."
762
+ );
794
763
  }
795
764
  }
796
765
  }
@@ -838,18 +807,6 @@ function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
838
807
  (allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin))
839
808
  );
840
809
  }
841
- function parseHostHeader(headers) {
842
- let forwardedHostHeader = headers.get("x-forwarded-host");
843
- let forwardedHostValue = forwardedHostHeader?.split(",")[0]?.trim();
844
- let hostHeader = headers.get("host");
845
- return forwardedHostValue ? {
846
- type: "x-forwarded-host",
847
- value: forwardedHostValue
848
- } : hostHeader ? {
849
- type: "host",
850
- value: hostHeader
851
- } : void 0;
852
- }
853
810
 
854
811
  // lib/server-runtime/urls.ts
855
812
  function getNormalizedPath(request, basename, future) {
@@ -895,7 +852,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
895
852
  try {
896
853
  try {
897
854
  throwIfPotentialCSRFAttack(
898
- request.headers,
855
+ request,
899
856
  Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
900
857
  );
901
858
  } catch (e) {
@@ -1225,7 +1182,7 @@ function derive(build, mode) {
1225
1182
  }
1226
1183
  if (build.prerender.length === 0) {
1227
1184
  isSpaMode = true;
1228
- } else if (!build.prerender.includes(decodedPath) && !build.prerender.includes(decodedPath + "/")) {
1185
+ } else if (!build.prerender.includes(decodedPath.replace(/\/$/, "")) && !build.prerender.includes(decodedPath.replace(/[^/]$/, "/"))) {
1229
1186
  if (requestUrl.pathname.endsWith(".data")) {
1230
1187
  errorHandler(
1231
1188
  new ErrorResponseImpl(
@@ -1386,6 +1343,12 @@ var createRequestHandler = (build, mode) => {
1386
1343
  };
1387
1344
  };
1388
1345
  async function handleManifestRequest(build, dataRoutes, branches, url) {
1346
+ if (url.toString().length > URL_LIMIT) {
1347
+ return new Response(null, {
1348
+ statusText: "Bad Request",
1349
+ status: 400
1350
+ });
1351
+ }
1389
1352
  if (build.assets.version !== url.searchParams.get("version")) {
1390
1353
  return new Response(null, {
1391
1354
  status: 204,
@@ -1394,28 +1357,14 @@ async function handleManifestRequest(build, dataRoutes, branches, url) {
1394
1357
  }
1395
1358
  });
1396
1359
  }
1397
- if (url.toString().length > URL_LIMIT) {
1398
- return new Response(null, {
1399
- statusText: "Bad Request",
1400
- status: 400
1401
- });
1402
- }
1403
1360
  let patches = {};
1404
1361
  if (url.searchParams.has("paths")) {
1405
- let paths = /* @__PURE__ */ new Set();
1406
1362
  let pathParam = url.searchParams.get("paths") || "";
1407
- let requestedPaths = pathParam.split(",").filter(Boolean);
1408
- requestedPaths.forEach((path) => {
1363
+ let paths = new Set(pathParam.split(",").filter(Boolean));
1364
+ for (let path of paths) {
1409
1365
  if (!path.startsWith("/")) {
1410
1366
  path = `/${path}`;
1411
1367
  }
1412
- let segments = path.split("/").slice(1);
1413
- segments.forEach((_, i) => {
1414
- let partialPath = segments.slice(0, i + 1).join("/");
1415
- paths.add(`/${partialPath}`);
1416
- });
1417
- });
1418
- for (let path of paths) {
1419
1368
  let matches = matchServerRoutes(
1420
1369
  build.routes,
1421
1370
  dataRoutes,
@@ -1468,7 +1417,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
1468
1417
  if (isMutationMethod(request.method)) {
1469
1418
  try {
1470
1419
  throwIfPotentialCSRFAttack(
1471
- request.headers,
1420
+ request,
1472
1421
  Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
1473
1422
  );
1474
1423
  } catch (e) {
@@ -1516,7 +1465,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
1516
1465
  let state = {
1517
1466
  loaderData: context.loaderData,
1518
1467
  actionData: context.actionData,
1519
- errors: serializeErrors(context.errors, serverMode)
1468
+ errors: context.errors
1520
1469
  };
1521
1470
  let baseServerHandoff = {
1522
1471
  basename: build.basename,
@@ -1582,7 +1531,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
1582
1531
  let state2 = {
1583
1532
  loaderData: context.loaderData,
1584
1533
  actionData: context.actionData,
1585
- errors: serializeErrors(context.errors, serverMode)
1534
+ errors: context.errors
1586
1535
  };
1587
1536
  entryContext = {
1588
1537
  ...entryContext,
@@ -2178,6 +2127,9 @@ async function routeRSCServerRequest({
2178
2127
  detectRedirectResponse.body
2179
2128
  );
2180
2129
  if (serverResponse.status === SINGLE_FETCH_REDIRECT_STATUS && payload.type === "redirect") {
2130
+ if (hasInvalidProtocol(payload.location)) {
2131
+ throw new Error("Invalid redirect location");
2132
+ }
2181
2133
  const headers2 = new Headers(serverResponse.headers);
2182
2134
  headers2.delete("Content-Encoding");
2183
2135
  headers2.delete("Content-Length");
@@ -2221,6 +2173,9 @@ async function routeRSCServerRequest({
2221
2173
  }
2222
2174
  headers.set("Content-Type", "text/html; charset=utf-8");
2223
2175
  if (renderRedirect) {
2176
+ if (hasInvalidProtocol(renderRedirect.location)) {
2177
+ throw new Error("Invalid redirect location");
2178
+ }
2224
2179
  headers.set("Location", renderRedirect.location);
2225
2180
  return new Response(html, {
2226
2181
  status: renderRedirect.status,
@@ -2230,6 +2185,9 @@ async function routeRSCServerRequest({
2230
2185
  const redirectTransform = new TransformStream({
2231
2186
  flush(controller) {
2232
2187
  if (renderRedirect) {
2188
+ if (hasInvalidProtocol(renderRedirect.location)) {
2189
+ return;
2190
+ }
2233
2191
  controller.enqueue(
2234
2192
  new TextEncoder().encode(
2235
2193
  `<meta http-equiv="refresh" content="0;url=${escapeHtml(renderRedirect.location)}"/>`
@@ -2259,6 +2217,9 @@ async function routeRSCServerRequest({
2259
2217
  return error;
2260
2218
  }
2261
2219
  if (renderRedirect) {
2220
+ if (hasInvalidProtocol(renderRedirect.location)) {
2221
+ throw new Error("Invalid redirect location");
2222
+ }
2262
2223
  return new Response(`Redirect: ${renderRedirect.location}`, {
2263
2224
  status: renderRedirect.status,
2264
2225
  headers: {
@@ -2332,6 +2293,9 @@ async function routeRSCServerRequest({
2332
2293
  }
2333
2294
  headers.set("Content-Type", "text/html; charset=utf-8");
2334
2295
  if (retryRedirect) {
2296
+ if (hasInvalidProtocol(retryRedirect.location)) {
2297
+ throw new Error("Invalid redirect location");
2298
+ }
2335
2299
  headers.set("Location", retryRedirect.location);
2336
2300
  return new Response(html, {
2337
2301
  status: retryRedirect.status,
@@ -2341,6 +2305,9 @@ async function routeRSCServerRequest({
2341
2305
  const retryRedirectTransform = new TransformStream({
2342
2306
  flush(controller) {
2343
2307
  if (retryRedirect) {
2308
+ if (hasInvalidProtocol(retryRedirect.location)) {
2309
+ return;
2310
+ }
2344
2311
  controller.enqueue(
2345
2312
  new TextEncoder().encode(
2346
2313
  `<meta http-equiv="refresh" content="0;url=${escapeHtml(retryRedirect.location)}"/>`
@@ -2374,6 +2341,9 @@ function RSCStaticRouter({ getPayload }) {
2374
2341
  const decoded = getPayload();
2375
2342
  const payload = useSafe(decoded);
2376
2343
  if (payload.type === "redirect") {
2344
+ if (hasInvalidProtocol(payload.location)) {
2345
+ throw new Error("Invalid redirect location");
2346
+ }
2377
2347
  throw new Response(null, {
2378
2348
  status: payload.status,
2379
2349
  headers: {
@@ -2491,43 +2461,6 @@ function isManifestRequest(url) {
2491
2461
  return url.pathname.endsWith(".manifest");
2492
2462
  }
2493
2463
 
2494
- // lib/dom/ssr/errors.ts
2495
- function deserializeErrors(errors) {
2496
- if (!errors) return null;
2497
- let entries = Object.entries(errors);
2498
- let serialized = {};
2499
- for (let [key, val] of entries) {
2500
- if (val && val.__type === "RouteErrorResponse") {
2501
- serialized[key] = new ErrorResponseImpl(
2502
- val.status,
2503
- val.statusText,
2504
- val.data,
2505
- val.internal === true
2506
- );
2507
- } else if (val && val.__type === "Error") {
2508
- if (val.__subType) {
2509
- let ErrorConstructor = window[val.__subType];
2510
- if (typeof ErrorConstructor === "function") {
2511
- try {
2512
- let error = new ErrorConstructor(val.message);
2513
- error.stack = val.stack;
2514
- serialized[key] = error;
2515
- } catch (e) {
2516
- }
2517
- }
2518
- }
2519
- if (serialized[key] == null) {
2520
- let error = new Error(val.message);
2521
- error.stack = val.stack;
2522
- serialized[key] = error;
2523
- }
2524
- } else {
2525
- serialized[key] = val;
2526
- }
2527
- }
2528
- return serialized;
2529
- }
2530
-
2531
2464
  // lib/dom/ssr/hydration.tsx
2532
2465
  function getHydrationData({
2533
2466
  state,
@@ -2580,6 +2513,5 @@ export {
2580
2513
  populateRSCRouteModules,
2581
2514
  routeRSCServerRequest,
2582
2515
  RSCStaticRouter,
2583
- deserializeErrors,
2584
2516
  getHydrationData
2585
2517
  };