react-router 7.11.0 → 7.12.0-pre.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 (68) hide show
  1. package/CHANGELOG.md +46 -13
  2. package/dist/development/{browser-Cv4JZyZ5.d.mts → browser-BEPxnEBW.d.mts} +4 -2
  3. package/dist/{production/browser-Cv4JZyZ5.d.mts → development/browser-CJ9_du-U.d.ts} +4 -2
  4. package/dist/development/{chunk-YNUBSHFH.mjs → chunk-2RQJSHF5.mjs} +111 -11
  5. package/dist/development/{chunk-2JY4UAJA.js → chunk-AUGQXA25.js} +98 -108
  6. package/dist/{production/chunk-BEXOWXJO.js → development/chunk-JBLDGBX7.js} +7 -7
  7. package/dist/development/{chunk-JMJ3UQ3L.mjs → chunk-KYKH2NCS.mjs} +122 -50
  8. package/dist/development/{chunk-SZQUWNVJ.js → chunk-MNTWZBMV.js} +117 -35
  9. package/dist/development/dom-export.d.mts +2 -2
  10. package/dist/development/dom-export.d.ts +2 -2
  11. package/dist/development/dom-export.js +35 -30
  12. package/dist/development/dom-export.mjs +12 -7
  13. package/dist/development/{index-react-server-client-P7VgYu6T.d.mts → index-react-server-client-IoJGLOqV.d.mts} +3 -1
  14. package/dist/{production/index-react-server-client-Cv5Q9lf0.d.ts → development/index-react-server-client-gGyf-7Xp.d.ts} +3 -1
  15. package/dist/development/index-react-server-client.d.mts +2 -2
  16. package/dist/development/index-react-server-client.d.ts +2 -2
  17. package/dist/development/index-react-server-client.js +4 -4
  18. package/dist/development/index-react-server-client.mjs +2 -2
  19. package/dist/development/index-react-server.d.mts +3 -1
  20. package/dist/development/index-react-server.d.ts +3 -1
  21. package/dist/development/index-react-server.js +92 -7
  22. package/dist/development/index-react-server.mjs +92 -7
  23. package/dist/development/index.d.mts +9 -9
  24. package/dist/development/index.d.ts +9 -9
  25. package/dist/development/index.js +205 -101
  26. package/dist/development/index.mjs +7 -3
  27. package/dist/{production/instrumentation-BlrVzjbg.d.ts → development/instrumentation-DvHY1sgY.d.ts} +45 -1
  28. package/dist/development/lib/types/internal.d.mts +2 -2
  29. package/dist/development/lib/types/internal.d.ts +2 -2
  30. package/dist/development/lib/types/internal.js +1 -1
  31. package/dist/development/lib/types/internal.mjs +1 -1
  32. package/dist/development/{register-BGQUMCK4.d.ts → register-Bm80E9qL.d.ts} +1 -1
  33. package/dist/development/{register-DTJJbt1o.d.mts → register-CS_tiXsm.d.mts} +1 -1
  34. package/dist/development/{router-5fbeEIMQ.d.mts → router-5iOvts3c.d.mts} +45 -1
  35. package/dist/{development/browser-o-qhcuhA.d.ts → production/browser-BEPxnEBW.d.mts} +4 -2
  36. package/dist/production/{browser-o-qhcuhA.d.ts → browser-CJ9_du-U.d.ts} +4 -2
  37. package/dist/production/{chunk-TINMVEA2.mjs → chunk-HFQUWXEK.mjs} +122 -50
  38. package/dist/production/{chunk-E6GYEQUT.mjs → chunk-ILRYJQTC.mjs} +111 -11
  39. package/dist/{development/chunk-GNDLROV6.js → production/chunk-O6YLM5NB.js} +7 -7
  40. package/dist/production/{chunk-ZMYPVUNZ.js → chunk-QWJQISZK.js} +98 -108
  41. package/dist/production/{chunk-2HFJAX7U.js → chunk-ZR2NIBH2.js} +117 -35
  42. package/dist/production/dom-export.d.mts +2 -2
  43. package/dist/production/dom-export.d.ts +2 -2
  44. package/dist/production/dom-export.js +35 -30
  45. package/dist/production/dom-export.mjs +12 -7
  46. package/dist/production/{index-react-server-client-P7VgYu6T.d.mts → index-react-server-client-IoJGLOqV.d.mts} +3 -1
  47. package/dist/{development/index-react-server-client-Cv5Q9lf0.d.ts → production/index-react-server-client-gGyf-7Xp.d.ts} +3 -1
  48. package/dist/production/index-react-server-client.d.mts +2 -2
  49. package/dist/production/index-react-server-client.d.ts +2 -2
  50. package/dist/production/index-react-server-client.js +4 -4
  51. package/dist/production/index-react-server-client.mjs +2 -2
  52. package/dist/production/index-react-server.d.mts +3 -1
  53. package/dist/production/index-react-server.d.ts +3 -1
  54. package/dist/production/index-react-server.js +92 -7
  55. package/dist/production/index-react-server.mjs +92 -7
  56. package/dist/production/index.d.mts +9 -9
  57. package/dist/production/index.d.ts +9 -9
  58. package/dist/production/index.js +205 -101
  59. package/dist/production/index.mjs +7 -3
  60. package/dist/{development/instrumentation-BlrVzjbg.d.ts → production/instrumentation-DvHY1sgY.d.ts} +45 -1
  61. package/dist/production/lib/types/internal.d.mts +2 -2
  62. package/dist/production/lib/types/internal.d.ts +2 -2
  63. package/dist/production/lib/types/internal.js +1 -1
  64. package/dist/production/lib/types/internal.mjs +1 -1
  65. package/dist/production/{register-BGQUMCK4.d.ts → register-Bm80E9qL.d.ts} +1 -1
  66. package/dist/production/{register-DTJJbt1o.d.mts → register-CS_tiXsm.d.mts} +1 -1
  67. package/dist/production/{router-5fbeEIMQ.d.mts → router-5iOvts3c.d.mts} +45 -1
  68. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.11.0
