react-router 7.8.2 → 7.9.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 (60) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/development/{chunk-5UALIXAM.mjs → chunk-AVXIT45F.mjs} +94 -70
  3. package/dist/development/{chunk-PVWAREVJ.mjs → chunk-QZH3B547.mjs} +47 -50
  4. package/dist/development/{chunk-ZO66TDGB.js → chunk-RGB6BZUL.js} +41 -44
  5. package/dist/development/{chunk-CSDGKXLR.js → chunk-XYB2GISA.js} +135 -135
  6. package/dist/{production/context-jKip1TFB.d.mts → development/context-BH6Jwdoy.d.mts} +39 -32
  7. package/dist/development/dom-export.d.mts +3 -3
  8. package/dist/development/dom-export.d.ts +2 -2
  9. package/dist/development/dom-export.js +14 -14
  10. package/dist/development/dom-export.mjs +14 -14
  11. package/dist/development/{index-react-server-client-DRhjXpk2.d.mts → index-react-server-client-1cWMpKk4.d.mts} +13 -13
  12. package/dist/{production/index-react-server-client-BKpa2trA.d.ts → development/index-react-server-client-CMC2eQAY.d.ts} +12 -12
  13. package/dist/development/index-react-server-client.d.mts +3 -3
  14. package/dist/development/index-react-server-client.d.ts +2 -2
  15. package/dist/development/index-react-server-client.js +4 -4
  16. package/dist/development/index-react-server-client.mjs +4 -4
  17. package/dist/development/index-react-server.d.mts +229 -37
  18. package/dist/development/index-react-server.d.ts +229 -37
  19. package/dist/development/index-react-server.js +89 -39
  20. package/dist/development/index-react-server.mjs +88 -36
  21. package/dist/development/index.d.mts +31 -24
  22. package/dist/development/index.d.ts +29 -22
  23. package/dist/development/index.js +184 -158
  24. package/dist/development/index.mjs +9 -7
  25. package/dist/development/lib/types/internal.d.mts +6 -6
  26. package/dist/development/lib/types/internal.d.ts +5 -5
  27. package/dist/development/lib/types/internal.js +1 -1
  28. package/dist/development/lib/types/internal.mjs +1 -1
  29. package/dist/development/{route-data-DAVP2QQ0.d.mts → route-data-BQkq8Erj.d.mts} +12 -12
  30. package/dist/development/{routeModules-rOzWJJ9x.d.ts → routeModules-DSKAn01V.d.ts} +175 -168
  31. package/dist/production/{chunk-Z56HUDN5.js → chunk-A6EU7LHU.js} +41 -44
  32. package/dist/production/{chunk-REDRD2MB.mjs → chunk-BQLQLXP4.mjs} +47 -50
  33. package/dist/production/{chunk-JNT5PWCQ.js → chunk-IR3XRH6J.js} +135 -135
  34. package/dist/production/{chunk-KWHRV2I7.mjs → chunk-WMHWIEJV.mjs} +94 -70
  35. package/dist/{development/context-jKip1TFB.d.mts → production/context-BH6Jwdoy.d.mts} +39 -32
  36. package/dist/production/dom-export.d.mts +3 -3
  37. package/dist/production/dom-export.d.ts +2 -2
  38. package/dist/production/dom-export.js +14 -14
  39. package/dist/production/dom-export.mjs +14 -14
  40. package/dist/production/{index-react-server-client-DRhjXpk2.d.mts → index-react-server-client-1cWMpKk4.d.mts} +13 -13
  41. package/dist/{development/index-react-server-client-BKpa2trA.d.ts → production/index-react-server-client-CMC2eQAY.d.ts} +12 -12
  42. package/dist/production/index-react-server-client.d.mts +3 -3
  43. package/dist/production/index-react-server-client.d.ts +2 -2
  44. package/dist/production/index-react-server-client.js +4 -4
  45. package/dist/production/index-react-server-client.mjs +4 -4
  46. package/dist/production/index-react-server.d.mts +229 -37
  47. package/dist/production/index-react-server.d.ts +229 -37
  48. package/dist/production/index-react-server.js +89 -39
  49. package/dist/production/index-react-server.mjs +88 -36
  50. package/dist/production/index.d.mts +31 -24
  51. package/dist/production/index.d.ts +29 -22
  52. package/dist/production/index.js +184 -158
  53. package/dist/production/index.mjs +9 -7
  54. package/dist/production/lib/types/internal.d.mts +6 -6
  55. package/dist/production/lib/types/internal.d.ts +5 -5
  56. package/dist/production/lib/types/internal.js +1 -1
  57. package/dist/production/lib/types/internal.mjs +1 -1
  58. package/dist/production/{route-data-DAVP2QQ0.d.mts → route-data-BQkq8Erj.d.mts} +12 -12
  59. package/dist/production/{routeModules-rOzWJJ9x.d.ts → routeModules-DSKAn01V.d.ts} +175 -168
  60. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # `react-router`
