react-router 7.8.1-pre.1 → 7.8.2-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 (62) hide show
  1. package/CHANGELOG.md +13 -7
  2. package/dist/development/{chunk-74543KUN.mjs → chunk-5LNVHL6T.mjs} +185 -201
  3. package/dist/development/{chunk-5556IWOV.js → chunk-KUJAVZYD.js} +123 -180
  4. package/dist/{production/chunk-J44BHEXU.mjs → development/chunk-RVSOEW4N.mjs} +34 -75
  5. package/dist/{production/chunk-OE6UW5JS.js → development/chunk-UMVNFWBW.js} +210 -169
  6. package/dist/development/{context-DohQKLID.d.mts → context-D5hQ2yCL.d.mts} +843 -6
  7. package/dist/development/dom-export.d.mts +20 -2
  8. package/dist/development/dom-export.d.ts +20 -1
  9. package/dist/development/dom-export.js +10 -4
  10. package/dist/development/dom-export.mjs +10 -4
  11. package/dist/development/{index-react-server-client-BQ6FxdA_.d.ts → index-react-server-client-C4AMmMi3.d.ts} +6 -816
  12. package/dist/{production/index-react-server-client-11fLy3qB.d.mts → development/index-react-server-client-DgVbd8DS.d.mts} +2 -3
  13. package/dist/development/index-react-server-client.d.mts +3 -4
  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 +2 -2
  17. package/dist/development/index-react-server.d.mts +1 -1
  18. package/dist/development/index-react-server.d.ts +1 -1
  19. package/dist/development/index-react-server.js +39 -45
  20. package/dist/development/index-react-server.mjs +39 -45
  21. package/dist/development/index.d.mts +7 -9
  22. package/dist/development/index.d.ts +5 -5
  23. package/dist/development/index.js +122 -163
  24. package/dist/development/index.mjs +3 -3
  25. package/dist/development/lib/types/internal.d.mts +3 -3
  26. package/dist/development/lib/types/internal.d.ts +2 -2
  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-CNjObrhZ.d.mts → route-data-B3sNokxM.d.mts} +2 -2
  30. package/dist/{production/routeModules-C3oqzPpI.d.ts → development/routeModules-DRWHoPcT.d.ts} +844 -7
  31. package/dist/{development/chunk-3JDDYHAM.js → production/chunk-3PSRBVDP.js} +210 -169
  32. package/dist/{development/chunk-NL6TORMN.mjs → production/chunk-4HHN5NDL.mjs} +34 -75
  33. package/dist/production/{chunk-3OSMCWIR.js → chunk-NCRSBAFG.js} +123 -180
  34. package/dist/production/{chunk-HVGIEXH6.mjs → chunk-O46NJYOA.mjs} +185 -201
  35. package/dist/production/{context-DohQKLID.d.mts → context-D5hQ2yCL.d.mts} +843 -6
  36. package/dist/production/dom-export.d.mts +20 -2
  37. package/dist/production/dom-export.d.ts +20 -1
  38. package/dist/production/dom-export.js +10 -4
  39. package/dist/production/dom-export.mjs +10 -4
  40. package/dist/production/{index-react-server-client-BQ6FxdA_.d.ts → index-react-server-client-C4AMmMi3.d.ts} +6 -816
  41. package/dist/{development/index-react-server-client-11fLy3qB.d.mts → production/index-react-server-client-DgVbd8DS.d.mts} +2 -3
  42. package/dist/production/index-react-server-client.d.mts +3 -4
  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 +2 -2
  46. package/dist/production/index-react-server.d.mts +1 -1
  47. package/dist/production/index-react-server.d.ts +1 -1
  48. package/dist/production/index-react-server.js +39 -45
  49. package/dist/production/index-react-server.mjs +39 -45
  50. package/dist/production/index.d.mts +7 -9
  51. package/dist/production/index.d.ts +5 -5
  52. package/dist/production/index.js +122 -163
  53. package/dist/production/index.mjs +3 -3
  54. package/dist/production/lib/types/internal.d.mts +3 -3
  55. package/dist/production/lib/types/internal.d.ts +2 -2
  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-CNjObrhZ.d.mts → route-data-B3sNokxM.d.mts} +2 -2
  59. package/dist/{development/routeModules-C3oqzPpI.d.ts → production/routeModules-DRWHoPcT.d.ts} +844 -7
  60. package/package.json +1 -1
  61. package/dist/development/components-CuPfnyiZ.d.mts +0 -814
  62. package/dist/production/components-CuPfnyiZ.d.mts +0 -814
package/CHANGELOG.md CHANGED
@@ -1,13 +1,18 @@
1
1
  # `react-router`
2
2
 
3
- ## 7.8.1-pre.1
3
+ ## 7.8.2-pre.0
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - Propagate non-redirect Responses thrown from middleware to the error boundary on document/data requests ([#14182](https://github.com/remix-run/react-router/pull/14182))
8
- - [REMOVE] Update data -> Response conversion (update changelog with latest from `rotten-steaks-perform.md`) ([#14181](https://github.com/remix-run/react-router/pull/14181))
7
+ - [UNSTABLE] Add `<RouterProvider unstable_onError>`/`<HydratedRouter unstable_onError>` prop for client side error reporting ([#14162](https://github.com/remix-run/react-router/pull/14162))
8
+ - Properly escape interpolated param values in `generatePath()` ([#13530](https://github.com/remix-run/react-router/pull/13530))
9
+ - Maintain `ReadonlyMap` and `ReadonlySet` types in server response data. ([#13092](https://github.com/remix-run/react-router/pull/13092))
10
+ - [UNSTABLE] Delay serialization of `.data` redirects to 202 responses until after middleware chain ([#14205](https://github.com/remix-run/react-router/pull/14205))
11
+ - Fix `TypeError` if you throw from `patchRoutesOnNavigation` when no partial matches exist ([#14198](https://github.com/remix-run/react-router/pull/14198))
12
+ - Fix `basename` usage without a leading slash in data routers ([#11671](https://github.com/remix-run/react-router/pull/11671))
13
+ - [UNSTABLE] Update client middleware so it returns the data strategy results allowing for more advanced post-processing middleware ([#14151](https://github.com/remix-run/react-router/pull/14151))
9
14
 
10
- ## 7.8.1-pre.0
15
+ ## 7.8.1
11
16
 
12
17
  ### Patch Changes
13
18
 
@@ -16,8 +21,9 @@
16
21
  - Fix optional static segment matching in `matchPath` ([#11813](https://github.com/remix-run/react-router/pull/11813))
17
22
  - Fix prerendering when a `basename` is set with `ssr:false` ([#13791](https://github.com/remix-run/react-router/pull/13791))
18
23
  - Provide `isRouteErrorResponse` utility in `react-server` environments ([#14166](https://github.com/remix-run/react-router/pull/14166))
24
+ - Propagate non-redirect Responses thrown from middleware to the error boundary on document/data requests ([#14182](https://github.com/remix-run/react-router/pull/14182))
19
25
  - Handle `meta` and `links` Route Exports in RSC Data Mode ([#14136](https://github.com/remix-run/react-router/pull/14136))
20
- - Properly handle data() values returned or thrown from resource routes and return corresponding responses with the data, status, and headers ([#14159](https://github.com/remix-run/react-router/pull/14159))
26
+ - Properly convert returned/thrown `data()` values to `Response` instances via `Response.json()` in resource routes and middleware ([#14159](https://github.com/remix-run/react-router/pull/14159), [#14181](https://github.com/remix-run/react-router/pull/14181))
21
27
 
22
28
  ## 7.8.0
23
29
 
@@ -111,9 +117,9 @@
111
117
  - \[UNSTABLE] Change the `unstable_getContext` signature on `RouterProvider`/`HydratedRouter`/`unstable_RSCHydratedRouter` so that it returns an `unstable_RouterContextProvider` instance instead of a `Map` used to contruct the instance internally ([#14097](https://github.com/remix-run/react-router/pull/14097))
112
118
  - ⚠️ This is a breaking change if you have adopted the `unstable_getContext` prop
113
119
 
114
- - [UNSTABLE] proxy server action side-effect redirects from actions for document and callServer requests ([#14131](https://github.com/remix-run/react-router/pull/14131))
120
+ - \[UNSTABLE] proxy server action side-effect redirects from actions for document and callServer requests ([#14131](https://github.com/remix-run/react-router/pull/14131))
115
121
 
116
- - [UNSTABLE] Fix RSC Data Mode issue where routes that return `false` from `shouldRevalidate` would be replaced by an `<Outlet />` ([#14071](https://github.com/remix-run/react-router/pull/14071))
122
+ - \[UNSTABLE] Fix RSC Data Mode issue where routes that return `false` from `shouldRevalidate` would be replaced by an `<Outlet />` ([#14071](https://github.com/remix-run/react-router/pull/14071))
117
123
 
118
124
  ## 7.7.1
119
125
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.8.1-pre.1
2
+ * react-router v7.8.2-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -699,7 +699,7 @@ function generatePath(originalPath, params = {}) {
699
699
  const [, key, optional] = keyMatch;
700
700
  let param = params[key];
701
701
  invariant(optional === "?" || param != null, `Missing ":${key}" param`);
702
- return stringify2(param);
702
+ return encodeURIComponent(stringify2(param));
703
703
  }
704
704
  return segment.replace(/\?$/g, "");
705
705
  }).filter((segment) => !!segment);
@@ -1004,6 +1004,9 @@ function createRouter(init) {
1004
1004
  );
1005
1005
  let inFlightDataRoutes;
1006
1006
  let basename = init.basename || "/";
1007
+ if (!basename.startsWith("/")) {
1008
+ basename = `/${basename}`;
1009
+ }
1007
1010
  let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
1008
1011
  let future = {
1009
1012
  unstable_middleware: false,
@@ -1553,6 +1556,19 @@ function createRouter(init) {
1553
1556
  if (discoverResult.type === "aborted") {
1554
1557
  return { shortCircuited: true };
1555
1558
  } else if (discoverResult.type === "error") {
1559
+ if (discoverResult.partialMatches.length === 0) {
1560
+ let { matches: matches2, route } = getShortCircuitMatches(dataRoutes);
1561
+ return {
1562
+ matches: matches2,
1563
+ pendingActionResult: [
1564
+ route.id,
1565
+ {
1566
+ type: "error" /* error */,
1567
+ error: discoverResult.error
1568
+ }
1569
+ ]
1570
+ };
1571
+ }
1556
1572
  let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1557
1573
  return {
1558
1574
  matches: discoverResult.partialMatches,
@@ -1684,6 +1700,16 @@ function createRouter(init) {
1684
1700
  if (discoverResult.type === "aborted") {
1685
1701
  return { shortCircuited: true };
1686
1702
  } else if (discoverResult.type === "error") {
1703
+ if (discoverResult.partialMatches.length === 0) {
1704
+ let { matches: matches2, route } = getShortCircuitMatches(dataRoutes);
1705
+ return {
1706
+ matches: matches2,
1707
+ loaderData: {},
1708
+ errors: {
1709
+ [route.id]: discoverResult.error
1710
+ }
1711
+ };
1712
+ }
1687
1713
  let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1688
1714
  return {
1689
1715
  matches: discoverResult.partialMatches,
@@ -3947,198 +3973,116 @@ async function defaultDataStrategyWithMiddleware(args) {
3947
3973
  if (!args.matches.some((m) => m.route.unstable_middleware)) {
3948
3974
  return defaultDataStrategy(args);
3949
3975
  }
3950
- let didCallHandler = false;
3951
- return runClientMiddlewarePipeline(
3976
+ return runClientMiddlewarePipeline(args, () => defaultDataStrategy(args));
3977
+ }
3978
+ function runServerMiddlewarePipeline(args, handler, errorHandler) {
3979
+ return runMiddlewarePipeline(
3952
3980
  args,
3953
- () => {
3954
- didCallHandler = true;
3955
- return defaultDataStrategy(args);
3956
- },
3957
- (error, routeId) => clientMiddlewareErrorHandler(
3958
- error,
3959
- routeId,
3960
- args.matches,
3961
- didCallHandler
3962
- )
3981
+ handler,
3982
+ processResult,
3983
+ isResponse,
3984
+ errorHandler
3963
3985
  );
3964
- }
3965
- function clientMiddlewareErrorHandler(error, routeId, matches, didCallHandler) {
3966
- if (didCallHandler) {
3967
- return {
3968
- [routeId]: { type: "error", result: error }
3969
- };
3970
- } else {
3971
- let maxBoundaryIdx = Math.min(
3972
- // Throwing route
3973
- matches.findIndex((m) => m.route.id === routeId) || 0,
3974
- // or the shallowest route that needs to load data
3975
- matches.findIndex((m) => m.unstable_shouldCallHandler()) || 0
3976
- );
3977
- let boundaryRouteId = findNearestBoundary(
3978
- matches,
3979
- matches[maxBoundaryIdx].route.id
3980
- ).route.id;
3981
- return {
3982
- [boundaryRouteId]: { type: "error", result: error }
3983
- };
3986
+ function processResult(result) {
3987
+ return isDataWithResponseInit(result) ? dataWithResponseInitToResponse(result) : result;
3984
3988
  }
3985
3989
  }
3986
- async function runServerMiddlewarePipeline(args, handler, errorHandler) {
3987
- let { matches, request, params, context } = args;
3988
- let tuples = matches.flatMap(
3989
- (m) => m.route.unstable_middleware ? m.route.unstable_middleware.map((fn) => [m.route.id, fn]) : []
3990
- );
3991
- let result = await callServerRouteMiddleware(
3992
- { request, params, context },
3993
- tuples,
3990
+ function runClientMiddlewarePipeline(args, handler) {
3991
+ return runMiddlewarePipeline(
3992
+ args,
3994
3993
  handler,
3994
+ (r) => r,
3995
+ // No post-processing needed on the client
3996
+ isDataStrategyResults,
3995
3997
  errorHandler
3996
3998
  );
3997
- if (isResponse(result)) {
3998
- return result;
3999
- }
4000
- invariant(false, `Expected a Response to be returned from route middleware`);
4001
- }
4002
- async function callServerRouteMiddleware(args, middlewares, handler, errorHandler, idx = 0) {
4003
- let { request } = args;
4004
- if (request.signal.aborted) {
4005
- if (request.signal.reason) {
4006
- throw request.signal.reason;
4007
- }
4008
- throw new Error(
4009
- `Request aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
4010
- );
4011
- }
4012
- let tuple = middlewares[idx];
4013
- if (!tuple) {
4014
- let result = await handler();
4015
- return result;
4016
- }
4017
- let [routeId, middleware] = tuple;
4018
- let nextCalled = false;
4019
- let nextResult = void 0;
4020
- let next = async () => {
4021
- if (nextCalled) {
4022
- throw new Error("You may only call `next()` once per middleware");
4023
- }
4024
- nextCalled = true;
4025
- try {
4026
- let result = await callServerRouteMiddleware(
4027
- args,
4028
- middlewares,
4029
- handler,
4030
- errorHandler,
4031
- idx + 1
3999
+ function errorHandler(error, routeId, nextResult) {
4000
+ if (nextResult) {
4001
+ return Promise.resolve(
4002
+ Object.assign(nextResult.value, {
4003
+ [routeId]: { type: "error", result: error }
4004
+ })
4032
4005
  );
4033
- if (isDataWithResponseInit(result)) {
4034
- result = dataWithResponseInitToResponse(result);
4035
- }
4036
- nextResult = result;
4037
- return nextResult;
4038
- } catch (e) {
4039
- nextResult = await errorHandler(e, routeId);
4040
- return nextResult;
4041
- }
4042
- };
4043
- try {
4044
- let result = await middleware(
4045
- {
4046
- request: args.request,
4047
- params: args.params,
4048
- context: args.context
4049
- },
4050
- next
4051
- );
4052
- if (isDataWithResponseInit(result)) {
4053
- result = dataWithResponseInitToResponse(result);
4054
- }
4055
- if (nextCalled) {
4056
- return typeof result === "undefined" ? nextResult : result;
4057
- } else if (isResponse(result)) {
4058
- return result;
4059
4006
  } else {
4060
- nextResult = await next();
4061
- return nextResult;
4007
+ let { matches } = args;
4008
+ let maxBoundaryIdx = Math.min(
4009
+ // Throwing route
4010
+ matches.findIndex((m) => m.route.id === routeId) || 0,
4011
+ // or the shallowest route that needs to load data
4012
+ matches.findIndex((m) => m.unstable_shouldCallHandler()) || 0
4013
+ );
4014
+ let boundaryRouteId = findNearestBoundary(
4015
+ matches,
4016
+ matches[maxBoundaryIdx].route.id
4017
+ ).route.id;
4018
+ return Promise.resolve({
4019
+ [boundaryRouteId]: { type: "error", result: error }
4020
+ });
4062
4021
  }
4063
- } catch (e) {
4064
- let response = await errorHandler(e, routeId);
4065
- return response;
4066
4022
  }
4067
4023
  }
4068
- async function runClientMiddlewarePipeline(args, handler, errorHandler) {
4024
+ async function runMiddlewarePipeline(args, handler, processResult, isResult, errorHandler) {
4069
4025
  let { matches, request, params, context } = args;
4070
4026
  let tuples = matches.flatMap(
4071
4027
  (m) => m.route.unstable_middleware ? m.route.unstable_middleware.map((fn) => [m.route.id, fn]) : []
4072
4028
  );
4073
- let handlerResult = {};
4074
- await callClientRouteMiddleware(
4029
+ let result = await callRouteMiddleware(
4075
4030
  { request, params, context },
4076
4031
  tuples,
4077
4032
  handler,
4078
- errorHandler,
4079
- handlerResult
4033
+ processResult,
4034
+ isResult,
4035
+ errorHandler
4080
4036
  );
4081
- return handlerResult;
4037
+ return result;
4082
4038
  }
4083
- async function callClientRouteMiddleware(args, middlewares, handler, errorHandler, handlerResult = {}, idx = 0) {
4039
+ async function callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx = 0) {
4084
4040
  let { request } = args;
4085
4041
  if (request.signal.aborted) {
4086
- if (request.signal.reason) {
4087
- throw request.signal.reason;
4088
- }
4089
- throw new Error(
4090
- `Request aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
4091
- );
4042
+ throw request.signal.reason ?? new Error(`Request aborted: ${request.method} ${request.url}`);
4092
4043
  }
4093
4044
  let tuple = middlewares[idx];
4094
4045
  if (!tuple) {
4095
4046
  let result = await handler();
4096
- Object.assign(handlerResult, result);
4097
- return;
4047
+ return result;
4098
4048
  }
4099
4049
  let [routeId, middleware] = tuple;
4100
- let nextCalled = false;
4050
+ let nextResult;
4101
4051
  let next = async () => {
4102
- if (nextCalled) {
4052
+ if (nextResult) {
4103
4053
  throw new Error("You may only call `next()` once per middleware");
4104
4054
  }
4105
- nextCalled = true;
4106
4055
  try {
4107
- let result = await callClientRouteMiddleware(
4056
+ let result = await callRouteMiddleware(
4108
4057
  args,
4109
4058
  middlewares,
4110
4059
  handler,
4060
+ processResult,
4061
+ isResult,
4111
4062
  errorHandler,
4112
- handlerResult,
4113
4063
  idx + 1
4114
4064
  );
4115
- Object.assign(handlerResult, result);
4116
- } catch (e) {
4117
- let result = await errorHandler(e, routeId);
4118
- Object.assign(handlerResult, result);
4065
+ nextResult = { value: result };
4066
+ return nextResult.value;
4067
+ } catch (error) {
4068
+ nextResult = { value: await errorHandler(error, routeId, nextResult) };
4069
+ return nextResult.value;
4119
4070
  }
4120
4071
  };
4121
4072
  try {
4122
- let result = await middleware(
4123
- {
4124
- request: args.request,
4125
- params: args.params,
4126
- context: args.context
4127
- },
4128
- next
4129
- );
4130
- if (typeof result !== "undefined") {
4131
- console.warn(
4132
- "client middlewares are not intended to return values, the value will be ignored",
4133
- result
4134
- );
4135
- }
4136
- if (!nextCalled) {
4137
- await next();
4073
+ let value = await middleware(args, next);
4074
+ let result = value != null ? processResult(value) : void 0;
4075
+ if (isResult(result)) {
4076
+ return result;
4077
+ } else if (nextResult) {
4078
+ return result ?? nextResult.value;
4079
+ } else {
4080
+ nextResult = { value: await next() };
4081
+ return nextResult.value;
4138
4082
  }
4139
4083
  } catch (error) {
4140
- let result = await errorHandler(error, routeId);
4141
- Object.assign(handlerResult, result);
4084
+ let response = await errorHandler(error, routeId, nextResult);
4085
+ return response;
4142
4086
  }
4143
4087
  }
4144
4088
  function getDataStrategyMatchLazyPromises(mapRouteProperties2, manifest, request, match, lazyRoutePropertiesToSkip) {
@@ -4249,28 +4193,17 @@ async function callDataStrategyImpl(dataStrategyImpl, request, matches, fetcherK
4249
4193
  );
4250
4194
  } : (cb) => {
4251
4195
  let typedDataStrategyArgs = dataStrategyArgs;
4252
- let didCallHandler = false;
4253
- return runClientMiddlewarePipeline(
4254
- typedDataStrategyArgs,
4255
- () => {
4256
- didCallHandler = true;
4257
- return cb({
4258
- ...typedDataStrategyArgs,
4259
- fetcherKey,
4260
- unstable_runClientMiddleware: () => {
4261
- throw new Error(
4262
- "Cannot call `unstable_runClientMiddleware()` from within an `unstable_runClientMiddleware` handler"
4263
- );
4264
- }
4265
- });
4266
- },
4267
- (error, routeId) => clientMiddlewareErrorHandler(
4268
- error,
4269
- routeId,
4270
- matches,
4271
- didCallHandler
4272
- )
4273
- );
4196
+ return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {
4197
+ return cb({
4198
+ ...typedDataStrategyArgs,
4199
+ fetcherKey,
4200
+ unstable_runClientMiddleware: () => {
4201
+ throw new Error(
4202
+ "Cannot call `unstable_runClientMiddleware()` from within an `unstable_runClientMiddleware` handler"
4203
+ );
4204
+ }
4205
+ });
4206
+ });
4274
4207
  };
4275
4208
  let results = await dataStrategyImpl({
4276
4209
  ...dataStrategyArgs,
@@ -4738,6 +4671,11 @@ function dataWithResponseInitToErrorResponse(data2) {
4738
4671
  data2.data
4739
4672
  );
4740
4673
  }
4674
+ function isDataStrategyResults(result) {
4675
+ return result != null && typeof result === "object" && Object.entries(result).every(
4676
+ ([key, value]) => typeof key === "string" && isDataStrategyResult(value)
4677
+ );
4678
+ }
4741
4679
  function isDataStrategyResult(result) {
4742
4680
  return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" /* data */ || result.type === "error" /* error */);
4743
4681
  }
@@ -5145,7 +5083,7 @@ function useResolvedPath(to, { relative } = {}) {
5145
5083
  function useRoutes(routes, locationArg) {
5146
5084
  return useRoutesImpl(routes, locationArg);
5147
5085
  }
5148
- function useRoutesImpl(routes, locationArg, dataRouterState, future) {
5086
+ function useRoutesImpl(routes, locationArg, dataRouterState, unstable_onError, future) {
5149
5087
  invariant(
5150
5088
  useInRouterContext(),
5151
5089
  // TODO: This error is probably because they somehow have 2 versions of the
@@ -5217,6 +5155,7 @@ Please change the parent <Route path="${parentPath}"> to <Route path="${parentPa
5217
5155
  ),
5218
5156
  parentMatches,
5219
5157
  dataRouterState,
5158
+ unstable_onError,
5220
5159
  future
5221
5160
  );
5222
5161
  if (locationArg && renderedMatches) {
@@ -5285,11 +5224,14 @@ var RenderErrorBoundary = class extends React2.Component {
5285
5224
  };
5286
5225
  }
5287
5226
  componentDidCatch(error, errorInfo) {
5288
- console.error(
5289
- "React Router caught the following error during render",
5290
- error,
5291
- errorInfo
5292
- );
5227
+ if (this.props.unstable_onError) {
5228
+ this.props.unstable_onError(error, errorInfo);
5229
+ } else {
5230
+ console.error(
5231
+ "React Router caught the following error during render",
5232
+ error
5233
+ );
5234
+ }
5293
5235
  }
5294
5236
  render() {
5295
5237
  return this.state.error !== void 0 ? /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React2.createElement(
@@ -5308,7 +5250,7 @@ function RenderedRoute({ routeContext, match, children }) {
5308
5250
  }
5309
5251
  return /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: routeContext }, children);
5310
5252
  }
5311
- function _renderMatches(matches, parentMatches = [], dataRouterState = null, future = null) {
5253
+ function _renderMatches(matches, parentMatches = [], dataRouterState = null, unstable_onError = null, future = null) {
5312
5254
  if (matches == null) {
5313
5255
  if (!dataRouterState) {
5314
5256
  return null;
@@ -5420,7 +5362,8 @@ function _renderMatches(matches, parentMatches = [], dataRouterState = null, fut
5420
5362
  component: errorElement,
5421
5363
  error,
5422
5364
  children: getChildren(),
5423
- routeContext: { outlet: null, matches: matches2, isDataRoute: true }
5365
+ routeContext: { outlet: null, matches: matches2, isDataRoute: true },
5366
+ unstable_onError
5424
5367
  }
5425
5368
  ) : getChildren();
5426
5369
  },
@@ -5686,7 +5629,8 @@ var Deferred = class {
5686
5629
  };
5687
5630
  function RouterProvider({
5688
5631
  router,
5689
- flushSync: reactDomFlushSyncImpl
5632
+ flushSync: reactDomFlushSyncImpl,
5633
+ unstable_onError
5690
5634
  }) {
5691
5635
  let [state, setStateImpl] = React3.useState(router.state);
5692
5636
  let [pendingState, setPendingState] = React3.useState();
@@ -5697,6 +5641,21 @@ function RouterProvider({
5697
5641
  let [transition, setTransition] = React3.useState();
5698
5642
  let [interruption, setInterruption] = React3.useState();
5699
5643
  let fetcherData = React3.useRef(/* @__PURE__ */ new Map());
5644
+ let logErrorsAndSetState = React3.useCallback(
5645
+ (newState) => {
5646
+ setStateImpl((prevState) => {
5647
+ if (newState.errors && unstable_onError) {
5648
+ Object.entries(newState.errors).forEach(([routeId, error]) => {
5649
+ if (prevState.errors?.[routeId] !== error) {
5650
+ unstable_onError(error);
5651
+ }
5652
+ });
5653
+ }
5654
+ return newState;
5655
+ });
5656
+ },
5657
+ [unstable_onError]
5658
+ );
5700
5659
  let setState = React3.useCallback(
5701
5660
  (newState, { deletedFetchers, flushSync, viewTransitionOpts }) => {
5702
5661
  newState.fetchers.forEach((fetcher, key) => {
@@ -5716,9 +5675,9 @@ function RouterProvider({
5716
5675
  );
5717
5676
  if (!viewTransitionOpts || !isViewTransitionAvailable) {
5718
5677
  if (reactDomFlushSyncImpl && flushSync) {
5719
- reactDomFlushSyncImpl(() => setStateImpl(newState));
5678
+ reactDomFlushSyncImpl(() => logErrorsAndSetState(newState));
5720
5679
  } else {
5721
- React3.startTransition(() => setStateImpl(newState));
5680
+ React3.startTransition(() => logErrorsAndSetState(newState));
5722
5681
  }
5723
5682
  return;
5724
5683
  }
@@ -5736,7 +5695,7 @@ function RouterProvider({
5736
5695
  });
5737
5696
  });
5738
5697
  let t = router.window.document.startViewTransition(() => {
5739
- reactDomFlushSyncImpl(() => setStateImpl(newState));
5698
+ reactDomFlushSyncImpl(() => logErrorsAndSetState(newState));
5740
5699
  });
5741
5700
  t.finished.finally(() => {
5742
5701
  reactDomFlushSyncImpl(() => {
@@ -5767,7 +5726,13 @@ function RouterProvider({
5767
5726
  });
5768
5727
  }
5769
5728
  },
5770
- [router.window, reactDomFlushSyncImpl, transition, renderDfd]
5729
+ [
5730
+ router.window,
5731
+ reactDomFlushSyncImpl,
5732
+ transition,
5733
+ renderDfd,
5734
+ logErrorsAndSetState
5735
+ ]
5771
5736
  );
5772
5737
  React3.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
5773
5738
  React3.useEffect(() => {
@@ -5780,7 +5745,7 @@ function RouterProvider({
5780
5745
  let newState = pendingState;
5781
5746
  let renderPromise = renderDfd.promise;
5782
5747
  let transition2 = router.window.document.startViewTransition(async () => {
5783
- React3.startTransition(() => setStateImpl(newState));
5748
+ React3.startTransition(() => logErrorsAndSetState(newState));
5784
5749
  await renderPromise;
5785
5750
  });
5786
5751
  transition2.finished.finally(() => {
@@ -5791,7 +5756,7 @@ function RouterProvider({
5791
5756
  });
5792
5757
  setTransition(transition2);
5793
5758
  }
5794
- }, [pendingState, renderDfd, router.window]);
5759
+ }, [pendingState, renderDfd, router.window, logErrorsAndSetState]);
5795
5760
  React3.useEffect(() => {
5796
5761
  if (renderDfd && pendingState && state.location.key === pendingState.location.key) {
5797
5762
  renderDfd.resolve();
@@ -5831,9 +5796,10 @@ function RouterProvider({
5831
5796
  router,
5832
5797
  navigator,
5833
5798
  static: false,
5834
- basename
5799
+ basename,
5800
+ unstable_onError
5835
5801
  }),
5836
- [router, navigator, basename]
5802
+ [router, navigator, basename, unstable_onError]
5837
5803
  );
5838
5804
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(DataRouterContext.Provider, { value: dataRouterContext }, /* @__PURE__ */ React3.createElement(DataRouterStateContext.Provider, { value: state }, /* @__PURE__ */ React3.createElement(FetchersContext.Provider, { value: fetcherData.current }, /* @__PURE__ */ React3.createElement(ViewTransitionContext.Provider, { value: vtContext }, /* @__PURE__ */ React3.createElement(
5839
5805
  Router,
@@ -5848,7 +5814,8 @@ function RouterProvider({
5848
5814
  {
5849
5815
  routes: router.routes,
5850
5816
  future: router.future,
5851
- state
5817
+ state,
5818
+ unstable_onError
5852
5819
  }
5853
5820
  )
5854
5821
  ))))), null);
@@ -5857,9 +5824,10 @@ var MemoizedDataRoutes = React3.memo(DataRoutes);
5857
5824
  function DataRoutes({
5858
5825
  routes,
5859
5826
  future,
5860
- state
5827
+ state,
5828
+ unstable_onError
5861
5829
  }) {
5862
- return useRoutesImpl(routes, void 0, state, future);
5830
+ return useRoutesImpl(routes, void 0, state, unstable_onError, future);
5863
5831
  }
5864
5832
  function MemoryRouter({
5865
5833
  basename,
@@ -6007,7 +5975,16 @@ function Await({
6007
5975
  errorElement,
6008
5976
  resolve
6009
5977
  }) {
6010
- return /* @__PURE__ */ React3.createElement(AwaitErrorBoundary, { resolve, errorElement }, /* @__PURE__ */ React3.createElement(ResolveAwait, null, children));
5978
+ let dataRouterContext = React3.useContext(DataRouterContext);
5979
+ return /* @__PURE__ */ React3.createElement(
5980
+ AwaitErrorBoundary,
5981
+ {
5982
+ resolve,
5983
+ errorElement,
5984
+ unstable_onError: dataRouterContext?.unstable_onError
5985
+ },
5986
+ /* @__PURE__ */ React3.createElement(ResolveAwait, null, children)
5987
+ );
6011
5988
  }
6012
5989
  var AwaitErrorBoundary = class extends React3.Component {
6013
5990
  constructor(props) {
@@ -6018,11 +5995,15 @@ var AwaitErrorBoundary = class extends React3.Component {
6018
5995
  return { error };
6019
5996
  }
6020
5997
  componentDidCatch(error, errorInfo) {
6021
- console.error(
6022
- "<Await> caught the following error during render",
6023
- error,
6024
- errorInfo
6025
- );
5998
+ if (this.props.unstable_onError) {
5999
+ this.props.unstable_onError(error, errorInfo);
6000
+ } else {
6001
+ console.error(
6002
+ "<Await> caught the following error during render",
6003
+ error,
6004
+ errorInfo
6005
+ );
6006
+ }
6026
6007
  }
6027
6008
  render() {
6028
6009
  let { children, errorElement, resolve } = this.props;
@@ -6048,7 +6029,10 @@ var AwaitErrorBoundary = class extends React3.Component {
6048
6029
  Object.defineProperty(resolve, "_tracked", { get: () => true });
6049
6030
  promise = resolve.then(
6050
6031
  (data2) => Object.defineProperty(resolve, "_data", { get: () => data2 }),
6051
- (error) => Object.defineProperty(resolve, "_error", { get: () => error })
6032
+ (error) => {
6033
+ this.props.unstable_onError?.(error);
6034
+ Object.defineProperty(resolve, "_error", { get: () => error });
6035
+ }
6052
6036
  );
6053
6037
  }
6054
6038
  if (status === 2 /* error */ && !errorElement) {
@@ -8986,7 +8970,7 @@ var isBrowser = typeof window !== "undefined" && typeof window.document !== "und
8986
8970
  try {
8987
8971
  if (isBrowser) {
8988
8972
  window.__reactRouterVersion = // @ts-expect-error
8989
- "7.8.1-pre.1";
8973
+ "7.8.2-pre.0";
8990
8974
  }
8991
8975
  } catch (e) {
8992
8976
  }
@@ -9893,7 +9877,7 @@ function DataRoutes2({
9893
9877
  future,
9894
9878
  state
9895
9879
  }) {
9896
- return useRoutesImpl(routes, void 0, state, future);
9880
+ return useRoutesImpl(routes, void 0, state, void 0, future);
9897
9881
  }
9898
9882
  function serializeErrors(errors) {
9899
9883
  if (!errors) return null;