2
+ * react-router v7.12.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -709,12 +709,12 @@ function generatePath(originalPath, params = {}) {
709
709
  const star = "*";
710
710
  return stringify2(params[star]);
711
711
  }
712
- const keyMatch = segment.match(/^:([\w-]+)(\??)$/);
712
+ const keyMatch = segment.match(/^:([\w-]+)(\??)(.*)/);
713
713
  if (keyMatch) {
714
- const [, key, optional] = keyMatch;
714
+ const [, key, optional, suffix] = keyMatch;
715
715
  let param = params[key];
716
716
  invariant(optional === "?" || param != null, `Missing ":${key}" param`);
717
- return encodeURIComponent(stringify2(param));
717
+ return encodeURIComponent(stringify2(param)) + suffix;
718
718
  }
719
719
  return segment.replace(/\?$/g, "");
720
720
  }).filter((segment) => !!segment);
@@ -1071,6 +1071,9 @@ function getRouteInstrumentationUpdates(fns, route) {
1071
1071
  (...args) => getHandlerInfo(args[0])
1072
1072
  );
1073
1073
  if (instrumented) {
1074
+ if (key === "loader" && original.hydrate === true) {
1075
+ instrumented.hydrate = true;
1076
+ }
1074
1077
  instrumented[UninstrumentedSymbol] = original;
1075
1078
  updates[key] = instrumented;
1076
1079
  }
@@ -2014,7 +2017,8 @@ function createRouter(init) {
2014
2017
  let location2 = normalizeRedirectLocation(
2015
2018
  result.response.headers.get("Location"),
2016
2019
  new URL(request.url),
2017
- basename
2020
+ basename,
2021
+ init.history
2018
2022
  );
2019
2023
  replace2 = location2 === state.location.pathname + state.location.search;
2020
2024
  }
@@ -2648,7 +2652,8 @@ function createRouter(init) {
2648
2652
  location = normalizeRedirectLocation(
2649
2653
  location,
2650
2654
  new URL(request.url),
2651
- basename
2655
+ basename,
2656
+ init.history
2652
2657
  );
2653
2658
  let redirectLocation = createLocation(state.location, location, {
2654
2659
  _isRedirect: true
@@ -4907,15 +4912,38 @@ function normalizeRelativeRoutingRedirectResponse(response, request, routeId, ma
4907
4912
  }
4908
4913
  return response;
4909
4914
  }
4910
- function normalizeRedirectLocation(location, currentUrl, basename) {
4915
+ function normalizeRedirectLocation(location, currentUrl, basename, historyInstance) {
4916
+ let invalidProtocols = [
4917
+ "about:",
4918
+ "blob:",
4919
+ "chrome:",
4920
+ "chrome-untrusted:",
4921
+ "content:",
4922
+ "data:",
4923
+ "devtools:",
4924
+ "file:",
4925
+ "filesystem:",
4926
+ // eslint-disable-next-line no-script-url
4927
+ "javascript:"
4928
+ ];
4911
4929
  if (isAbsoluteUrl(location)) {
4912
4930
  let normalizedLocation = location;
4913
4931
  let url = normalizedLocation.startsWith("//") ? new URL(currentUrl.protocol + normalizedLocation) : new URL(normalizedLocation);
4932
+ if (invalidProtocols.includes(url.protocol)) {
4933
+ throw new Error("Invalid redirect location");
4934
+ }
4914
4935
  let isSameBasename = stripBasename(url.pathname, basename) != null;
4915
4936
  if (url.origin === currentUrl.origin && isSameBasename) {
4916
4937
  return url.pathname + url.search + url.hash;
4917
4938
  }
4918
4939
  }
4940
+ try {
4941
+ let url = historyInstance.createURL(location);
4942
+ if (invalidProtocols.includes(url.protocol)) {
4943
+ throw new Error("Invalid redirect location");
4944
+ }
4945
+ } catch (e) {
4946
+ }
4919
4947
  return location;
4920
4948
  }
4921
4949
  function createClientSideRequest(history, location, signal, submission) {
@@ -7761,7 +7789,7 @@ function StreamTransfer({
7761
7789
  )));
7762
7790
  }
7763
7791
  }
7764
- function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules, ssr, basename) {
7792
+ function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules, ssr, basename, trailingSlashAware) {
7765
7793
  let dataStrategy = getSingleFetchDataStrategyImpl(
7766
7794
  getRouter,
7767
7795
  (match) => {
@@ -7776,26 +7804,43 @@ function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules
7776
7804
  },
7777
7805
  fetchAndDecodeViaTurboStream,
7778
7806
  ssr,
7779
- basename
7807
+ basename,
7808
+ trailingSlashAware
7780
7809
  );
7781
7810
  return async (args) => args.runClientMiddleware(dataStrategy);
7782
7811
  }
7783
- function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7812
+ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename, trailingSlashAware, shouldAllowOptOut = () => true) {
7784
7813
  return async (args) => {
7785
7814
  let { request, matches, fetcherKey } = args;
7786
7815
  let router = getRouter();
7787
7816
  if (request.method !== "GET") {
7788
- return singleFetchActionStrategy(args, fetchAndDecode, basename);
7817
+ return singleFetchActionStrategy(
7818
+ args,
7819
+ fetchAndDecode,
7820
+ basename,
7821
+ trailingSlashAware
7822
+ );
7789
7823
  }
7790
7824
  let foundRevalidatingServerLoader = matches.some((m) => {
7791
7825
  let { hasLoader, hasClientLoader } = getRouteInfo(m);
7792
7826
  return m.shouldCallHandler() && hasLoader && !hasClientLoader;
7793
7827
  });
7794
7828
  if (!ssr && !foundRevalidatingServerLoader) {
7795
- return nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename);
7829
+ return nonSsrStrategy(
7830
+ args,
7831
+ getRouteInfo,
7832
+ fetchAndDecode,
7833
+ basename,
7834
+ trailingSlashAware
7835
+ );
7796
7836
  }
7797
7837
  if (fetcherKey) {
7798
- return singleFetchLoaderFetcherStrategy(args, fetchAndDecode, basename);
7838
+ return singleFetchLoaderFetcherStrategy(
7839
+ args,
7840
+ fetchAndDecode,
7841
+ basename,
7842
+ trailingSlashAware
7843
+ );
7799
7844
  }
7800
7845
  return singleFetchLoaderNavigationStrategy(
7801
7846
  args,
@@ -7804,19 +7849,23 @@ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode,
7804
7849
  fetchAndDecode,
7805
7850
  ssr,
7806
7851
  basename,
7852
+ trailingSlashAware,
7807
7853
  shouldAllowOptOut
7808
7854
  );
7809
7855
  };
7810
7856
  }
7811
- async function singleFetchActionStrategy(args, fetchAndDecode, basename) {
7857
+ async function singleFetchActionStrategy(args, fetchAndDecode, basename, trailingSlashAware) {
7812
7858
  let actionMatch = args.matches.find((m) => m.shouldCallHandler());
7813
7859
  invariant2(actionMatch, "No action match found");
7814
7860
  let actionStatus = void 0;
7815
7861
  let result = await actionMatch.resolve(async (handler) => {
7816
7862
  let result2 = await handler(async () => {
7817
- let { data: data2, status } = await fetchAndDecode(args, basename, [
7818
- actionMatch.route.id
7819
- ]);
7863
+ let { data: data2, status } = await fetchAndDecode(
7864
+ args,
7865
+ basename,
7866
+ trailingSlashAware,
7867
+ [actionMatch.route.id]
7868
+ );
7820
7869
  actionStatus = status;
7821
7870
  return unwrapSingleFetchResult(data2, actionMatch.route.id);
7822
7871
  });
@@ -7832,7 +7881,7 @@ async function singleFetchActionStrategy(args, fetchAndDecode, basename) {
7832
7881
  }
7833
7882
  };
7834
7883
  }
7835
- async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
7884
+ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename, trailingSlashAware) {
7836
7885
  let matchesToLoad = args.matches.filter((m) => m.shouldCallHandler());
7837
7886
  let results = {};
7838
7887
  await Promise.all(
@@ -7842,7 +7891,12 @@ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
7842
7891
  let { hasClientLoader } = getRouteInfo(m);
7843
7892
  let routeId = m.route.id;
7844
7893
  let result = hasClientLoader ? await handler(async () => {
7845
- let { data: data2 } = await fetchAndDecode(args, basename, [routeId]);
7894
+ let { data: data2 } = await fetchAndDecode(
7895
+ args,
7896
+ basename,
7897
+ trailingSlashAware,
7898
+ [routeId]
7899
+ );
7846
7900
  return unwrapSingleFetchResult(data2, routeId);
7847
7901
  }) : await handler();
7848
7902
  results[m.route.id] = { type: "data", result };
@@ -7854,7 +7908,7 @@ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
7854
7908
  );
7855
7909
  return results;
7856
7910
  }
7857
- async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7911
+ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename, trailingSlashAware, shouldAllowOptOut = () => true) {
7858
7912
  let routesParams = /* @__PURE__ */ new Set();
7859
7913
  let foundOptOutRoute = false;
7860
7914
  let routeDfds = args.matches.map(() => createDeferred2());
@@ -7880,7 +7934,12 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
7880
7934
  }
7881
7935
  try {
7882
7936
  let result = await handler(async () => {
7883
- let { data: data2 } = await fetchAndDecode(args, basename, [routeId]);
7937
+ let { data: data2 } = await fetchAndDecode(
7938
+ args,
7939
+ basename,
7940
+ trailingSlashAware,
7941
+ [routeId]
7942
+ );
7884
7943
  return unwrapSingleFetchResult(data2, routeId);
7885
7944
  });
7886
7945
  results[routeId] = { type: "data", result };
@@ -7911,7 +7970,12 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
7911
7970
  } else {
7912
7971
  let targetRoutes = ssr && foundOptOutRoute && routesParams.size > 0 ? [...routesParams.keys()] : void 0;
7913
7972
  try {
7914
- let data2 = await fetchAndDecode(args, basename, targetRoutes);
7973
+ let data2 = await fetchAndDecode(
7974
+ args,
7975
+ basename,
7976
+ trailingSlashAware,
7977
+ targetRoutes
7978
+ );
7915
7979
  singleFetchDfd.resolve(data2.data);
7916
7980
  } catch (e) {
7917
7981
  singleFetchDfd.reject(e);
@@ -7957,13 +8021,15 @@ async function bubbleMiddlewareErrors(singleFetchPromise, matches, routesParams,
7957
8021
  } catch (e) {
7958
8022
  }
7959
8023
  }
7960
- async function singleFetchLoaderFetcherStrategy(args, fetchAndDecode, basename) {
8024
+ async function singleFetchLoaderFetcherStrategy(args, fetchAndDecode, basename, trailingSlashAware) {
7961
8025
  let fetcherMatch = args.matches.find((m) => m.shouldCallHandler());
7962
8026
  invariant2(fetcherMatch, "No fetcher match found");
7963
8027
  let routeId = fetcherMatch.route.id;
7964
8028
  let result = await fetcherMatch.resolve(
7965
8029
  async (handler) => handler(async () => {
7966
- let { data: data2 } = await fetchAndDecode(args, basename, [routeId]);
8030
+ let { data: data2 } = await fetchAndDecode(args, basename, trailingSlashAware, [
8031
+ routeId
8032
+ ]);
7967
8033
  return unwrapSingleFetchResult(data2, routeId);
7968
8034
  })
7969
8035
  );
@@ -7983,25 +8049,33 @@ function stripIndexParam(url) {
7983
8049
  }
7984
8050
  return url;
7985
8051
  }
7986
- function singleFetchUrl(reqUrl, basename, extension) {
8052
+ function singleFetchUrl(reqUrl, basename, trailingSlashAware, extension) {
7987
8053
  let url = typeof reqUrl === "string" ? new URL(
7988
8054
  reqUrl,
7989
8055
  // This can be called during the SSR flow via PrefetchPageLinksImpl so
7990
8056
  // don't assume window is available
7991
8057
  typeof window === "undefined" ? "server://singlefetch/" : window.location.origin
7992
8058
  ) : reqUrl;
7993
- if (url.pathname === "/") {
7994
- url.pathname = `_root.${extension}`;
7995
- } else if (basename && stripBasename(url.pathname, basename) === "/") {
7996
- url.pathname = `${basename.replace(/\/$/, "")}/_root.${extension}`;
8059
+ if (trailingSlashAware) {
8060
+ if (url.pathname.endsWith("/")) {
8061
+ url.pathname = `${url.pathname}_.${extension}`;
8062
+ } else {
8063
+ url.pathname = `${url.pathname}.${extension}`;
8064
+ }
7997
8065
  } else {
7998
- url.pathname = `${url.pathname.replace(/\/$/, "")}.${extension}`;
8066
+ if (url.pathname === "/") {
8067
+ url.pathname = `_root.${extension}`;
8068
+ } else if (basename && stripBasename(url.pathname, basename) === "/") {
8069
+ url.pathname = `${basename.replace(/\/$/, "")}/_root.${extension}`;
8070
+ } else {
8071
+ url.pathname = `${url.pathname.replace(/\/$/, "")}.${extension}`;
8072
+ }
7999
8073
  }
8000
8074
  return url;
8001
8075
  }
8002
- async function fetchAndDecodeViaTurboStream(args, basename, targetRoutes) {
8076
+ async function fetchAndDecodeViaTurboStream(args, basename, trailingSlashAware, targetRoutes) {
8003
8077
  let { request } = args;
8004
- let url = singleFetchUrl(request.url, basename, "data");
8078
+ let url = singleFetchUrl(request.url, basename, trailingSlashAware, "data");
8005
8079
  if (request.method === "GET") {
8006
8080
  url = stripIndexParam(url);
8007
8081
  if (targetRoutes) {
@@ -9192,7 +9266,7 @@ function PrefetchPageLinksImpl({
9192
9266
  ...linkProps
9193
9267
  }) {
9194
9268
  let location = useLocation();
9195
- let { manifest, routeModules } = useFrameworkContext();
9269
+ let { future, manifest, routeModules } = useFrameworkContext();
9196
9270
  let { basename } = useDataRouterContext2();
9197
9271
  let { loaderData, matches } = useDataRouterStateContext();
9198
9272
  let newMatchesForData = React8.useMemo(
@@ -9239,7 +9313,12 @@ function PrefetchPageLinksImpl({
9239
9313
  if (routesParams.size === 0) {
9240
9314
  return [];
9241
9315
  }
9242
- let url = singleFetchUrl(page, basename, "data");
9316
+ let url = singleFetchUrl(
9317
+ page,
9318
+ basename,
9319
+ future.unstable_trailingSlashAwareDataRequests,
9320
+ "data"
9321
+ );
9243
9322
  if (foundOptOutRoute && routesParams.size > 0) {
9244
9323
  url.searchParams.set(
9245
9324
  "_routes",
@@ -9249,6 +9328,7 @@ function PrefetchPageLinksImpl({
9249
9328
  return [url.pathname + url.search];
9250
9329
  }, [
9251
9330
  basename,
9331
+ future.unstable_trailingSlashAwareDataRequests,
9252
9332
  loaderData,
9253
9333
  location,
9254
9334
  manifest,
@@ -9492,6 +9572,7 @@ import(${JSON.stringify(manifest.entry.module)});`;
9492
9572
  return isHydrated || isRSCRouterContext ? null : /* @__PURE__ */ React8.createElement(React8.Fragment, null, typeof manifest.sri === "object" ? /* @__PURE__ */ React8.createElement(
9493
9573
  "script",
9494
9574
  {
9575
+ ...scriptProps,
9495
9576
  "rr-importmap": "",
9496
9577
  type: "importmap",
9497
9578
  suppressHydrationWarning: true,
@@ -9649,7 +9730,7 @@ var isBrowser2 = typeof window !== "undefined" && typeof window.document !== "un
9649
9730
  try {
9650
9731
  if (isBrowser2) {
9651
9732
  window.__reactRouterVersion = // @ts-expect-error
9652
- "7.11.0";
9733
+ "7.12.0-pre.0";
9653
9734
  }
9654
9735
  } catch (e) {
9655
9736
  }
@@ -10077,9 +10158,9 @@ function ScrollRestoration({
10077
10158
  ...props,
10078
10159
  suppressHydrationWarning: true,
10079
10160
  dangerouslySetInnerHTML: {
10080
- __html: `(${restoreScroll})(${JSON.stringify(
10081
- storageKey || SCROLL_RESTORATION_STORAGE_KEY
10082
- )}, ${JSON.stringify(ssrKey)})`
10161
+ __html: `(${restoreScroll})(${escapeHtml(
10162
+ JSON.stringify(storageKey || SCROLL_RESTORATION_STORAGE_KEY)
10163
+ )}, ${escapeHtml(JSON.stringify(ssrKey))})`
10083
10164
  }
10084
10165
  }
10085
10166
  );
@@ -10557,7 +10638,7 @@ function StaticRouterProvider({
10557
10638
  actionData: context.actionData,
10558
10639
  errors: serializeErrors(context.errors)
10559
10640
  };
10560
- let json = htmlEscape(JSON.stringify(JSON.stringify(data2)));
10641
+ let json = escapeHtml(JSON.stringify(JSON.stringify(data2)));
10561
10642
  hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`;
10562
10643
  }
10563
10644
  let { state } = dataRouterContext.router;
@@ -10768,21 +10849,12 @@ function encodeLocation(to) {
10768
10849
  };
10769
10850
  }
10770
10851
  var ABSOLUTE_URL_REGEX3 = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
10771
- var ESCAPE_LOOKUP2 = {
10772
- "&": "\\u0026",
10773
- ">": "\\u003e",
10774
- "<": "\\u003c",
10775
- "\u2028": "\\u2028",
10776
- "\u2029": "\\u2029"
10777
- };
10778
- var ESCAPE_REGEX2 = /[&><\u2028\u2029]/g;
10779
- function htmlEscape(str) {
10780
- return str.replace(ESCAPE_REGEX2, (match) => ESCAPE_LOOKUP2[match]);
10781
- }
10782
10852
 
10783
10853
  export {
10784
10854
  Action,
10855
+ createMemoryHistory,
10785
10856
  createBrowserHistory,
10857
+ createHashHistory,
10786
10858
  invariant,
10787
10859
  createPath,
10788
10860
  parsePath,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.11.0
2
+ * react-router v7.12.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -51,7 +51,7 @@ import {
51
51
  withComponentProps,
52
52
  withErrorBoundaryProps,
53
53
  withHydrateFallbackProps
54
- } from "./chunk-TINMVEA2.mjs";
54
+ } from "./chunk-HFQUWXEK.mjs";
55
55
 
56
56
  // lib/dom/ssr/server.tsx
57
57
  import * as React from "react";
@@ -138,7 +138,8 @@ function createRoutesStub(routes, _context) {
138
138
  frameworkContextRef.current = {
139
139
  future: {
140
140
  unstable_subResourceIntegrity: future?.unstable_subResourceIntegrity === true,
141
- v8_middleware: future?.v8_middleware === true
141
+ v8_middleware: future?.v8_middleware === true,
142
+ unstable_trailingSlashAwareDataRequests: future?.unstable_trailingSlashAwareDataRequests === true
142
143
  },
143
144
  manifest: {
144
145
  routes: {},
@@ -754,6 +755,85 @@ function prependCookies(parentHeaders, childHeaders) {
754
755
  }
755
756
  }
756
757
 
758
+ // lib/actions.ts
759
+ function throwIfPotentialCSRFAttack(headers, allowedActionOrigins) {
760
+ let originHeader = headers.get("origin");
761
+ let originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
762
+ let host = parseHostHeader(headers);
763
+ if (originDomain && (!host || originDomain !== host.value)) {
764
+ if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
765
+ if (host) {
766
+ throw new Error(
767
+ `${host.type} header does not match \`origin\` header from a forwarded action request. Aborting the action.`
768
+ );
769
+ } else {
770
+ throw new Error(
771
+ "`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."
772
+ );
773
+ }
774
+ }
775
+ }
776
+ }
777
+ function matchWildcardDomain(domain, pattern) {
778
+ const domainParts = domain.split(".");
779
+ const patternParts = pattern.split(".");
780
+ if (patternParts.length < 1) {
781
+ return false;
782
+ }
783
+ if (domainParts.length < patternParts.length) {
784
+ return false;
785
+ }
786
+ if (patternParts.length === 1 && (patternParts[0] === "*" || patternParts[0] === "**")) {
787
+ return false;
788
+ }
789
+ while (patternParts.length) {
790
+ const patternPart = patternParts.pop();
791
+ const domainPart = domainParts.pop();
792
+ switch (patternPart) {
793
+ case "": {
794
+ return false;
795
+ }
796
+ case "*": {
797
+ if (domainPart) {
798
+ continue;
799
+ } else {
800
+ return false;
801
+ }
802
+ }
803
+ case "**": {
804
+ if (patternParts.length > 0) {
805
+ return false;
806
+ }
807
+ return domainPart !== void 0;
808
+ }
809
+ case void 0:
810
+ default: {
811
+ if (domainPart !== patternPart) {
812
+ return false;
813
+ }
814
+ }
815
+ }
816
+ }
817
+ return domainParts.length === 0;
818
+ }
819
+ function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
820
+ return allowedActionOrigins.some(
821
+ (allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin))
822
+ );
823
+ }
824
+ function parseHostHeader(headers) {
825
+ let forwardedHostHeader = headers.get("x-forwarded-host");
826
+ let forwardedHostValue = forwardedHostHeader?.split(",")[0]?.trim();
827
+ let hostHeader = headers.get("host");
828
+ return forwardedHostValue ? {
829
+ type: "x-forwarded-host",
830
+ value: forwardedHostValue
831
+ } : hostHeader ? {
832
+ type: "host",
833
+ value: hostHeader
834
+ } : void 0;
835
+ }
836
+
757
837
  // lib/server-runtime/single-fetch.ts
758
838
  var SERVER_NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
759
839
  ...NO_BODY_STATUS_CODES,
@@ -761,6 +841,10 @@ var SERVER_NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
761
841
  ]);
762
842
  async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
763
843
  try {
844
+ throwIfPotentialCSRFAttack(
845
+ request.headers,
846
+ Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
847
+ );
764
848
  let handlerRequest = new Request(handlerUrl, {
765
849
  method: request.method,
766
850
  body: request.body,
@@ -1041,13 +1125,21 @@ function derive(build, mode) {
1041
1125
  let url = new URL(request.url);
1042
1126
  let normalizedBasename = build.basename || "/";
1043
1127
  let normalizedPath = url.pathname;
1044
- if (stripBasename(normalizedPath, normalizedBasename) === "/_root.data") {
1045
- normalizedPath = normalizedBasename;
1046
- } else if (normalizedPath.endsWith(".data")) {
1047
- normalizedPath = normalizedPath.replace(/\.data$/, "");
1048
- }
1049
- if (stripBasename(normalizedPath, normalizedBasename) !== "/" && normalizedPath.endsWith("/")) {
1050
- normalizedPath = normalizedPath.slice(0, -1);
1128
+ if (build.future.unstable_trailingSlashAwareDataRequests) {
1129
+ if (normalizedPath.endsWith("/_.data")) {
1130
+ normalizedPath = normalizedPath.replace(/_.data$/, "");
1131
+ } else {
1132
+ normalizedPath = normalizedPath.replace(/\.data$/, "");
1133
+ }
1134
+ } else {
1135
+ if (stripBasename(normalizedPath, normalizedBasename) === "/_root.data") {
1136
+ normalizedPath = normalizedBasename;
1137
+ } else if (normalizedPath.endsWith(".data")) {
1138
+ normalizedPath = normalizedPath.replace(/\.data$/, "");
1139
+ }
1140
+ if (stripBasename(normalizedPath, normalizedBasename) !== "/" && normalizedPath.endsWith("/")) {
1141
+ normalizedPath = normalizedPath.slice(0, -1);
1142
+ }
1051
1143
  }
1052
1144
  let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
1053
1145
  if (!build.ssr) {
@@ -1303,6 +1395,12 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
1303
1395
  }
1304
1396
  async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
1305
1397
  try {
1398
+ if (request.method === "POST") {
1399
+ throwIfPotentialCSRFAttack(
1400
+ request.headers,
1401
+ Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
1402
+ );
1403
+ }
1306
1404
  let result = await staticHandler.query(request, {
1307
1405
  requestContext: loadContext,
1308
1406
  generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
@@ -2274,7 +2372,9 @@ function RSCStaticRouter({ getPayload }) {
2274
2372
  // These flags have no runtime impact so can always be false. If we add
2275
2373
  // flags that drive runtime behavior they'll need to be proxied through.
2276
2374
  v8_middleware: false,
2277
- unstable_subResourceIntegrity: false
2375
+ unstable_subResourceIntegrity: false,
2376
+ unstable_trailingSlashAwareDataRequests: true
2377
+ // always on for RSC
2278
2378
  },
2279
2379
  isSpaMode: false,
2280
2380
  ssr: true,
@@ -1,5 +1,5 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }/**
2
- * react-router v7.11.0
2
+ * react-router v7.12.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,7 +14,7 @@
14
14
 
15
15
 
16
16
 
17
- var _chunkSZQUWNVJjs = require('./chunk-SZQUWNVJ.js');
17
+ var _chunkZR2NIBH2js = require('./chunk-ZR2NIBH2.js');
18
18
 
19
19
  // lib/dom/ssr/hydration.tsx
20
20
  function getHydrationData({
@@ -29,12 +29,12 @@ function getHydrationData({
29
29
  ...state,
30
30
  loaderData: { ...state.loaderData }
31
31
  };
32
- let initialMatches = _chunkSZQUWNVJjs.matchRoutes.call(void 0, routes, location, basename);
32
+ let initialMatches = _chunkZR2NIBH2js.matchRoutes.call(void 0, routes, location, basename);
33
33
  if (initialMatches) {
34
34
  for (let match of initialMatches) {
35
35
  let routeId = match.route.id;
36
36
  let routeInfo = getRouteInfo(routeId);
37
- if (_chunkSZQUWNVJjs.shouldHydrateRouteLoader.call(void 0,
37
+ if (_chunkZR2NIBH2js.shouldHydrateRouteLoader.call(void 0,
38
38
  routeId,
39
39
  routeInfo.clientLoader,
40
40
  routeInfo.hasLoader,
@@ -112,7 +112,7 @@ function RSCDefaultRootErrorBoundaryImpl({
112
112
  }
113
113
  }
114
114
  );
115
- if (_chunkSZQUWNVJjs.isRouteErrorResponse.call(void 0, error)) {
115
+ if (_chunkZR2NIBH2js.isRouteErrorResponse.call(void 0, error)) {
116
116
  return /* @__PURE__ */ _react2.default.createElement(
117
117
  ErrorWrapper,
118
118
  {
@@ -120,7 +120,7 @@ function RSCDefaultRootErrorBoundaryImpl({
120
120
  title: "Unhandled Thrown Response!"
121
121
  },
122
122
  /* @__PURE__ */ _react2.default.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText),
123
- _chunkSZQUWNVJjs.ENABLE_DEV_WARNINGS ? heyDeveloper : null
123
+ _chunkZR2NIBH2js.ENABLE_DEV_WARNINGS ? heyDeveloper : null
124
124
  );
125
125
  }
126
126
  let errorInstance;
@@ -146,7 +146,7 @@ function RSCDefaultRootErrorBoundaryImpl({
146
146
  function RSCDefaultRootErrorBoundary({
147
147
  hasRootLayout
148
148
  }) {
149
- let error = _chunkSZQUWNVJjs.useRouteError.call(void 0, );
149
+ let error = _chunkZR2NIBH2js.useRouteError.call(void 0, );
150
150
  if (hasRootLayout === void 0) {
151
151
  throw new Error("Missing 'hasRootLayout' prop");
152
152
  }