2
2
 
3
+ ## 7.9.0-pre.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Escape HTML in `meta()` JSON-LD content ([#14316](https://github.com/remix-run/react-router/pull/14316))
8
+
9
+ ## 7.9.0-pre.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215))
14
+
15
+ We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use:
16
+ - [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider)
17
+ - [`createContext`](https://reactrouter.com/api/utils/createContext)
18
+ - `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option
19
+ - `<HydratedRouter>` [`getContext`](https://reactrouter.com/api/framework-routers/HydratedRouter#getcontext) prop
20
+
21
+ Please see the [Middleware Docs](https://reactrouter.com/how-to/middleware), the [Middleware RFC](https://github.com/remix-run/remix/discussions/7642), and the [Client-side Context RFC](https://github.com/remix-run/react-router/discussions/9856) for more information.
22
+
23
+ ### Patch Changes
24
+
25
+ - Add react-server Await component implementation ([#14261](https://github.com/remix-run/react-router/pull/14261))
26
+ - In RSC Data Mode when using a custom basename, fix hydration errors for routes that only have client loaders ([#14264](https://github.com/remix-run/react-router/pull/14264))
27
+ - Make `href` function available in a react-server context ([#14262](https://github.com/remix-run/react-router/pull/14262))
28
+ - decode each time `getPayload()` is called to allow for "in-context" decoding and hoisting of contextual assets ([#14248](https://github.com/remix-run/react-router/pull/14248))
29
+ - `href()` now correctly processes routes that have an extension after the parameter or are a single optional parameter. ([#13797](https://github.com/remix-run/react-router/pull/13797))
30
+
3
31
  ## 7.8.2
4
32
 
5
33
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.8.2
2
+ * react-router v7.9.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -16,6 +16,7 @@ import {
16
16
  Outlet,
17
17
  RSCRouterContext,
18
18
  RemixErrorBoundary,
19
+ RouterContextProvider,
19
20
  RouterProvider,
20
21
  SINGLE_FETCH_REDIRECT_STATUS,
21
22
  SingleFetchRedirectSymbol,
@@ -23,6 +24,7 @@ import {
23
24
  StreamTransfer,
24
25
  convertRoutesToDataRoutes,
25
26
  createBrowserHistory,
27
+ createContext,
26
28
  createMemoryRouter,
27
29
  createRequestInit,
28
30
  createRouter,
@@ -31,6 +33,7 @@ import {
31
33
  createStaticRouter,
32
34
  decodeViaTurboStream,
33
35
  encode,
36
+ escapeHtml,
34
37
  getManifestPath,
35
38
  getSingleFetchDataStrategyImpl,
36
39
  getStaticContextFromError,
@@ -51,14 +54,12 @@ import {
51
54
  singleFetchUrl,
52
55
  stripBasename,
53
56
  stripIndexParam,
54
- unstable_RouterContextProvider,
55
- unstable_createContext,
56
57
  useRouteError,
57
58
  warnOnce,
58
59
  withComponentProps,
59
60
  withErrorBoundaryProps,
60
61
  withHydrateFallbackProps
61
- } from "./chunk-PVWAREVJ.mjs";
62
+ } from "./chunk-QZH3B547.mjs";
62
63
 
63
64
  // lib/dom/ssr/server.tsx
64
65
  import * as React from "react";
@@ -145,7 +146,7 @@ function createRoutesStub(routes, _context) {
145
146
  frameworkContextRef.current = {
146
147
  future: {
147
148
  unstable_subResourceIntegrity: future?.unstable_subResourceIntegrity === true,
148
- unstable_middleware: future?.unstable_middleware === true
149
+ v8_middleware: future?.v8_middleware === true
149
150
  },
150
151
  manifest: {
151
152
  routes: {},
@@ -162,7 +163,7 @@ function createRoutesStub(routes, _context) {
162
163
  // @ts-expect-error `StubRouteObject` is stricter about `loader`/`action`
163
164
  // types compared to `AgnosticRouteObject`
164
165
  convertRoutesToDataRoutes(routes, (r) => r),
165
- _context !== void 0 ? _context : future?.unstable_middleware ? new unstable_RouterContextProvider() : {},
166
+ _context !== void 0 ? _context : future?.v8_middleware ? new RouterContextProvider() : {},
166
167
  frameworkContextRef.current.manifest,
167
168
  frameworkContextRef.current.routeModules
168
169
  );
@@ -612,7 +613,7 @@ function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesBy
612
613
  hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
613
614
  id: route.id,
614
615
  path: route.path,
615
- unstable_middleware: route.module.unstable_middleware,
616
+ middleware: route.module.middleware,
616
617
  // Need to use RR's version in the param typed here to permit the optional
617
618
  // context even though we know it'll always be provided in remix
618
619
  loader: route.module.loader ? async (args) => {
@@ -677,19 +678,6 @@ function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesBy
677
678
  });
678
679
  }
679
680
 
680
- // lib/server-runtime/markup.ts
681
- var ESCAPE_LOOKUP = {
682
- "&": "\\u0026",
683
- ">": "\\u003e",
684
- "<": "\\u003c",
685
- "\u2028": "\\u2028",
686
- "\u2029": "\\u2029"
687
- };
688
- var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
689
- function escapeHtml(html) {
690
- return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
691
- }
692
-
693
681
  // lib/server-runtime/serverHandoff.ts
694
682
  function createServerHandoffString(serverHandoff) {
695
683
  return escapeHtml(JSON.stringify(serverHandoff));
@@ -785,7 +773,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
785
773
  requestContext: loadContext,
786
774
  skipLoaderErrorBubbling: true,
787
775
  skipRevalidation: true,
788
- unstable_generateMiddlewareResponse: build.future.unstable_middleware ? async (query) => {
776
+ generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
789
777
  try {
790
778
  let innerResult = await query(handlerRequest);
791
779
  return handleQueryResult(innerResult);
@@ -849,7 +837,7 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, han
849
837
  requestContext: loadContext,
850
838
  filterMatchesToLoad: (m) => !loadRouteIds || loadRouteIds.has(m.route.id),
851
839
  skipLoaderErrorBubbling: true,
852
- unstable_generateMiddlewareResponse: build.future.unstable_middleware ? async (query) => {
840
+ generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
853
841
  try {
854
842
  let innerResult = await query(handlerRequest);
855
843
  return handleQueryResult(innerResult);
@@ -1066,15 +1054,15 @@ var createRequestHandler = (build, mode) => {
1066
1054
  request
1067
1055
  });
1068
1056
  };
1069
- if (_build.future.unstable_middleware) {
1070
- if (initialContext && !(initialContext instanceof unstable_RouterContextProvider)) {
1057
+ if (_build.future.v8_middleware) {
1058
+ if (initialContext && !(initialContext instanceof RouterContextProvider)) {
1071
1059
  let error = new Error(
1072
- "Invalid `context` value provided to `handleRequest`. When middleware is enabled you must return an instance of `unstable_RouterContextProvider` from your `getLoadContext` function."
1060
+ "Invalid `context` value provided to `handleRequest`. When middleware is enabled you must return an instance of `RouterContextProvider` from your `getLoadContext` function."
1073
1061
  );
1074
1062
  handleError(error);
1075
1063
  return returnLastResortErrorResponse(error, serverMode);
1076
1064
  }
1077
- loadContext = initialContext || new unstable_RouterContextProvider();
1065
+ loadContext = initialContext || new RouterContextProvider();
1078
1066
  } else {
1079
1067
  loadContext = initialContext || {};
1080
1068
  }
@@ -1302,7 +1290,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
1302
1290
  try {
1303
1291
  let result = await staticHandler.query(request, {
1304
1292
  requestContext: loadContext,
1305
- unstable_generateMiddlewareResponse: build.future.unstable_middleware ? async (query) => {
1293
+ generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
1306
1294
  try {
1307
1295
  let innerResult = await query(request);
1308
1296
  if (!isResponse(innerResult)) {
@@ -1438,7 +1426,7 @@ async function handleResourceRequest(serverMode, build, staticHandler, routeId,
1438
1426
  let result = await staticHandler.queryRoute(request, {
1439
1427
  routeId,
1440
1428
  requestContext: loadContext,
1441
- unstable_generateMiddlewareResponse: build.future.unstable_middleware ? async (queryRoute) => {
1429
+ generateMiddlewareResponse: build.future.v8_middleware ? async (queryRoute) => {
1442
1430
  try {
1443
1431
  let innerResult = await queryRoute(request);
1444
1432
  return handleQueryRouteResult(innerResult);
@@ -1658,22 +1646,27 @@ function createMemorySessionStorage({ cookie } = {}) {
1658
1646
  // lib/href.ts
1659
1647
  function href(path, ...args) {
1660
1648
  let params = args[0];
1661
- return path.split("/").map((segment) => {
1662
- if (segment === "*") {
1663
- return params ? params["*"] : void 0;
1664
- }
1665
- const match = segment.match(/^:([\w-]+)(\?)?/);
1666
- if (!match) return segment;
1667
- const param = match[1];
1668
- const value = params ? params[param] : void 0;
1669
- const isRequired = match[2] === void 0;
1670
- if (isRequired && value === void 0) {
1671
- throw Error(
1672
- `Path '${path}' requires param '${param}' but it was not provided`
1673
- );
1649
+ let result = path.replace(/\/*\*?$/, "").replace(
1650
+ /\/:([\w-]+)(\?)?/g,
1651
+ // same regex as in .\router\utils.ts: compilePath().
1652
+ (_, param, questionMark) => {
1653
+ const isRequired = questionMark === void 0;
1654
+ const value = params ? params[param] : void 0;
1655
+ if (isRequired && value === void 0) {
1656
+ throw new Error(
1657
+ `Path '${path}' requires param '${param}' but it was not provided`
1658
+ );
1659
+ }
1660
+ return value === void 0 ? "" : "/" + value;
1674
1661
  }
1675
- return value;
1676
- }).filter((segment) => segment !== void 0).join("/");
1662
+ );
1663
+ if (path.endsWith("*")) {
1664
+ const value = params ? params["*"] : void 0;
1665
+ if (value !== void 0) {
1666
+ result += "/" + value;
1667
+ }
1668
+ }
1669
+ return result || "/";
1677
1670
  }
1678
1671
 
1679
1672
  // lib/rsc/browser.tsx
@@ -1681,7 +1674,14 @@ import * as React4 from "react";
1681
1674
  import * as ReactDOM from "react-dom";
1682
1675
 
1683
1676
  // lib/dom/ssr/hydration.tsx
1684
- function getHydrationData(state, routes, getRouteInfo, location2, basename, isSpaMode) {
1677
+ function getHydrationData({
1678
+ state,
1679
+ routes,
1680
+ getRouteInfo,
1681
+ location: location2,
1682
+ basename,
1683
+ isSpaMode
1684
+ }) {
1685
1685
  let hydrationData = {
1686
1686
  ...state,
1687
1687
  loaderData: { ...state.loaderData }
@@ -1933,7 +1933,7 @@ function createCallServer({
1933
1933
  function createRouterFromPayload({
1934
1934
  fetchImplementation,
1935
1935
  createFromReadableStream,
1936
- unstable_getContext,
1936
+ getContext,
1937
1937
  payload
1938
1938
  }) {
1939
1939
  const globalVar = window;
@@ -1971,17 +1971,17 @@ function createRouterFromPayload({
1971
1971
  }, []);
1972
1972
  globalVar.__reactRouterDataRouter = createRouter({
1973
1973
  routes,
1974
- unstable_getContext,
1974
+ getContext,
1975
1975
  basename: payload.basename,
1976
1976
  history: createBrowserHistory(),
1977
- hydrationData: getHydrationData(
1978
- {
1977
+ hydrationData: getHydrationData({
1978
+ state: {
1979
1979
  loaderData: payload.loaderData,
1980
1980
  actionData: payload.actionData,
1981
1981
  errors: payload.errors
1982
1982
  },
1983
1983
  routes,
1984
- (routeId) => {
1984
+ getRouteInfo: (routeId) => {
1985
1985
  let match = payload.matches.find((m) => m.id === routeId);
1986
1986
  invariant(match, "Route not found in payload");
1987
1987
  return {
@@ -1990,10 +1990,10 @@ function createRouterFromPayload({
1990
1990
  hasHydrateFallback: match.hydrateFallbackElement != null
1991
1991
  };
1992
1992
  },
1993
- payload.location,
1994
- void 0,
1995
- false
1996
- ),
1993
+ location: payload.location,
1994
+ basename: payload.basename,
1995
+ isSpaMode: false
1996
+ }),
1997
1997
  async patchRoutesOnNavigation({ path, signal }) {
1998
1998
  if (discoveredPaths.has(path)) {
1999
1999
  return;
@@ -2081,7 +2081,7 @@ function createRouterFromPayload({
2081
2081
  routeModules: globalVar.__reactRouterRouteModules
2082
2082
  };
2083
2083
  }
2084
- var renderedRoutesContext = unstable_createContext();
2084
+ var renderedRoutesContext = createContext();
2085
2085
  function getRSCSingleFetchDataStrategy(getRouter, ssr, basename, createFromReadableStream, fetchImplementation) {
2086
2086
  let dataStrategy = getSingleFetchDataStrategyImpl(
2087
2087
  getRouter,
@@ -2108,7 +2108,7 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, basename, createFromReada
2108
2108
  return M.route.hasComponent && !M.route.element;
2109
2109
  }
2110
2110
  );
2111
- return async (args) => args.unstable_runClientMiddleware(async () => {
2111
+ return async (args) => args.runClientMiddleware(async () => {
2112
2112
  let context = args.context;
2113
2113
  context.set(renderedRoutesContext, []);
2114
2114
  let results = await dataStrategy(args);
@@ -2194,22 +2194,17 @@ function RSCHydratedRouter({
2194
2194
  fetch: fetchImplementation = fetch,
2195
2195
  payload,
2196
2196
  routeDiscovery = "eager",
2197
- unstable_getContext
2197
+ getContext
2198
2198
  }) {
2199
2199
  if (payload.type !== "render") throw new Error("Invalid payload type");
2200
2200
  let { router, routeModules } = React4.useMemo(
2201
2201
  () => createRouterFromPayload({
2202
2202
  payload,
2203
2203
  fetchImplementation,
2204
- unstable_getContext,
2204
+ getContext,
2205
2205
  createFromReadableStream
2206
2206
  }),
2207
- [
2208
- createFromReadableStream,
2209
- payload,
2210
- fetchImplementation,
2211
- unstable_getContext
2212
- ]
2207
+ [createFromReadableStream, payload, fetchImplementation, getContext]
2213
2208
  );
2214
2209
  React4.useEffect(() => {
2215
2210
  setIsHydrated();
@@ -2281,7 +2276,7 @@ function RSCHydratedRouter({
2281
2276
  future: {
2282
2277
  // These flags have no runtime impact so can always be false. If we add
2283
2278
  // flags that drive runtime behavior they'll need to be proxied through.
2284
- unstable_middleware: false,
2279
+ v8_middleware: false,
2285
2280
  unstable_subResourceIntegrity: false
2286
2281
  },
2287
2282
  isSpaMode: false,
@@ -2574,19 +2569,48 @@ async function routeRSCServerRequest({
2574
2569
  if (!serverResponse.body) {
2575
2570
  throw new Error("Missing body in server response");
2576
2571
  }
2572
+ const detectRedirectResponse = serverResponse.clone();
2577
2573
  let serverResponseB = null;
2578
2574
  if (hydrate) {
2579
2575
  serverResponseB = serverResponse.clone();
2580
2576
  }
2581
2577
  const body = serverResponse.body;
2582
- let payloadPromise;
2578
+ let buffer;
2579
+ let streamControllers = [];
2580
+ const createStream = () => {
2581
+ if (!buffer) {
2582
+ buffer = [];
2583
+ return body.pipeThrough(
2584
+ new TransformStream({
2585
+ transform(chunk, controller) {
2586
+ buffer.push(chunk);
2587
+ controller.enqueue(chunk);
2588
+ streamControllers.forEach((c) => c.enqueue(chunk));
2589
+ },
2590
+ flush() {
2591
+ streamControllers.forEach((c) => c.close());
2592
+ streamControllers = [];
2593
+ }
2594
+ })
2595
+ );
2596
+ }
2597
+ return new ReadableStream({
2598
+ start(controller) {
2599
+ buffer.forEach((chunk) => controller.enqueue(chunk));
2600
+ streamControllers.push(controller);
2601
+ }
2602
+ });
2603
+ };
2583
2604
  const getPayload = async () => {
2584
- if (payloadPromise) return payloadPromise;
2585
- payloadPromise = createFromReadableStream(body);
2586
- return payloadPromise;
2605
+ return createFromReadableStream(createStream());
2587
2606
  };
2588
2607
  try {
2589
- const payload = await getPayload();
2608
+ if (!detectRedirectResponse.body) {
2609
+ throw new Error("Failed to clone server response");
2610
+ }
2611
+ const payload = await createFromReadableStream(
2612
+ detectRedirectResponse.body
2613
+ );
2590
2614
  if (serverResponse.status === SINGLE_FETCH_REDIRECT_STATUS && payload.type === "redirect") {
2591
2615
  const headers2 = new Headers(serverResponse.headers);
2592
2616
  headers2.delete("Content-Encoding");
@@ -2697,7 +2721,7 @@ function RSCStaticRouter({ getPayload }) {
2697
2721
  future: {
2698
2722
  // These flags have no runtime impact so can always be false. If we add
2699
2723
  // flags that drive runtime behavior they'll need to be proxied through.
2700
- unstable_middleware: false,
2724
+ v8_middleware: false,
2701
2725
  unstable_subResourceIntegrity: false
2702
2726
  },
2703
2727
  isSpaMode: false,