react-router 8.4.0 → 8.5.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 (198) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/dist/development/dom-export.d.ts +2 -1
  3. package/dist/development/dom-export.js +1 -1
  4. package/dist/development/index-react-server-client.js +2 -2
  5. package/dist/development/index-react-server.d.ts +583 -165
  6. package/dist/development/index-react-server.js +27 -19
  7. package/dist/development/index.d.ts +9 -8
  8. package/dist/development/index.js +5 -4
  9. package/dist/development/lib/actions.js +1 -1
  10. package/dist/development/lib/components.js +22 -3
  11. package/dist/development/lib/context.d.ts +6 -1
  12. package/dist/development/lib/context.js +1 -1
  13. package/dist/development/lib/dom/dom.d.ts +3 -0
  14. package/dist/development/lib/dom/dom.js +1 -1
  15. package/dist/development/lib/dom/global.d.ts +35 -0
  16. package/dist/development/lib/dom/lib.d.ts +34 -9
  17. package/dist/development/lib/dom/lib.js +17 -6
  18. package/dist/development/lib/dom/server.js +2 -2
  19. package/dist/development/lib/dom/ssr/components.js +12 -9
  20. package/dist/development/lib/dom/ssr/data.js +1 -1
  21. package/dist/development/lib/dom/ssr/entry.d.ts +9 -2
  22. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  23. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  24. package/dist/development/lib/dom/ssr/fog-of-war.d.ts +3 -2
  25. package/dist/development/lib/dom/ssr/fog-of-war.js +14 -11
  26. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  27. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  28. package/dist/development/lib/dom/ssr/links.js +1 -1
  29. package/dist/development/lib/dom/ssr/markup.js +1 -1
  30. package/dist/development/lib/dom/ssr/route-discovery.d.ts +120 -0
  31. package/dist/development/lib/dom/ssr/route-discovery.js +415 -0
  32. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  33. package/dist/development/lib/dom/ssr/routes-test-stub.js +2 -2
  34. package/dist/development/lib/dom/ssr/routes.d.ts +2 -2
  35. package/dist/development/lib/dom/ssr/routes.js +8 -8
  36. package/dist/development/lib/dom/ssr/server.js +3 -1
  37. package/dist/development/lib/dom/ssr/single-fetch.d.ts +28 -2
  38. package/dist/development/lib/dom/ssr/single-fetch.js +73 -55
  39. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  40. package/dist/development/lib/dom-export/hydrated-router.d.ts +28 -0
  41. package/dist/development/lib/dom-export/hydrated-router.js +32 -12
  42. package/dist/development/lib/errors.js +1 -1
  43. package/dist/development/lib/hooks.d.ts +3 -3
  44. package/dist/development/lib/hooks.js +4 -4
  45. package/dist/development/lib/href.js +1 -1
  46. package/dist/development/lib/router/history.js +1 -1
  47. package/dist/development/lib/router/instrumentation.js +1 -1
  48. package/dist/development/lib/router/matcher-route-pattern.js +1 -1
  49. package/dist/development/lib/router/matcher-route-pattern.preload.js +1 -1
  50. package/dist/development/lib/router/matcher.js +1 -1
  51. package/dist/development/lib/router/navigation.js +1 -1
  52. package/dist/development/lib/router/router.d.ts +6 -0
  53. package/dist/development/lib/router/router.js +157 -65
  54. package/dist/development/lib/router/url.js +1 -1
  55. package/dist/development/lib/router/utils.d.ts +24 -4
  56. package/dist/development/lib/router/utils.js +4 -3
  57. package/dist/development/lib/rsc/browser.js +2 -2
  58. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  59. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  60. package/dist/development/lib/rsc/html-stream/server.js +24 -12
  61. package/dist/development/lib/rsc/route-modules.js +1 -1
  62. package/dist/development/lib/rsc/server.rsc.d.ts +3 -2
  63. package/dist/development/lib/rsc/server.ssr.js +1 -1
  64. package/dist/development/lib/server-runtime/build.d.ts +14 -0
  65. package/dist/development/lib/server-runtime/cookies.js +1 -1
  66. package/dist/development/lib/server-runtime/crypto.js +1 -1
  67. package/dist/development/lib/server-runtime/data.js +1 -1
  68. package/dist/development/lib/server-runtime/dev.js +1 -1
  69. package/dist/development/lib/server-runtime/entry.js +1 -1
  70. package/dist/development/lib/server-runtime/errors.js +1 -1
  71. package/dist/development/lib/server-runtime/headers.js +1 -1
  72. package/dist/development/lib/server-runtime/invariant.js +1 -1
  73. package/dist/development/lib/server-runtime/mode.js +1 -1
  74. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  75. package/dist/development/lib/server-runtime/routes.d.ts +1 -1
  76. package/dist/development/lib/server-runtime/routes.js +1 -1
  77. package/dist/development/lib/server-runtime/server.js +12 -4
  78. package/dist/development/lib/server-runtime/serverHandoff.d.ts +17 -0
  79. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  80. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  81. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  82. package/dist/development/lib/server-runtime/sessions.js +1 -1
  83. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  84. package/dist/development/lib/server-runtime/urls.js +1 -1
  85. package/dist/development/lib/server-runtime/warnings.js +1 -1
  86. package/dist/development/lib/types/internal.js +1 -1
  87. package/dist/development/lib/types/route-data.d.ts +2 -2
  88. package/dist/development/lib/types/route-module-annotations.d.ts +1 -1
  89. package/dist/development/route-pattern.js +1 -1
  90. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  91. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  92. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  93. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  94. package/dist/production/dom-export.d.ts +2 -1
  95. package/dist/production/dom-export.js +1 -1
  96. package/dist/production/index-react-server-client.js +2 -2
  97. package/dist/production/index-react-server.d.ts +583 -165
  98. package/dist/production/index-react-server.js +27 -19
  99. package/dist/production/index.d.ts +9 -8
  100. package/dist/production/index.js +5 -4
  101. package/dist/production/lib/actions.js +1 -1
  102. package/dist/production/lib/components.js +22 -3
  103. package/dist/production/lib/context.d.ts +6 -1
  104. package/dist/production/lib/context.js +1 -1
  105. package/dist/production/lib/dom/dom.d.ts +3 -0
  106. package/dist/production/lib/dom/dom.js +1 -1
  107. package/dist/production/lib/dom/global.d.ts +35 -0
  108. package/dist/production/lib/dom/lib.d.ts +34 -9
  109. package/dist/production/lib/dom/lib.js +17 -6
  110. package/dist/production/lib/dom/server.js +2 -2
  111. package/dist/production/lib/dom/ssr/components.js +12 -9
  112. package/dist/production/lib/dom/ssr/data.js +1 -1
  113. package/dist/production/lib/dom/ssr/entry.d.ts +9 -2
  114. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  115. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  116. package/dist/production/lib/dom/ssr/fog-of-war.d.ts +3 -2
  117. package/dist/production/lib/dom/ssr/fog-of-war.js +14 -11
  118. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  119. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  120. package/dist/production/lib/dom/ssr/links.js +1 -1
  121. package/dist/production/lib/dom/ssr/markup.js +1 -1
  122. package/dist/production/lib/dom/ssr/route-discovery.d.ts +120 -0
  123. package/dist/production/lib/dom/ssr/route-discovery.js +415 -0
  124. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  125. package/dist/production/lib/dom/ssr/routes-test-stub.js +2 -2
  126. package/dist/production/lib/dom/ssr/routes.d.ts +2 -2
  127. package/dist/production/lib/dom/ssr/routes.js +8 -8
  128. package/dist/production/lib/dom/ssr/server.js +3 -1
  129. package/dist/production/lib/dom/ssr/single-fetch.d.ts +28 -2
  130. package/dist/production/lib/dom/ssr/single-fetch.js +73 -55
  131. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  132. package/dist/production/lib/dom-export/hydrated-router.d.ts +28 -0
  133. package/dist/production/lib/dom-export/hydrated-router.js +32 -12
  134. package/dist/production/lib/errors.js +1 -1
  135. package/dist/production/lib/hooks.d.ts +3 -3
  136. package/dist/production/lib/hooks.js +3 -3
  137. package/dist/production/lib/href.js +1 -1
  138. package/dist/production/lib/router/history.js +1 -1
  139. package/dist/production/lib/router/instrumentation.js +1 -1
  140. package/dist/production/lib/router/matcher-route-pattern.js +1 -1
  141. package/dist/production/lib/router/matcher-route-pattern.preload.js +1 -1
  142. package/dist/production/lib/router/matcher.js +1 -1
  143. package/dist/production/lib/router/navigation.js +1 -1
  144. package/dist/production/lib/router/router.d.ts +6 -0
  145. package/dist/production/lib/router/router.js +157 -65
  146. package/dist/production/lib/router/url.js +1 -1
  147. package/dist/production/lib/router/utils.d.ts +24 -4
  148. package/dist/production/lib/router/utils.js +4 -3
  149. package/dist/production/lib/rsc/browser.js +2 -2
  150. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  151. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  152. package/dist/production/lib/rsc/html-stream/server.js +24 -12
  153. package/dist/production/lib/rsc/route-modules.js +1 -1
  154. package/dist/production/lib/rsc/server.rsc.d.ts +3 -2
  155. package/dist/production/lib/rsc/server.ssr.js +1 -1
  156. package/dist/production/lib/server-runtime/build.d.ts +14 -0
  157. package/dist/production/lib/server-runtime/cookies.js +1 -1
  158. package/dist/production/lib/server-runtime/crypto.js +1 -1
  159. package/dist/production/lib/server-runtime/data.js +1 -1
  160. package/dist/production/lib/server-runtime/dev.js +1 -1
  161. package/dist/production/lib/server-runtime/entry.js +1 -1
  162. package/dist/production/lib/server-runtime/errors.js +1 -1
  163. package/dist/production/lib/server-runtime/headers.js +1 -1
  164. package/dist/production/lib/server-runtime/invariant.js +1 -1
  165. package/dist/production/lib/server-runtime/mode.js +1 -1
  166. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  167. package/dist/production/lib/server-runtime/routes.d.ts +1 -1
  168. package/dist/production/lib/server-runtime/routes.js +1 -1
  169. package/dist/production/lib/server-runtime/server.js +12 -4
  170. package/dist/production/lib/server-runtime/serverHandoff.d.ts +17 -0
  171. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  172. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  173. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  174. package/dist/production/lib/server-runtime/sessions.js +1 -1
  175. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  176. package/dist/production/lib/server-runtime/urls.js +1 -1
  177. package/dist/production/lib/server-runtime/warnings.js +1 -1
  178. package/dist/production/lib/types/internal.js +1 -1
  179. package/dist/production/lib/types/route-data.d.ts +2 -2
  180. package/dist/production/lib/types/route-module-annotations.d.ts +1 -1
  181. package/dist/production/route-pattern.js +1 -1
  182. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  183. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  184. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  185. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  186. package/docs/explanation/lazy-route-discovery.md +4 -0
  187. package/docs/explanation/sessions-and-cookies.md +108 -4
  188. package/docs/how-to/custom-fetch.md +218 -0
  189. package/docs/how-to/data-strategy.md +23 -1
  190. package/docs/how-to/middleware.md +1 -0
  191. package/docs/how-to/optimize-revalidation.md +2 -2
  192. package/docs/how-to/pre-rendering.md +23 -1
  193. package/docs/how-to/route-discovery.md +145 -0
  194. package/docs/how-to/spa.md +2 -0
  195. package/docs/how-to/view-transitions.md +80 -13
  196. package/docs/start/framework/navigating.md +5 -9
  197. package/docs/start/framework/rendering.md +37 -0
  198. package/package.json +9 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.4.0
2
+ * react-router v8.5.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { PROTOCOL_RELATIVE_URL_REGEX, normalizeProtocolRelativeUrl } from "./url.js";
12
12
  import { createBrowserURLImpl, createLocation, createPath, invariant, parsePath, warning } from "./history.js";
13
- import { ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
13
+ import { DiscoveryCancelledError, ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
14
14
  import { consumeInstrumentationClientResultMetaReceiver, getRouteInstrumentationUpdates, instrumentClientSideRouter } from "./instrumentation.js";
15
15
  import { V6RegExMatcher } from "./matcher.js";
16
16
  import { getRoutePatternMatcher } from "./matcher-route-pattern.preload.js";
@@ -114,6 +114,7 @@ var DataRoutes = class {
114
114
  }
115
115
  }
116
116
  };
117
+ const clientErrors = /* @__PURE__ */ new WeakMap();
117
118
  /**
118
119
  * Create a router and listen to history POP navigations
119
120
  */
@@ -142,7 +143,6 @@ function createRouter(init) {
142
143
  let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
143
144
  let unlistenHistory = null;
144
145
  let subscribers = /* @__PURE__ */ new Set();
145
- let bufferedInitialStateUpdate = null;
146
146
  let savedScrollPositions = null;
147
147
  let getScrollRestorationKey = null;
148
148
  let getScrollPosition = null;
@@ -213,6 +213,8 @@ function createRouter(init) {
213
213
  blockers: /* @__PURE__ */ new Map()
214
214
  };
215
215
  let pendingAction = "POP";
216
+ let pendingPopstateDelta = 0;
217
+ let pendingDiscoveryCancellation;
216
218
  let pendingPopstateNavigationDfd = null;
217
219
  let pendingPreventScrollReset = false;
218
220
  let pendingNavigationController;
@@ -273,6 +275,7 @@ function createRouter(init) {
273
275
  pendingPopstateNavigationDfd = null;
274
276
  return;
275
277
  }
278
+ if (future.unstable_customRouteDiscovery) pendingPopstateDelta += delta || 0;
276
279
  return startNavigation(historyAction, location);
277
280
  });
278
281
  if (isBrowser) {
@@ -294,19 +297,16 @@ function createRouter(init) {
294
297
  }
295
298
  function subscribe(fn) {
296
299
  subscribers.add(fn);
297
- if (bufferedInitialStateUpdate) {
298
- let { newErrors } = bufferedInitialStateUpdate;
299
- bufferedInitialStateUpdate = null;
300
- fn(state, {
301
- deletedFetchers: [],
302
- newErrors,
303
- viewTransitionOpts: void 0,
304
- flushSync: false
305
- });
306
- }
307
300
  return () => subscribers.delete(fn);
308
301
  }
309
302
  function updateState(newState, opts = {}) {
303
+ let newErrors = newState.errors ?? null;
304
+ let cachedErrors = newErrors ? clientErrors.get(newErrors) : void 0;
305
+ if (cachedErrors !== void 0) newErrors = cachedErrors;
306
+ if (newState.errors !== void 0 || newState.initialized) {
307
+ if (state.errors) clientErrors.delete(state.errors);
308
+ if (newState.errors) clientErrors.set(newState.errors, newErrors);
309
+ }
310
310
  if (newState.matches) newState.matches = newState.matches.map((m) => {
311
311
  let route = manifest[m.route.id];
312
312
  let matchRoute = m.route;
@@ -329,10 +329,9 @@ function createRouter(init) {
329
329
  fetchersQueuedForDeletion.forEach((key) => {
330
330
  if (!state.fetchers.has(key) && !fetchControllers.has(key)) unmountedFetchers.push(key);
331
331
  });
332
- if (subscribers.size === 0) bufferedInitialStateUpdate = { newErrors: newState.errors ?? null };
333
332
  [...subscribers].forEach((subscriber) => subscriber(state, {
334
333
  deletedFetchers: unmountedFetchers,
335
- newErrors: newState.errors ?? null,
334
+ newErrors,
336
335
  viewTransitionOpts: opts.viewTransitionOpts,
337
336
  flushSync: opts.flushSync === true
338
337
  }));
@@ -397,17 +396,22 @@ function createRouter(init) {
397
396
  viewTransitionOpts,
398
397
  flushSync: flushSync === true
399
398
  });
399
+ resetPendingNavigation();
400
+ pendingPopstateNavigationDfd?.resolve();
401
+ pendingPopstateNavigationDfd = null;
402
+ pendingRevalidationDfd?.resolve();
403
+ pendingRevalidationDfd = null;
404
+ }
405
+ function resetPendingNavigation() {
406
+ pendingPopstateDelta = 0;
400
407
  pendingAction = "POP";
401
408
  pendingPreventScrollReset = false;
402
409
  pendingViewTransitionEnabled = false;
403
410
  isUninterruptedRevalidation = false;
404
411
  isRevalidationRequired = false;
405
- pendingPopstateNavigationDfd?.resolve();
406
- pendingPopstateNavigationDfd = null;
407
- pendingRevalidationDfd?.resolve();
408
- pendingRevalidationDfd = null;
409
412
  }
410
413
  async function navigate(to, opts) {
414
+ if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
411
415
  pendingPopstateNavigationDfd?.resolve();
412
416
  pendingPopstateNavigationDfd = null;
413
417
  if (typeof to === "number") {
@@ -484,22 +488,28 @@ function createRouter(init) {
484
488
  });
485
489
  }
486
490
  function revalidate() {
491
+ if (pendingDiscoveryCancellation) return pendingDiscoveryCancellation.then(revalidate);
487
492
  if (!pendingRevalidationDfd) pendingRevalidationDfd = createDeferred();
488
493
  interruptActiveLoads();
489
494
  updateState({ revalidation: "loading" });
490
495
  let promise = pendingRevalidationDfd.promise;
491
496
  if (state.navigation.state === "submitting") return promise;
492
497
  if (state.navigation.state === "idle") {
493
- startNavigation(state.historyAction, state.location, { startUninterruptedRevalidation: true });
498
+ startNavigation(state.historyAction, state.location, {
499
+ startUninterruptedRevalidation: true,
500
+ dataStrategyInitiator: "revalidation"
501
+ });
494
502
  return promise;
495
503
  }
496
504
  startNavigation(pendingAction || state.historyAction, state.navigation.location, {
497
505
  overrideNavigation: state.navigation,
506
+ dataStrategyInitiator: "revalidation",
498
507
  enableViewTransition: pendingViewTransitionEnabled === true
499
508
  });
500
509
  return promise;
501
510
  }
502
511
  async function startNavigation(historyAction, location, opts) {
512
+ if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
503
513
  pendingNavigationController && pendingNavigationController.abort();
504
514
  pendingNavigationController = null;
505
515
  pendingAction = historyAction;
@@ -535,6 +545,7 @@ function createRouter(init) {
535
545
  } : void 0;
536
546
  pendingNavigationController = new AbortController();
537
547
  let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
548
+ let dataStrategyInitiator = opts?.initialHydration ? "initialization" : opts?.dataStrategyInitiator ?? "navigation";
538
549
  let scopedContext = init.getContext ? await init.getContext() : new RouterContextProvider();
539
550
  let pendingActionResult;
540
551
  if (opts && opts.pendingError) pendingActionResult = [findNearestBoundary(matches).route.id, {
@@ -542,7 +553,7 @@ function createRouter(init) {
542
553
  error: opts.pendingError
543
554
  }];
544
555
  else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
545
- let actionResult = await handleAction(request, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
556
+ let actionResult = await handleAction(request, dataStrategyInitiator, location, opts.submission, matches, historyAction, scopedContext, fogOfWar.active, opts && opts.initialHydration === true, {
546
557
  replace: opts.replace,
547
558
  flushSync
548
559
  });
@@ -566,7 +577,7 @@ function createRouter(init) {
566
577
  fogOfWar.active = false;
567
578
  request = createClientSideRequest(init.history, request.url, request.signal);
568
579
  }
569
- let { shortCircuited, matches: updatedMatches, loaderData, errors, workingFetchers } = await handleLoaders(request, location, matches, historyAction, scopedContext, fogOfWar.active, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionResult, opts && opts.callSiteDefaultShouldRevalidate);
580
+ let { shortCircuited, matches: updatedMatches, loaderData, errors, workingFetchers } = await handleLoaders(request, dataStrategyInitiator, location, matches, historyAction, scopedContext, fogOfWar.active, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, opts && opts.initialHydration === true, flushSync, pendingActionResult, opts && opts.callSiteDefaultShouldRevalidate);
570
581
  if (shortCircuited) return;
571
582
  pendingNavigationController = null;
572
583
  completeNavigation(location, {
@@ -577,13 +588,57 @@ function createRouter(init) {
577
588
  ...workingFetchers ? { fetchers: workingFetchers } : {}
578
589
  });
579
590
  }
580
- async function handleAction(request, location, submission, matches, historyAction, scopedContext, isFogOfWar, initialHydration, opts = {}) {
581
- interruptActiveLoads();
591
+ function cancelDiscoveryNavigation() {
592
+ let cancellation = createDeferred();
593
+ pendingDiscoveryCancellation = cancellation.promise;
594
+ let delta = pendingPopstateDelta;
595
+ let popstateNavigationDfd = pendingPopstateNavigationDfd;
596
+ pendingPopstateNavigationDfd = null;
597
+ pendingNavigationController?.abort();
598
+ pendingNavigationController = null;
599
+ resetPendingNavigation();
600
+ pendingRevalidationDfd?.resolve();
601
+ pendingRevalidationDfd = null;
602
+ let blockers = new Map(state.blockers);
603
+ blockers.forEach((blocker, key) => {
604
+ if (blocker.state === "proceeding") blockers.set(key, IDLE_BLOCKER);
605
+ });
606
+ let fetchers = new Map(state.fetchers);
607
+ let didUpdateFetchers = markFetchRedirectsDone(fetchers);
608
+ fetchers.forEach((fetcher, key) => {
609
+ if (fetcher.state === "loading" && !fetchControllers.has(key)) {
610
+ fetchers.set(key, getDoneFetcher(fetcher.data));
611
+ didUpdateFetchers = true;
612
+ }
613
+ });
614
+ cancelledFetcherLoads.clear();
615
+ updateState({
616
+ navigation: IDLE_NAVIGATION,
617
+ revalidation: "idle",
618
+ blockers,
619
+ ...didUpdateFetchers ? { fetchers } : {}
620
+ });
621
+ function finishCancellation() {
622
+ pendingDiscoveryCancellation = void 0;
623
+ popstateNavigationDfd?.resolve();
624
+ cancellation.resolve();
625
+ }
626
+ if (delta) {
627
+ unblockBlockerHistoryUpdate = finishCancellation;
628
+ init.history.go(-delta);
629
+ } else finishCancellation();
630
+ return cancellation.promise;
631
+ }
632
+ async function handleAction(request, dataStrategyInitiator, location, submission, matches, historyAction, scopedContext, isFogOfWar, initialHydration, opts = {}) {
633
+ if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
582
634
  updateState({ navigation: getSubmittingNavigation(location, matches, historyAction, submission) }, { flushSync: opts.flushSync === true });
583
635
  if (isFogOfWar) {
584
636
  let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
585
- if (discoverResult.type === "aborted") return { shortCircuited: true };
586
- else if (discoverResult.type === "error") {
637
+ if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
638
+ else if (discoverResult.type === "cancelled") {
639
+ await cancelDiscoveryNavigation();
640
+ return { shortCircuited: true };
641
+ } else if (discoverResult.type === "error") {
587
642
  if (discoverResult.partialMatches.length === 0) {
588
643
  let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
589
644
  return {
@@ -613,6 +668,7 @@ function createRouter(init) {
613
668
  };
614
669
  } else matches = discoverResult.matches;
615
670
  }
671
+ if (future.unstable_customRouteDiscovery) interruptActiveLoads();
616
672
  let result;
617
673
  let actionMatch = getTargetMatch(matches, location);
618
674
  if (!actionMatch.route.action && !actionMatch.route.lazy) result = {
@@ -624,7 +680,7 @@ function createRouter(init) {
624
680
  })
625
681
  };
626
682
  else {
627
- let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null);
683
+ let results = await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, initialHydration ? [] : hydrationRouteProperties, scopedContext), scopedContext, null, dataStrategyInitiator, historyAction);
628
684
  result = results[actionMatch.route.id];
629
685
  if (!result) {
630
686
  for (let match of matches) if (results[match.route.id]) {
@@ -638,7 +694,7 @@ function createRouter(init) {
638
694
  let replace;
639
695
  if (opts && opts.replace != null) replace = opts.replace;
640
696
  else replace = normalizeRedirectLocation(result.response.headers.get("Location"), new URL(request.url), basename, init.history) === state.location.pathname + state.location.search;
641
- await startRedirectNavigation(request, result, true, {
697
+ await startRedirectNavigation(request, result, true, dataStrategyInitiator, {
642
698
  submission,
643
699
  replace
644
700
  });
@@ -661,7 +717,7 @@ function createRouter(init) {
661
717
  pendingActionResult: [actionMatch.route.id, result]
662
718
  };
663
719
  }
664
- async function handleLoaders(request, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
720
+ async function handleLoaders(request, dataStrategyInitiator, location, matches, historyAction, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult, callSiteDefaultShouldRevalidate) {
665
721
  let loadingNavigation = overrideNavigation || getLoadingNavigation(location, matches, historyAction, submission);
666
722
  let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
667
723
  let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
@@ -674,8 +730,11 @@ function createRouter(init) {
674
730
  }, { flushSync });
675
731
  }
676
732
  let discoverResult = await discoverRoutes(matches, location.pathname, request.signal);
677
- if (discoverResult.type === "aborted") return { shortCircuited: true };
678
- else if (discoverResult.type === "error") {
733
+ if (future.unstable_customRouteDiscovery && request.signal.aborted || discoverResult.type === "aborted") return { shortCircuited: true };
734
+ else if (discoverResult.type === "cancelled") {
735
+ await cancelDiscoveryNavigation();
736
+ return { shortCircuited: true };
737
+ } else if (discoverResult.type === "error") {
679
738
  if (discoverResult.partialMatches.length === 0) {
680
739
  let { matches, route } = getShortCircuitMatches(dataRoutes.activeRoutes);
681
740
  return {
@@ -697,7 +756,10 @@ function createRouter(init) {
697
756
  loaderData: {},
698
757
  errors: { [route.id]: error }
699
758
  };
700
- } else matches = discoverResult.matches;
759
+ } else {
760
+ matches = discoverResult.matches;
761
+ if (initialHydration && !request.signal.aborted) updateState({ matches });
762
+ }
701
763
  }
702
764
  let { dsMatches, revalidatingFetchers } = getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, init.history, state, matches, activeSubmission, location, initialHydration ? [] : hydrationRouteProperties, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, pendingActionResult, callSiteDefaultShouldRevalidate);
703
765
  pendingNavigationLoadId = ++incrementingLoadId;
@@ -729,27 +791,31 @@ function createRouter(init) {
729
791
  });
730
792
  let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((f) => abortFetcher(f.key));
731
793
  if (pendingNavigationController) pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
732
- let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext);
794
+ let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, request, location, scopedContext, dataStrategyInitiator, historyAction);
733
795
  if (request.signal.aborted) return { shortCircuited: true };
734
796
  if (pendingNavigationController) pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
735
797
  revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
736
798
  let redirect = findRedirect(loaderResults);
737
799
  if (redirect) {
738
- await startRedirectNavigation(request, redirect.result, true, { replace });
800
+ await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
739
801
  return { shortCircuited: true };
740
802
  }
741
803
  redirect = findRedirect(fetcherResults);
742
804
  if (redirect) {
743
805
  fetchRedirectIds.add(redirect.key);
744
- await startRedirectNavigation(request, redirect.result, true, { replace });
806
+ await startRedirectNavigation(request, redirect.result, true, dataStrategyInitiator, { replace });
745
807
  return { shortCircuited: true };
746
808
  }
747
809
  let workingFetchers = new Map(state.fetchers);
748
810
  let { loaderData, errors } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, workingFetchers);
749
- if (initialHydration && state.errors) errors = {
750
- ...state.errors,
751
- ...errors
752
- };
811
+ if (initialHydration && state.errors) {
812
+ let newClientErrors = errors ?? null;
813
+ errors = {
814
+ ...state.errors,
815
+ ...errors
816
+ };
817
+ clientErrors.set(errors, newClientErrors);
818
+ }
753
819
  let didUpdateFetcherRedirects = markFetchRedirectsDone(workingFetchers);
754
820
  let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId, workingFetchers);
755
821
  let shouldUpdateFetchers = didUpdateFetcherRedirects || didAbortFetchLoads || revalidatingFetchers.length > 0;
@@ -775,6 +841,7 @@ function createRouter(init) {
775
841
  return workingFetchers;
776
842
  }
777
843
  async function fetch(key, routeId, href, opts) {
844
+ if (pendingDiscoveryCancellation) await pendingDiscoveryCancellation;
778
845
  abortFetcher(key);
779
846
  let flushSync = (opts && opts.flushSync) === true;
780
847
  let instrumentationResultMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
@@ -807,15 +874,22 @@ function createRouter(init) {
807
874
  await handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission);
808
875
  }
809
876
  async function handleFetcherAction(key, routeId, path, requestMatches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission, callSiteDefaultShouldRevalidate) {
810
- interruptActiveLoads();
877
+ if (!future.unstable_customRouteDiscovery) interruptActiveLoads();
811
878
  fetchLoadMatches.delete(key);
812
- updateFetcherState(key, getSubmittingFetcher(submission, state.fetchers.get(key)), { flushSync });
879
+ let existingFetcher = state.fetchers.get(key);
880
+ updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), { flushSync });
813
881
  let abortController = new AbortController();
882
+ if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
814
883
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
815
884
  if (isFogOfWar) {
816
885
  let discoverResult = await discoverRoutes(requestMatches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
817
- if (discoverResult.type === "aborted") return;
818
- else if (discoverResult.type === "error") {
886
+ if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
887
+ else if (discoverResult.type === "cancelled") {
888
+ fetchControllers.delete(key);
889
+ fetchLoadMatches.delete(key);
890
+ updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
891
+ return;
892
+ } else if (discoverResult.type === "error") {
819
893
  setFetcherError(key, routeId, discoverResult.error, { flushSync });
820
894
  return;
821
895
  } else if (!discoverResult.matches) {
@@ -832,10 +906,11 @@ function createRouter(init) {
832
906
  }), { flushSync });
833
907
  return;
834
908
  }
909
+ if (future.unstable_customRouteDiscovery) interruptActiveLoads();
835
910
  fetchControllers.set(key, abortController);
836
911
  let originatingLoadId = incrementingLoadId;
837
912
  let fetchMatches = getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, requestMatches, match, hydrationRouteProperties, scopedContext);
838
- let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key);
913
+ let actionResults = await callDataStrategy(fetchRequest, path, fetchMatches, scopedContext, key, "fetcher");
839
914
  let actionResult = actionResults[match.route.id];
840
915
  if (!actionResult) {
841
916
  for (let match of fetchMatches) if (actionResults[match.route.id]) {
@@ -861,7 +936,7 @@ function createRouter(init) {
861
936
  } else {
862
937
  fetchRedirectIds.add(key);
863
938
  updateFetcherState(key, getLoadingFetcher(submission));
864
- return startRedirectNavigation(fetchRequest, actionResult, false, {
939
+ return startRedirectNavigation(fetchRequest, actionResult, false, "fetcher", {
865
940
  fetcherSubmission: submission,
866
941
  preventScrollReset
867
942
  });
@@ -893,7 +968,7 @@ function createRouter(init) {
893
968
  updateState({ fetchers: workingFetchers });
894
969
  let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
895
970
  abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
896
- let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext);
971
+ let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext, "fetcher");
897
972
  if (abortController.signal.aborted) {
898
973
  if (fetchReloadIds.get(key) === loadId) fetchReloadIds.delete(key);
899
974
  return;
@@ -915,13 +990,13 @@ function createRouter(init) {
915
990
  let redirect = findRedirect(loaderResults);
916
991
  if (redirect) {
917
992
  state = getRedirectStateWithDoneFetcher(state);
918
- return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
993
+ return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
919
994
  }
920
995
  redirect = findRedirect(fetcherResults);
921
996
  if (redirect) {
922
997
  fetchRedirectIds.add(redirect.key);
923
998
  state = getRedirectStateWithDoneFetcher(state);
924
- return startRedirectNavigation(revalidationRequest, redirect.result, false, { preventScrollReset });
999
+ return startRedirectNavigation(revalidationRequest, redirect.result, false, "fetcher", { preventScrollReset });
925
1000
  }
926
1001
  let finalFetchers = new Map(state.fetchers);
927
1002
  if (fetcherIsMounted) finalFetchers.set(key, getDoneFetcher(actionResult.data));
@@ -950,11 +1025,17 @@ function createRouter(init) {
950
1025
  let existingFetcher = state.fetchers.get(key);
951
1026
  updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : void 0), { flushSync });
952
1027
  let abortController = new AbortController();
1028
+ if (future.unstable_customRouteDiscovery) fetchControllers.set(key, abortController);
953
1029
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
954
1030
  if (loadMatch.isDiscovering) {
955
1031
  let discoverResult = await discoverRoutes(matches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
956
- if (discoverResult.type === "aborted") return;
957
- else if (discoverResult.type === "error") {
1032
+ if (future.unstable_customRouteDiscovery && fetchRequest.signal.aborted || discoverResult.type === "aborted") return;
1033
+ else if (discoverResult.type === "cancelled") {
1034
+ fetchControllers.delete(key);
1035
+ fetchLoadMatches.delete(key);
1036
+ updateFetcherState(key, getDoneFetcher(existingFetcher?.data), { flushSync });
1037
+ return;
1038
+ } else if (discoverResult.type === "error") {
958
1039
  setFetcherError(key, routeId, discoverResult.error, { flushSync });
959
1040
  return;
960
1041
  } else if (!discoverResult.matches) {
@@ -968,7 +1049,7 @@ function createRouter(init) {
968
1049
  let match = getTargetMatch(matches, path);
969
1050
  fetchControllers.set(key, abortController);
970
1051
  let originatingLoadId = incrementingLoadId;
971
- let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key);
1052
+ let results = await callDataStrategy(fetchRequest, path, getTargetedDataStrategyMatches(mapRouteProperties, manifest, fetchRequest, path, matches, match, hydrationRouteProperties, scopedContext), scopedContext, key, "fetcher");
972
1053
  let result = results[match.route.id];
973
1054
  if (!result) {
974
1055
  for (let match of matches) if (results[match.route.id]) {
@@ -987,7 +1068,7 @@ function createRouter(init) {
987
1068
  return;
988
1069
  } else {
989
1070
  fetchRedirectIds.add(key);
990
- await startRedirectNavigation(fetchRequest, result, false, { preventScrollReset });
1071
+ await startRedirectNavigation(fetchRequest, result, false, "fetcher", { preventScrollReset });
991
1072
  return;
992
1073
  }
993
1074
  if (isErrorResult(result)) {
@@ -1015,7 +1096,7 @@ function createRouter(init) {
1015
1096
  * actually touch history until we've processed redirects, so we just use
1016
1097
  * the history action from the original navigation (PUSH or REPLACE).
1017
1098
  */
1018
- async function startRedirectNavigation(request, redirect, isNavigation, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
1099
+ async function startRedirectNavigation(request, redirect, isNavigation, dataStrategyInitiator, { submission, fetcherSubmission, preventScrollReset, replace } = {}) {
1019
1100
  if (!isNavigation) {
1020
1101
  pendingPopstateNavigationDfd?.resolve();
1021
1102
  pendingPopstateNavigationDfd = null;
@@ -1052,20 +1133,22 @@ function createRouter(init) {
1052
1133
  formAction: location
1053
1134
  },
1054
1135
  preventScrollReset: preventScrollReset || pendingPreventScrollReset,
1055
- enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
1136
+ enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
1137
+ dataStrategyInitiator
1056
1138
  });
1057
1139
  else await startNavigation(redirectNavigationType, redirectLocation, {
1058
1140
  overrideNavigation: getLoadingNavigation(redirectLocation, [], redirectNavigationType, submission),
1059
1141
  fetcherSubmission,
1060
1142
  preventScrollReset: preventScrollReset || pendingPreventScrollReset,
1061
- enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
1143
+ enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0,
1144
+ dataStrategyInitiator
1062
1145
  });
1063
1146
  }
1064
- async function callDataStrategy(request, path, matches, scopedContext, fetcherKey) {
1147
+ async function callDataStrategy(request, path, matches, scopedContext, fetcherKey, initiator, navigationType = null) {
1065
1148
  let results;
1066
1149
  let dataResults = {};
1067
1150
  try {
1068
- results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, false);
1151
+ results = await callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, false, navigationType);
1069
1152
  } catch (e) {
1070
1153
  matches.filter((m) => m.shouldLoad).forEach((m) => {
1071
1154
  dataResults[m.route.id] = {
@@ -1092,11 +1175,11 @@ function createRouter(init) {
1092
1175
  } else dataResults[routeId] = await convertDataStrategyResultToDataResult(result);
1093
1176
  return dataResults;
1094
1177
  }
1095
- async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext) {
1096
- let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null);
1178
+ async function callLoadersAndMaybeResolveData(matches, fetchersToLoad, request, location, scopedContext, initiator, navigationType = null) {
1179
+ let loaderResultsPromise = callDataStrategy(request, location, matches, scopedContext, null, initiator, navigationType);
1097
1180
  let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async (f) => {
1098
1181
  if (f.matches && f.match && f.request && f.controller) {
1099
- let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key))[f.match.route.id];
1182
+ let result = (await callDataStrategy(f.request, f.path, f.matches, scopedContext, f.key, initiator, navigationType))[f.match.route.id];
1100
1183
  return { [f.key]: result };
1101
1184
  } else return Promise.resolve({ [f.key]: {
1102
1185
  type: "error",
@@ -1110,7 +1193,8 @@ function createRouter(init) {
1110
1193
  }
1111
1194
  function interruptActiveLoads() {
1112
1195
  isRevalidationRequired = true;
1113
- fetchLoadMatches.forEach((_, key) => {
1196
+ fetchLoadMatches.forEach((loadMatch, key) => {
1197
+ if (future.unstable_customRouteDiscovery && loadMatch.isDiscovering) return;
1114
1198
  if (fetchControllers.has(key)) cancelledFetcherLoads.add(key);
1115
1199
  abortFetcher(key);
1116
1200
  });
@@ -1136,6 +1220,8 @@ function createRouter(init) {
1136
1220
  }
1137
1221
  function resetFetcher(key, opts) {
1138
1222
  abortFetcher(key, opts?.reason);
1223
+ fetchLoadMatches.delete(key);
1224
+ cancelledFetcherLoads.delete(key);
1139
1225
  updateFetcherState(key, getDoneFetcher(null));
1140
1226
  }
1141
1227
  function deleteFetcher(fetchers, key) {
@@ -1308,6 +1394,10 @@ function createRouter(init) {
1308
1394
  }
1309
1395
  });
1310
1396
  } catch (e) {
1397
+ if (future.unstable_customRouteDiscovery) {
1398
+ if (signal.aborted) return { type: "aborted" };
1399
+ if (e instanceof DiscoveryCancelledError) return { type: "cancelled" };
1400
+ }
1311
1401
  return {
1312
1402
  type: "error",
1313
1403
  error: e,
@@ -1768,7 +1858,7 @@ function createStaticHandler(routes, opts) {
1768
1858
  };
1769
1859
  }
1770
1860
  async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
1771
- let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, requestContext, true);
1861
+ let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, "static", requestContext, true);
1772
1862
  let dataResults = {};
1773
1863
  await Promise.all(matches.map(async (match) => {
1774
1864
  if (!(match.route.id in results)) return;
@@ -2409,7 +2499,7 @@ function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, p
2409
2499
  return getDataStrategyMatch(mapRouteProperties, manifest, request, path, getRoutePattern(matches), match, lazyRoutePropertiesToSkip, scopedContext, true, shouldRevalidateArgs);
2410
2500
  });
2411
2501
  }
2412
- async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
2502
+ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, initiator, scopedContext, isStaticHandler, navigationType = null) {
2413
2503
  if (matches.some((m) => m._lazyPromises?.middleware)) await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
2414
2504
  let dataStrategyArgs = {
2415
2505
  request,
@@ -2417,7 +2507,9 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
2417
2507
  pattern: getRoutePattern(matches),
2418
2508
  params: matches[0].params,
2419
2509
  context: scopedContext,
2420
- matches
2510
+ matches,
2511
+ unstable_initiator: initiator,
2512
+ unstable_navigationType: initiator === "navigation" ? navigationType : null
2421
2513
  };
2422
2514
  let runClientMiddleware = isStaticHandler ? () => {
2423
2515
  throw new Error("You cannot call `runClientMiddleware()` from a static handler `dataStrategy`. Middleware is run outside of `dataStrategy` during SSR in order to bubble up the Response. You can enable middleware via the `respond` API in `query`/`queryRoute`");
@@ -3014,4 +3106,4 @@ function createDeferred() {
3014
3106
  };
3015
3107
  }
3016
3108
  //#endregion
3017
- export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
3109
+ export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, clientErrors, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.4.0
2
+ * react-router v8.5.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
 
2
- import { Location, Path, To } from "./history.js";
2
+ import { Action, Location, Path, To } from "./history.js";
3
3
  import * as React$1 from "react";
4
4
 
5
5
  //#region lib/router/utils.d.ts
@@ -389,6 +389,11 @@ interface DataStrategyMatch extends RouteMatch<string, DataRouteObject> {
389
389
  */
390
390
  resolve: (handlerOverride?: (handler: (ctx?: unknown) => DataFunctionReturnValue) => DataFunctionReturnValue) => Promise<DataStrategyResult>;
391
391
  }
392
+ /**
393
+ * The operation that initiated a data strategy execution. Static handler
394
+ * executions use `"static"`.
395
+ */
396
+ type DataStrategyInitiator = "initialization" | "navigation" | "fetcher" | "revalidation" | "static";
392
397
  interface DataStrategyFunctionArgs<Context = DefaultContext> extends DataFunctionArgs<Context> {
393
398
  /**
394
399
  * Matches for this route extended with Data strategy APIs
@@ -396,8 +401,23 @@ interface DataStrategyFunctionArgs<Context = DefaultContext> extends DataFunctio
396
401
  matches: DataStrategyMatch[];
397
402
  runClientMiddleware: (cb: DataStrategyFunction<Context>) => Promise<Record<string, DataStrategyResult>>;
398
403
  /**
399
- * The key of the fetcher we are calling `dataStrategy` for, otherwise `null`
400
- * for navigational executions
404
+ * The operation that initiated this data strategy execution
405
+ *
406
+ * This field is experimental and subject to breaking changes.
407
+ */
408
+ unstable_initiator: DataStrategyInitiator;
409
+ /**
410
+ * The history action (`"PUSH"`, `"REPLACE"`, or `"POP"`) for a navigation-
411
+ * initiated execution, including fetchers reloaded by that navigation.
412
+ * `null` for initialization, fetcher, revalidation, and static executions.
413
+ *
414
+ * This field is experimental and subject to breaking changes.
415
+ */
416
+ unstable_navigationType: Action | null;
417
+ /**
418
+ * The key of the fetcher targeted by this data strategy execution, otherwise
419
+ * `null`. Fetchers reloaded during a navigation or revalidation retain that
420
+ * `unstable_initiator` while providing their key here.
401
421
  */
402
422
  fetcherKey: string | null;
403
423
  }
@@ -962,4 +982,4 @@ declare class ErrorResponseImpl implements ErrorResponse {
962
982
  */
963
983
  declare function isRouteErrorResponse(error: any): error is ErrorResponse;
964
984
  //#endregion
965
- export { ActionFunction, ActionFunctionArgs, BaseRouteObject, DataRouteMatch, DataRouteObject, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyMatch, DataStrategyResult, DataWithResponseInit, ErrorResponse, ErrorResponseImpl, FormEncType, FormMethod, HTMLFormMethod, IndexRouteObject, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, MapRoutePropertiesFunction, MaybePromise, MiddlewareFunction, MiddlewareNextFunction, NonIndexRouteObject, ParamParseKey, Params, PatchRoutesOnNavigationFunction, PatchRoutesOnNavigationFunctionArgs, PathMatch, PathParam, PathPattern, RedirectFunction, RouteBranch, RouteData, RouteManifest, RouteMatch, RouteObject, RouterContext, RouterContextProvider, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, Submission, TrackedPromise, UIMatch, createContext, data, defaultMapRouteProperties, generatePath, isRouteErrorResponse, matchPath, matchRoutes, redirect, redirectDocument, replace, resolvePath };
985
+ export { ActionFunction, ActionFunctionArgs, BaseRouteObject, DataRouteMatch, DataRouteObject, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyInitiator, DataStrategyMatch, DataStrategyResult, DataWithResponseInit, ErrorResponse, ErrorResponseImpl, FormEncType, FormMethod, HTMLFormMethod, IndexRouteObject, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, MapRoutePropertiesFunction, MaybePromise, MiddlewareFunction, MiddlewareNextFunction, NonIndexRouteObject, ParamParseKey, Params, PatchRoutesOnNavigationFunction, PatchRoutesOnNavigationFunctionArgs, PathMatch, PathParam, PathPattern, RedirectFunction, RouteBranch, RouteData, RouteManifest, RouteMatch, RouteObject, RouterContext, RouterContextProvider, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, Submission, TrackedPromise, UIMatch, createContext, data, defaultMapRouteProperties, generatePath, isRouteErrorResponse, matchPath, matchRoutes, redirect, redirectDocument, replace, resolvePath };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.4.0
2
+ * react-router v8.5.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -129,6 +129,7 @@ var RouterContextProvider = class {
129
129
  this.#map.set(context, value);
130
130
  }
131
131
  };
132
+ var DiscoveryCancelledError = class extends Error {};
132
133
  const unsupportedLazyRouteObjectKeys = new Set([
133
134
  "lazy",
134
135
  "caseSensitive",
@@ -514,7 +515,7 @@ function compilePath(path, caseSensitive = false, end = true) {
514
515
  return "(?:/([^\\/]*))?";
515
516
  }
516
517
  return "/([^\\/]+)";
517
- }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
518
+ }).replace(/\/((?:[^/?()[\]*^\\]|\\.)+)\?(?=\/|$|\()/g, "(?:/$1)?");
518
519
  if (path.endsWith("*")) {
519
520
  params.push({ paramName: "*" });
520
521
  regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
@@ -875,4 +876,4 @@ function parseToInfo(_to, basename) {
875
876
  };
876
877
  }
877
878
  //#endregion
878
- export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, explodeOptionalSegments, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, normalizePathname, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
879
+ export { DiscoveryCancelledError, ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, explodeOptionalSegments, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, normalizePathname, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };