react-router 8.5.0 → 8.5.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 (204) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/dist/development/dom-export.js +1 -1
  3. package/dist/development/index-react-server-client.js +1 -1
  4. package/dist/development/index-react-server.d.ts +50 -396
  5. package/dist/development/index-react-server.js +43 -15
  6. package/dist/development/index.js +1 -1
  7. package/dist/development/lib/actions.js +1 -1
  8. package/dist/development/lib/await.js +58 -0
  9. package/dist/development/lib/components.d.ts +41 -5
  10. package/dist/development/lib/components.js +62 -4
  11. package/dist/development/lib/context.d.ts +2 -2
  12. package/dist/development/lib/context.js +1 -1
  13. package/dist/development/lib/dom/dom.js +1 -1
  14. package/dist/development/lib/dom/lib.js +1 -1
  15. package/dist/development/lib/dom/server.js +1 -1
  16. package/dist/development/lib/dom/ssr/components.js +1 -1
  17. package/dist/development/lib/dom/ssr/data.js +1 -1
  18. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  19. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  20. package/dist/development/lib/dom/ssr/fog-of-war.js +12 -3
  21. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  22. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  23. package/dist/development/lib/dom/ssr/links.js +1 -1
  24. package/dist/development/lib/dom/ssr/markup.js +1 -1
  25. package/dist/development/lib/dom/ssr/route-discovery.d.ts +2 -2
  26. package/dist/development/lib/dom/ssr/route-discovery.js +3 -3
  27. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  28. package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
  29. package/dist/development/lib/dom/ssr/routes.js +1 -1
  30. package/dist/development/lib/dom/ssr/server.js +1 -1
  31. package/dist/development/lib/dom/ssr/single-fetch.d.ts +1 -1
  32. package/dist/development/lib/dom/ssr/single-fetch.js +7 -7
  33. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  34. package/dist/development/lib/dom-export/hydrated-router.js +2 -2
  35. package/dist/development/lib/errors.js +1 -1
  36. package/dist/development/lib/hooks.d.ts +0 -3
  37. package/dist/development/lib/hooks.js +5 -6
  38. package/dist/development/lib/href.js +1 -1
  39. package/dist/development/lib/router/history.js +1 -1
  40. package/dist/development/lib/router/instrumentation.js +1 -1
  41. package/dist/development/lib/router/matcher-route-pattern.js +1 -1
  42. package/dist/development/lib/router/matcher-route-pattern.preload.js +1 -1
  43. package/dist/development/lib/router/matcher.js +6 -1
  44. package/dist/development/lib/router/navigation.js +1 -1
  45. package/dist/development/lib/router/router.d.ts +2 -0
  46. package/dist/development/lib/router/router.js +58 -28
  47. package/dist/development/lib/router/url.js +1 -1
  48. package/dist/development/lib/router/utils.d.ts +7 -0
  49. package/dist/development/lib/router/utils.js +1 -1
  50. package/dist/development/lib/rsc/browser.js +3 -3
  51. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  52. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  53. package/dist/development/lib/rsc/html-stream/server.js +1 -1
  54. package/dist/development/lib/rsc/route-modules.js +1 -1
  55. package/dist/development/lib/rsc/server.ssr.js +1 -1
  56. package/dist/development/lib/server-runtime/cookies.js +1 -1
  57. package/dist/development/lib/server-runtime/crypto.js +1 -1
  58. package/dist/development/lib/server-runtime/data.js +1 -1
  59. package/dist/development/lib/server-runtime/dev.js +1 -1
  60. package/dist/development/lib/server-runtime/entry.js +1 -1
  61. package/dist/development/lib/server-runtime/errors.js +1 -1
  62. package/dist/development/lib/server-runtime/headers.js +1 -1
  63. package/dist/development/lib/server-runtime/invariant.js +1 -1
  64. package/dist/development/lib/server-runtime/mode.js +1 -1
  65. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  66. package/dist/development/lib/server-runtime/routes.js +1 -1
  67. package/dist/development/lib/server-runtime/server.js +13 -5
  68. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  69. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  70. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  71. package/dist/development/lib/server-runtime/sessions.js +2 -2
  72. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  73. package/dist/development/lib/server-runtime/urls.js +1 -1
  74. package/dist/development/lib/server-runtime/warnings.js +1 -1
  75. package/dist/development/lib/types/internal.js +1 -1
  76. package/dist/development/route-pattern.js +1 -1
  77. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  78. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  79. package/dist/development/vendor/turbo-stream-v2/unflatten.js +23 -3
  80. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  81. package/dist/production/dom-export.js +1 -1
  82. package/dist/production/index-react-server-client.js +1 -1
  83. package/dist/production/index-react-server.d.ts +50 -396
  84. package/dist/production/index-react-server.js +43 -15
  85. package/dist/production/index.js +1 -1
  86. package/dist/production/lib/actions.js +1 -1
  87. package/dist/production/lib/await.js +58 -0
  88. package/dist/production/lib/components.d.ts +41 -5
  89. package/dist/production/lib/components.js +62 -4
  90. package/dist/production/lib/context.d.ts +2 -2
  91. package/dist/production/lib/context.js +1 -1
  92. package/dist/production/lib/dom/dom.js +1 -1
  93. package/dist/production/lib/dom/lib.js +1 -1
  94. package/dist/production/lib/dom/server.js +1 -1
  95. package/dist/production/lib/dom/ssr/components.js +1 -1
  96. package/dist/production/lib/dom/ssr/data.js +1 -1
  97. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  98. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  99. package/dist/production/lib/dom/ssr/fog-of-war.js +12 -3
  100. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  101. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  102. package/dist/production/lib/dom/ssr/links.js +1 -1
  103. package/dist/production/lib/dom/ssr/markup.js +1 -1
  104. package/dist/production/lib/dom/ssr/route-discovery.d.ts +2 -2
  105. package/dist/production/lib/dom/ssr/route-discovery.js +3 -3
  106. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  107. package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
  108. package/dist/production/lib/dom/ssr/routes.js +1 -1
  109. package/dist/production/lib/dom/ssr/server.js +1 -1
  110. package/dist/production/lib/dom/ssr/single-fetch.d.ts +1 -1
  111. package/dist/production/lib/dom/ssr/single-fetch.js +7 -7
  112. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  113. package/dist/production/lib/dom-export/hydrated-router.js +2 -2
  114. package/dist/production/lib/errors.js +1 -1
  115. package/dist/production/lib/hooks.d.ts +0 -3
  116. package/dist/production/lib/hooks.js +5 -6
  117. package/dist/production/lib/href.js +1 -1
  118. package/dist/production/lib/router/history.js +1 -1
  119. package/dist/production/lib/router/instrumentation.js +1 -1
  120. package/dist/production/lib/router/matcher-route-pattern.js +1 -1
  121. package/dist/production/lib/router/matcher-route-pattern.preload.js +1 -1
  122. package/dist/production/lib/router/matcher.js +6 -1
  123. package/dist/production/lib/router/navigation.js +1 -1
  124. package/dist/production/lib/router/router.d.ts +2 -0
  125. package/dist/production/lib/router/router.js +58 -28
  126. package/dist/production/lib/router/url.js +1 -1
  127. package/dist/production/lib/router/utils.d.ts +7 -0
  128. package/dist/production/lib/router/utils.js +1 -1
  129. package/dist/production/lib/rsc/browser.js +3 -3
  130. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  131. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  132. package/dist/production/lib/rsc/html-stream/server.js +1 -1
  133. package/dist/production/lib/rsc/route-modules.js +1 -1
  134. package/dist/production/lib/rsc/server.ssr.js +1 -1
  135. package/dist/production/lib/server-runtime/cookies.js +1 -1
  136. package/dist/production/lib/server-runtime/crypto.js +1 -1
  137. package/dist/production/lib/server-runtime/data.js +1 -1
  138. package/dist/production/lib/server-runtime/dev.js +1 -1
  139. package/dist/production/lib/server-runtime/entry.js +1 -1
  140. package/dist/production/lib/server-runtime/errors.js +1 -1
  141. package/dist/production/lib/server-runtime/headers.js +1 -1
  142. package/dist/production/lib/server-runtime/invariant.js +1 -1
  143. package/dist/production/lib/server-runtime/mode.js +1 -1
  144. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  145. package/dist/production/lib/server-runtime/routes.js +1 -1
  146. package/dist/production/lib/server-runtime/server.js +13 -5
  147. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  148. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  149. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  150. package/dist/production/lib/server-runtime/sessions.js +2 -2
  151. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  152. package/dist/production/lib/server-runtime/urls.js +1 -1
  153. package/dist/production/lib/server-runtime/warnings.js +1 -1
  154. package/dist/production/lib/types/internal.js +1 -1
  155. package/dist/production/route-pattern.js +1 -1
  156. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  157. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  158. package/dist/production/vendor/turbo-stream-v2/unflatten.js +23 -3
  159. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  160. package/docs/explanation/backend-for-frontend.md +0 -3
  161. package/docs/explanation/code-splitting.md +0 -3
  162. package/docs/explanation/concurrency.md +0 -3
  163. package/docs/explanation/hot-module-replacement.md +0 -3
  164. package/docs/explanation/lazy-route-discovery.md +0 -3
  165. package/docs/explanation/progressive-enhancement.md +0 -3
  166. package/docs/explanation/race-conditions.md +0 -3
  167. package/docs/explanation/react-transitions.md +0 -3
  168. package/docs/explanation/sessions-and-cookies.md +1 -1
  169. package/docs/explanation/state-management.md +0 -3
  170. package/docs/explanation/styling.md +0 -3
  171. package/docs/explanation/type-safety.md +0 -3
  172. package/docs/how-to/accessibility.md +0 -6
  173. package/docs/how-to/client-data.md +0 -3
  174. package/docs/how-to/data-strategy.md +0 -3
  175. package/docs/how-to/error-boundary.md +0 -3
  176. package/docs/how-to/error-reporting.md +0 -3
  177. package/docs/how-to/fetchers.md +0 -3
  178. package/docs/how-to/file-route-conventions.md +0 -3
  179. package/docs/how-to/file-uploads.md +0 -3
  180. package/docs/how-to/form-validation.md +0 -3
  181. package/docs/how-to/headers.md +0 -3
  182. package/docs/how-to/instrumentation.md +0 -3
  183. package/docs/how-to/middleware.md +6 -3
  184. package/docs/how-to/navigation-blocking.md +0 -3
  185. package/docs/how-to/optimize-revalidation.md +0 -3
  186. package/docs/how-to/pre-rendering.md +0 -3
  187. package/docs/how-to/presets.md +0 -3
  188. package/docs/how-to/react-server-components.md +0 -3
  189. package/docs/how-to/resource-routes.md +0 -3
  190. package/docs/how-to/route-discovery.md +4 -2
  191. package/docs/how-to/route-module-type-safety.md +0 -3
  192. package/docs/how-to/security.md +0 -3
  193. package/docs/how-to/server-bundles.md +0 -3
  194. package/docs/how-to/spa.md +0 -3
  195. package/docs/how-to/status.md +0 -3
  196. package/docs/how-to/suspense.md +22 -6
  197. package/docs/how-to/using-handle.md +0 -3
  198. package/docs/how-to/view-transitions.md +0 -3
  199. package/docs/start/framework/data-loading.md +9 -0
  200. package/docs/upgrading/future.md +0 -12
  201. package/docs/upgrading/v7.md +3 -33
  202. package/package.json +1 -1
  203. package/dist/development/lib/dom/global.d.ts +0 -35
  204. package/dist/production/lib/dom/global.d.ts +0 -35
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1047,12 +1047,17 @@ var V6RegExMatcher = class {
1047
1047
  #routes = [];
1048
1048
  #branches = [];
1049
1049
  #basename;
1050
+ #matchCost = 0;
1050
1051
  constructor(basename) {
1051
1052
  this.#basename = basename;
1052
1053
  }
1053
1054
  update(routes) {
1054
1055
  this.#routes = routes;
1055
1056
  this.#branches = flattenAndRankRoutes(routes);
1057
+ this.#matchCost = this.#branches.reduce((total, branch) => total + branch.routesMeta.length, 0);
1058
+ }
1059
+ get matchCost() {
1060
+ return this.#matchCost;
1056
1061
  }
1057
1062
  match(locationArg, allowPartial = false) {
1058
1063
  return matchRoutesImpl(this.#routes, locationArg, this.#basename, allowPartial, this.#branches);
@@ -1478,6 +1483,9 @@ function createStaticHandler(routes, opts) {
1478
1483
  }
1479
1484
  return {
1480
1485
  dataRoutes,
1486
+ get _matchCost() {
1487
+ return dataRouteMatcher instanceof V6RegExMatcher ? dataRouteMatcher.matchCost : void 0;
1488
+ },
1481
1489
  match,
1482
1490
  query,
1483
1491
  queryRoute
@@ -1589,6 +1597,9 @@ const loadLazyRouteProperty = ({ key, route, manifest, mapRouteProperties }) =>
1589
1597
  }
1590
1598
  })();
1591
1599
  cache[key] = propertyPromise;
1600
+ propertyPromise.catch(() => {
1601
+ if (cache[key] === propertyPromise) delete cache[key];
1602
+ });
1592
1603
  return propertyPromise;
1593
1604
  };
1594
1605
  const lazyRouteFunctionCache = /* @__PURE__ */ new WeakMap();
@@ -1630,7 +1641,9 @@ function loadLazyRoute(route, type, manifest, mapRouteProperties, lazyRoutePrope
1630
1641
  });
1631
1642
  })();
1632
1643
  lazyRouteFunctionCache.set(routeToUpdate, lazyRoutePromise);
1633
- lazyRoutePromise.catch(() => {});
1644
+ lazyRoutePromise.catch(() => {
1645
+ if (lazyRouteFunctionCache.get(routeToUpdate) === lazyRoutePromise) lazyRouteFunctionCache.delete(routeToUpdate);
1646
+ });
1634
1647
  return {
1635
1648
  lazyRoutePromise,
1636
1649
  lazyHandlerPromise: lazyRoutePromise
@@ -1918,10 +1931,13 @@ async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPr
1918
1931
  pathname,
1919
1932
  routeId: match.route.id
1920
1933
  });
1921
- } else return {
1922
- type: "data",
1923
- result: void 0
1924
- };
1934
+ } else {
1935
+ await lazyRoutePromise;
1936
+ return {
1937
+ type: "data",
1938
+ result: void 0
1939
+ };
1940
+ }
1925
1941
  }
1926
1942
  else if (!handler) {
1927
1943
  let url = new URL(request.url);
@@ -2251,6 +2267,12 @@ function getPathsWithAncestors(paths) {
2251
2267
  });
2252
2268
  return Array.from(result);
2253
2269
  }
2270
+ const MANIFEST_MATCH_COST_LIMIT = 5e4;
2271
+ const MANIFEST_MATCH_COST_SEGMENT_THRESHOLD = 10;
2272
+ function shouldUseInitialRouteDiscovery(pathname, matchCost = 0) {
2273
+ let segmentCount = pathname.split("/").length - 1;
2274
+ return Math.max(segmentCount - 1, 0) * pathname.length + 1 > 7680 || segmentCount > MANIFEST_MATCH_COST_SEGMENT_THRESHOLD && segmentCount * matchCost > MANIFEST_MATCH_COST_LIMIT;
2275
+ }
2254
2276
  //#endregion
2255
2277
  //#region lib/actions.ts
2256
2278
  function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
@@ -2346,12 +2368,15 @@ const replace = (...args) => {
2346
2368
  const cachedResolvePromise = React.cache(async (resolve) => {
2347
2369
  return Promise.allSettled([resolve]).then((r) => r[0]);
2348
2370
  });
2349
- const Await = (async ({ children, resolve, errorElement }) => {
2350
- let resolved = await cachedResolvePromise(resolve);
2371
+ const Await = (async (props) => {
2372
+ invariant$1("resolve" in props !== "unstable_promise" in props, "<Await> requires exactly one of `resolve` or `unstable_promise`");
2373
+ let { children, errorElement } = props;
2374
+ let usePromise = "unstable_promise" in props;
2375
+ let resolved = await cachedResolvePromise(usePromise ? props.unstable_promise : props.resolve);
2351
2376
  if (resolved.status === "rejected" && !errorElement) throw resolved.reason;
2352
2377
  if (resolved.status === "rejected") return React.createElement(UNSAFE_AwaitContextProvider, {
2353
2378
  children: React.createElement(React.Fragment, null, errorElement),
2354
- value: {
2379
+ value: usePromise ? resolved : {
2355
2380
  _tracked: true,
2356
2381
  _error: resolved.reason
2357
2382
  }
@@ -2359,7 +2384,7 @@ const Await = (async ({ children, resolve, errorElement }) => {
2359
2384
  const toRender = typeof children === "function" ? children(resolved.value) : children;
2360
2385
  return React.createElement(UNSAFE_AwaitContextProvider, {
2361
2386
  children: toRender,
2362
- value: {
2387
+ value: usePromise ? resolved : {
2363
2388
  _tracked: true,
2364
2389
  _data: resolved.value
2365
2390
  }
@@ -2676,7 +2701,7 @@ async function generateRenderResponse(request, staticHandler, basename, isDataRe
2676
2701
  let result = await processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences).finally(() => {
2677
2702
  ctx.runningAction = false;
2678
2703
  });
2679
- if (isResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2704
+ if (isResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, result === ctx.redirect ? void 0 : ctx.redirect?.headers);
2680
2705
  skipRevalidation = result?.skipRevalidation ?? false;
2681
2706
  actionResult = result?.actionResult;
2682
2707
  formState = result?.formState;
@@ -2710,7 +2735,7 @@ function generateRedirectResponse(response, actionResult, basename, isDataReques
2710
2735
  status: response.status,
2711
2736
  actionResult
2712
2737
  };
2713
- let headers = new Headers(sideEffectRedirectHeaders);
2738
+ let headers = new Headers(sideEffectRedirectHeaders === response.headers ? void 0 : sideEffectRedirectHeaders);
2714
2739
  for (const [key, value] of response.headers.entries()) headers.append(key, value);
2715
2740
  headers.delete("Location");
2716
2741
  headers.delete("X-Remix-Reload-Document");
@@ -2788,11 +2813,14 @@ async function getRenderPayload(baseRenderPayload, staticHandler, basename, rout
2788
2813
  parentId
2789
2814
  });
2790
2815
  }));
2816
+ let pathname = staticContext.location.pathname;
2817
+ let useInitialRouteDiscovery = routeDiscovery?.mode === "initial" && !isDataRequest || shouldUseInitialRouteDiscovery(pathname, staticHandler._matchCost);
2791
2818
  let patches;
2792
- if (routeDiscovery?.mode === "initial" && !isDataRequest) patches = getAllRoutePatches(routes, basename).then((patches) => patches.filter((patch) => !staticContext.matches.some((m) => m.route.id === patch.id)));
2793
- else patches = getAdditionalRoutePatches(getPathsWithAncestors([staticContext.location.pathname]), staticHandler, staticContext.matches.map((m) => m.route.id));
2819
+ if (useInitialRouteDiscovery) patches = getAllRoutePatches(routes, basename).then((patches) => patches.filter((patch) => !staticContext.matches.some((m) => m.route.id === patch.id)));
2820
+ else patches = getAdditionalRoutePatches(getPathsWithAncestors([pathname]).slice(0, -1), staticHandler, staticContext.matches.map((m) => m.route.id));
2794
2821
  return {
2795
2822
  ...baseRenderPayload,
2823
+ routeDiscovery: useInitialRouteDiscovery ? { mode: "initial" } : baseRenderPayload.routeDiscovery,
2796
2824
  matches: await matchesPromise,
2797
2825
  patches
2798
2826
  };
@@ -3251,7 +3279,7 @@ function createSessionStorage({ cookie: cookieArg, createData, readData, updateD
3251
3279
  return cookie.serialize(id, options);
3252
3280
  },
3253
3281
  async destroySession(session, options) {
3254
- await deleteData(session.id);
3282
+ if (session.id) await deleteData(session.id);
3255
3283
  return cookie.serialize("", {
3256
3284
  ...options,
3257
3285
  maxAge: void 0,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -0,0 +1,58 @@
1
+ /**
2
+ * react-router v8.5.1
3
+ *
4
+ * Copyright (c) Remix Software Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ //#region lib/await.ts
12
+ function getPromiseResult(promise) {
13
+ if (promise.status === "fulfilled") return {
14
+ status: "fulfilled",
15
+ value: promise.value
16
+ };
17
+ if (promise.status === "rejected") return {
18
+ status: "rejected",
19
+ reason: promise.reason
20
+ };
21
+ }
22
+ let awaitPromises = /* @__PURE__ */ new WeakMap();
23
+ function getAwaitPromise(source, onError) {
24
+ let cached = awaitPromises.get(source);
25
+ if (!cached) {
26
+ cached = {
27
+ promise: Promise.resolve(source).then((value) => settle({
28
+ status: "fulfilled",
29
+ value
30
+ }), (reason) => {
31
+ let result = settle({
32
+ status: "rejected",
33
+ reason
34
+ });
35
+ try {
36
+ cached.onError(reason);
37
+ } catch (error) {
38
+ console.error("<Await> caught the following error in onError", error);
39
+ }
40
+ return result;
41
+ }),
42
+ onError
43
+ };
44
+ awaitPromises.set(source, cached);
45
+ } else cached.onError = onError;
46
+ function settle(result) {
47
+ Object.assign(cached.promise, {
48
+ status: "fulfilled",
49
+ value: result
50
+ });
51
+ return result;
52
+ }
53
+ let result = getPromiseResult(source);
54
+ if (result) settle(result);
55
+ return cached.promise;
56
+ }
57
+ //#endregion
58
+ export { getAwaitPromise, getPromiseResult };
@@ -768,6 +768,8 @@ interface AwaitResolveRenderFunction<Resolve = any> {
768
768
  * @category Types
769
769
  */
770
770
  interface AwaitProps<Resolve> {
771
+ /** Use either `resolve` or `unstable_promise`, never both. */
772
+ unstable_promise?: never;
771
773
  /**
772
774
  * When using a function, the resolved value is provided as the parameter.
773
775
  *
@@ -869,11 +871,46 @@ interface AwaitProps<Resolve> {
869
871
  */
870
872
  resolve: Resolve;
871
873
  }
874
+ interface AwaitPromiseProps<Resolve> extends Omit<AwaitProps<Resolve>, "resolve" | "unstable_promise"> {
875
+ resolve?: never;
876
+ /**
877
+ * A promise (or value) to read using React's `use()` API in client components.
878
+ * Unlike `resolve` in client components, this accepts promise-like values
879
+ * without modifying the source promise.
880
+ *
881
+ * `errorElement` handles promise rejections. Errors thrown while rendering
882
+ * children bubble to the nearest React error boundary.
883
+ *
884
+ * ```tsx
885
+ * <Await unstable_promise={reviewsPromise} errorElement={<ReviewsError />}>
886
+ * {(reviews) => <Reviews items={reviews} />}
887
+ * </Await>
888
+ * ```
889
+ *
890
+ * Pass exactly one of `unstable_promise` or `resolve`.
891
+ */
892
+ unstable_promise: Resolve;
893
+ }
872
894
  /**
873
895
  * Used to render promise values with automatic error handling.
874
896
  *
875
897
  * **Note:** `<Await>` expects to be rendered inside a [`<React.Suspense>`](https://react.dev/reference/react/Suspense)
876
898
  *
899
+ * Pass `unstable_promise` instead of `resolve` to opt into React's
900
+ * [`use()`](https://react.dev/reference/react/use) implementation. With
901
+ * `unstable_promise`, `errorElement` handles promise rejections, while errors
902
+ * thrown by children bubble to the nearest React error boundary.
903
+ *
904
+ * In React Server Components, `resolve` already has this error-handling behavior:
905
+ * `errorElement` handles only input rejections, while child render errors
906
+ * propagate to the surrounding error boundary. Both props accept promise-like
907
+ * values without modifying the source promise. Both props treat a falsy
908
+ * `errorElement` as absent and propagate the rejection. Pass an empty fragment
909
+ * to handle a rejection without rendering any content.
910
+ *
911
+ * <docs-warning>The `unstable_promise` prop is experimental and may change in
912
+ * minor or patch releases.</docs-warning>
913
+ *
877
914
  * @example
878
915
  * import { Await, useLoaderData } from "react-router";
879
916
  *
@@ -914,13 +951,12 @@ interface AwaitProps<Resolve> {
914
951
  * @param {AwaitProps.children} props.children n/a
915
952
  * @param {AwaitProps.errorElement} props.errorElement n/a
916
953
  * @param {AwaitProps.resolve} props.resolve n/a
954
+ * @param props.unstable_promise A promise (or value) to read using React's `use()`
955
+ * API in client components. Accepts promise-like values without modifying the
956
+ * source promise. Pass exactly one of `unstable_promise` or `resolve`.
917
957
  * @returns React element for the rendered awaited value
918
958
  */
919
- declare function Await<Resolve>({
920
- children,
921
- errorElement,
922
- resolve
923
- }: AwaitProps<Resolve>): React$1.JSX.Element;
959
+ declare function Await<Resolve>(props: AwaitProps<Resolve> | AwaitPromiseProps<Resolve>): React$1.JSX.Element;
924
960
  /**
925
961
  * Creates a route config from a React "children" object, which is usually
926
962
  * either a `<Route>` element or an array of them. Used internally by
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -13,6 +13,7 @@ import { defaultMapRouteProperties, getResolveToMatches, getRoutePattern, resolv
13
13
  import { getNavigatorCurrentUrl, validateNavigationTarget } from "./router/navigation.js";
14
14
  import { clientErrors, createRouter } from "./router/router.js";
15
15
  import { AwaitContext, DataRouterContext, DataRouterDataContext, DataRouterNavigationContext, DataRouterStateContext, FetchersContext, LocationContext, NavigationContext, RouteContext, ViewTransitionContext, useIsRSCRouterContext } from "./context.js";
16
+ import { getAwaitPromise, getPromiseResult } from "./await.js";
16
17
  import { _renderMatches, useActionData, useAsyncValue, useInRouterContext, useLoaderData, useLocation, useMatches, useNavigate, useOutlet, useParams, useRouteError, useRoutes, useRoutesImpl } from "./hooks.js";
17
18
  import { warnOnce } from "./server-runtime/warnings.js";
18
19
  import { FrameworkContext } from "./dom/ssr/components.js";
@@ -85,6 +86,11 @@ var Deferred = class {
85
86
  });
86
87
  }
87
88
  };
89
+ function handleSkippedViewTransition(transition, document) {
90
+ transition.ready.catch((reason) => {
91
+ if (!(document.visibilityState === "hidden" || typeof reason === "object" && reason !== null && "name" in reason && reason.name === "AbortError")) throw reason;
92
+ });
93
+ }
88
94
  /**
89
95
  * Render the UI for the given {@link DataRouter}. This component should
90
96
  * typically be at the top of an app's element tree. The router prop should
@@ -172,6 +178,7 @@ function RouterProvider({ router, flushSync: reactDomFlushSyncImpl, onError, use
172
178
  let t = router.window.document.startViewTransition(() => {
173
179
  reactDomFlushSyncImpl(() => setStateImpl(newState));
174
180
  });
181
+ handleSkippedViewTransition(t, router.window.document);
175
182
  t.finished.finally(() => {
176
183
  reactDomFlushSyncImpl(() => {
177
184
  setRenderDfd(void 0);
@@ -234,6 +241,7 @@ function RouterProvider({ router, flushSync: reactDomFlushSyncImpl, onError, use
234
241
  });
235
242
  await renderPromise;
236
243
  });
244
+ handleSkippedViewTransition(transition, router.window.document);
237
245
  transition.finished.finally(() => {
238
246
  setRenderDfd(void 0);
239
247
  setTransition(void 0);
@@ -643,6 +651,21 @@ function Routes({ children, location }) {
643
651
  *
644
652
  * **Note:** `<Await>` expects to be rendered inside a [`<React.Suspense>`](https://react.dev/reference/react/Suspense)
645
653
  *
654
+ * Pass `unstable_promise` instead of `resolve` to opt into React's
655
+ * [`use()`](https://react.dev/reference/react/use) implementation. With
656
+ * `unstable_promise`, `errorElement` handles promise rejections, while errors
657
+ * thrown by children bubble to the nearest React error boundary.
658
+ *
659
+ * In React Server Components, `resolve` already has this error-handling behavior:
660
+ * `errorElement` handles only input rejections, while child render errors
661
+ * propagate to the surrounding error boundary. Both props accept promise-like
662
+ * values without modifying the source promise. Both props treat a falsy
663
+ * `errorElement` as absent and propagate the rejection. Pass an empty fragment
664
+ * to handle a rejection without rendering any content.
665
+ *
666
+ * <docs-warning>The `unstable_promise` prop is experimental and may change in
667
+ * minor or patch releases.</docs-warning>
668
+ *
646
669
  * @example
647
670
  * import { Await, useLoaderData } from "react-router";
648
671
  *
@@ -683,9 +706,14 @@ function Routes({ children, location }) {
683
706
  * @param {AwaitProps.children} props.children n/a
684
707
  * @param {AwaitProps.errorElement} props.errorElement n/a
685
708
  * @param {AwaitProps.resolve} props.resolve n/a
709
+ * @param props.unstable_promise A promise (or value) to read using React's `use()`
710
+ * API in client components. Accepts promise-like values without modifying the
711
+ * source promise. Pass exactly one of `unstable_promise` or `resolve`.
686
712
  * @returns React element for the rendered awaited value
687
713
  */
688
- function Await({ children, errorElement, resolve }) {
714
+ function Await(props) {
715
+ invariant("resolve" in props !== "unstable_promise" in props, "<Await> requires exactly one of `resolve` or `unstable_promise`");
716
+ let { children, errorElement } = props;
689
717
  let dataRouterContext = React$1.useContext(DataRouterContext);
690
718
  let dataRouterStateContext = React$1.useContext(DataRouterStateContext);
691
719
  let onError = React$1.useCallback((error, errorInfo) => {
@@ -696,12 +724,25 @@ function Await({ children, errorElement, resolve }) {
696
724
  errorInfo
697
725
  });
698
726
  }, [dataRouterContext, dataRouterStateContext]);
727
+ if ("unstable_promise" in props) return /* @__PURE__ */ React$1.createElement(AwaitPromise, {
728
+ value: props.unstable_promise,
729
+ errorElement,
730
+ onError
731
+ }, children);
699
732
  return /* @__PURE__ */ React$1.createElement(AwaitErrorBoundary, {
700
- resolve,
733
+ resolve: props.resolve,
701
734
  errorElement,
702
735
  onError
703
736
  }, /* @__PURE__ */ React$1.createElement(ResolveAwait, null, children));
704
737
  }
738
+ function AwaitPromise({ value, children, errorElement, onError }) {
739
+ let result = value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function" ? React$1.use(getAwaitPromise(value, onError)) : {
740
+ status: "fulfilled",
741
+ value
742
+ };
743
+ if (result.status === "rejected" && !errorElement) throw result.reason;
744
+ return /* @__PURE__ */ React$1.createElement(AwaitContext.Provider, { value: result }, result.status === "rejected" ? errorElement : /* @__PURE__ */ React$1.createElement(ResolveAwait, null, children));
745
+ }
705
746
  var AwaitErrorBoundary = class extends React$1.Component {
706
747
  constructor(props) {
707
748
  super(props);
@@ -735,7 +776,24 @@ var AwaitErrorBoundary = class extends React$1.Component {
735
776
  } else {
736
777
  status = 0;
737
778
  Object.defineProperty(resolve, "_tracked", { get: () => true });
738
- promise = Promise.resolve(resolve).then((data) => Object.defineProperty(resolve, "_data", { get: () => data }), (error) => {
779
+ let result = getPromiseResult(resolve);
780
+ if (result) {
781
+ promise = resolve;
782
+ if (result.status === "fulfilled") {
783
+ status = 1;
784
+ Object.defineProperty(resolve, "_data", { get: () => result.value });
785
+ } else {
786
+ status = 2;
787
+ Object.defineProperty(resolve, "_error", { get: () => result.reason });
788
+ Promise.resolve(resolve).catch((reason) => {
789
+ try {
790
+ this.props.onError?.(reason);
791
+ } catch (error) {
792
+ console.error("<Await> caught the following error in onError", error);
793
+ }
794
+ });
795
+ }
796
+ } else promise = Promise.resolve(resolve).then((data) => Object.defineProperty(resolve, "_data", { get: () => data }), (error) => {
739
797
  this.props.onError?.(error);
740
798
  Object.defineProperty(resolve, "_error", { get: () => error });
741
799
  });
@@ -32,8 +32,8 @@ type FetchersContextObject = {
32
32
  fetcherData: Map<string, any>;
33
33
  };
34
34
  declare const FetchersContext: React$1.Context<FetchersContextObject | null>;
35
- declare const AwaitContext: React$1.Context<TrackedPromise | null>;
36
- declare const AwaitContextProvider: (props: React$1.ComponentProps<typeof AwaitContext.Provider>) => React$1.FunctionComponentElement<React$1.ProviderProps<TrackedPromise | null>>;
35
+ declare const AwaitContext: React$1.Context<TrackedPromise | PromiseSettledResult<unknown> | null>;
36
+ declare const AwaitContextProvider: (props: React$1.ComponentProps<typeof AwaitContext.Provider>) => React$1.FunctionComponentElement<React$1.ProviderProps<TrackedPromise | PromiseSettledResult<unknown> | null>>;
37
37
  interface NavigateOptions {
38
38
  /** Replace the current entry in the history stack instead of pushing a new one */
39
39
  replace?: boolean;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -29,6 +29,12 @@ function getPathsWithAncestors(paths) {
29
29
  function isFogOfWarEnabled(routeDiscovery, ssr) {
30
30
  return routeDiscovery.mode === "lazy" && ssr;
31
31
  }
32
+ const MANIFEST_MATCH_COST_LIMIT = 5e4;
33
+ const MANIFEST_MATCH_COST_SEGMENT_THRESHOLD = 10;
34
+ function shouldUseInitialRouteDiscovery(pathname, matchCost = 0) {
35
+ let segmentCount = pathname.split("/").length - 1;
36
+ return Math.max(segmentCount - 1, 0) * pathname.length + 1 > 7680 || segmentCount > MANIFEST_MATCH_COST_SEGMENT_THRESHOLD && segmentCount * matchCost > MANIFEST_MATCH_COST_LIMIT;
37
+ }
32
38
  function getPartialManifest({ sri, ...manifest }, router) {
33
39
  let routeIds = new Set(router.state.matches.map((m) => m.route.id));
34
40
  let segments = router.state.location.pathname.split("/").filter(Boolean);
@@ -108,6 +114,9 @@ function useFogOFWarDiscovery(router, manifest, routeModules, ssr, routeDiscover
108
114
  isApiOnly
109
115
  ]);
110
116
  }
117
+ function getManifestPathsParam(paths) {
118
+ return paths.slice().sort().map((path) => path.replace(/,/g, "%2C")).join(",");
119
+ }
111
120
  function getManifestPath(_manifestPath, basename) {
112
121
  let manifestPath = _manifestPath || "/__manifest";
113
122
  return basename == null ? manifestPath : joinPaths([basename, manifestPath]);
@@ -160,7 +169,7 @@ async function handleClientVersionMismatch(needsReload, version, errorReloadPath
160
169
  async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, routeModules, ssr, isSpaMode, basename, manifestPath, patchRoutes, signal, fetchImplementation = (request) => fetch(request), serverOrigin, isApiOnly = false) {
161
170
  paths = getPathsWithAncestors(paths);
162
171
  const searchParams = new URLSearchParams();
163
- searchParams.set("paths", paths.sort().join(","));
172
+ searchParams.set("paths", getManifestPathsParam(paths));
164
173
  searchParams.set("version", manifest.version);
165
174
  let url = new URL(getManifestPath(manifestPath, basename), serverOrigin ?? window.location.origin);
166
175
  url.search = searchParams.toString();
@@ -207,4 +216,4 @@ function debounce(callback, wait) {
207
216
  };
208
217
  }
209
218
  //#endregion
210
- export { URL_LIMIT, getManifestPath, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled, useFogOFWarDiscovery };
219
+ export { URL_LIMIT, getManifestPath, getManifestPathsParam, getPartialManifest, getPatchRoutesOnNavigationFunction, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled, shouldUseInitialRouteDiscovery, useFogOFWarDiscovery };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -4,7 +4,7 @@ import { Router } from "../../router/router.js";
4
4
  import { ClientOnErrorFunction } from "../../components.js";
5
5
  import { RouteModules } from "./routeModules.js";
6
6
  import { RouterFetch } from "./single-fetch.js";
7
- import { WindowReactRouterContext } from "../global.js";
7
+ import { ServerHandoff } from "../../server-runtime/serverHandoff.js";
8
8
  import { AssetsManifest } from "./entry.js";
9
9
 
10
10
  //#region lib/dom/ssr/route-discovery.d.ts
@@ -37,7 +37,7 @@ type RouteDiscoverySsrInfo = {
37
37
  manifest: AssetsManifest;
38
38
  routeModules: RouteModules;
39
39
  router: Router | undefined;
40
- context: Pick<WindowReactRouterContext, "ssr" | "routeDiscovery" | "isSpaMode" | "basename" | "unstable_apiServerOrigin" | "unstable_apiOnly">;
40
+ context: Pick<ServerHandoff, "ssr" | "routeDiscovery" | "isSpaMode" | "basename" | "unstable_apiServerOrigin" | "unstable_apiOnly">;
41
41
  };
42
42
  declare class RouteDiscoveryRuntime {
43
43
  private ssrInfo;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -11,7 +11,7 @@
11
11
  import { createPath, invariant } from "../../router/history.js";
12
12
  import { DiscoveryCancelledError, getRoutePattern, prependBasename } from "../../router/utils.js";
13
13
  import { createClientRoutes } from "./routes.js";
14
- import { getManifestPath, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled } from "./fog-of-war.js";
14
+ import { getManifestPath, getManifestPathsParam, getPathsWithAncestors, handleClientVersionMismatch, isFogOfWarEnabled } from "./fog-of-war.js";
15
15
  import { useFrameworkContext } from "./components.js";
16
16
  import * as React$1 from "react";
17
17
  //#region lib/dom/ssr/route-discovery.ts
@@ -158,7 +158,7 @@ var RouteDiscoveryRuntime = class {
158
158
  requestUrl(paths) {
159
159
  let { manifest, context } = this.ssrInfo;
160
160
  let params = new URLSearchParams();
161
- params.set("paths", paths.slice().sort().join(","));
161
+ params.set("paths", getManifestPathsParam(paths));
162
162
  params.set("version", manifest.version);
163
163
  let url = new URL(getManifestPath(context.routeDiscovery.manifestPath, context.basename), context.unstable_apiServerOrigin ?? window.location.origin);
164
164
  url.search = params.toString();
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.5.0
2
+ * react-router v8.5.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *