react-router 7.2.0 → 7.3.0-pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +266 -0
  2. package/dist/development/{chunk-HA7DTUK3.mjs → chunk-3XNZT7XE.mjs} +782 -340
  3. package/dist/development/dom-export.d.mts +13 -3
  4. package/dist/development/dom-export.d.ts +13 -3
  5. package/dist/development/dom-export.js +306 -83
  6. package/dist/development/dom-export.mjs +14 -5
  7. package/dist/development/{fog-of-war-Cm1iXIp7.d.ts → fog-of-war-CvttGpNz.d.ts} +93 -9
  8. package/dist/{production/fog-of-war-Cm1iXIp7.d.ts → development/fog-of-war-Da8gpnoZ.d.mts} +93 -9
  9. package/dist/{production/data-CQbyyGzl.d.mts → development/future-ldDp5FKH.d.mts} +11 -1
  10. package/dist/development/{data-CQbyyGzl.d.mts → future-ldDp5FKH.d.ts} +11 -1
  11. package/dist/development/index.d.mts +16 -14
  12. package/dist/development/index.d.ts +16 -14
  13. package/dist/development/index.js +784 -340
  14. package/dist/development/index.mjs +6 -2
  15. package/dist/development/lib/types/route-module.d.mts +25 -6
  16. package/dist/development/lib/types/route-module.d.ts +25 -6
  17. package/dist/development/lib/types/route-module.js +1 -1
  18. package/dist/development/lib/types/route-module.mjs +1 -1
  19. package/dist/{production/route-data-BmvbmBej.d.mts → development/route-data-H2S3hwhf.d.mts} +66 -13
  20. package/dist/development/{route-data-BmvbmBej.d.mts → route-data-H2S3hwhf.d.ts} +66 -13
  21. package/dist/production/{chunk-Z4EF7MSU.mjs → chunk-ZGBK665M.mjs} +782 -340
  22. package/dist/production/dom-export.d.mts +13 -3
  23. package/dist/production/dom-export.d.ts +13 -3
  24. package/dist/production/dom-export.js +306 -83
  25. package/dist/production/dom-export.mjs +14 -5
  26. package/dist/production/{fog-of-war-BALYJxf_.d.mts → fog-of-war-CvttGpNz.d.ts} +93 -9
  27. package/dist/{development/fog-of-war-BALYJxf_.d.mts → production/fog-of-war-Da8gpnoZ.d.mts} +93 -9
  28. package/dist/{development/data-CQbyyGzl.d.ts → production/future-ldDp5FKH.d.mts} +11 -1
  29. package/dist/production/{data-CQbyyGzl.d.ts → future-ldDp5FKH.d.ts} +11 -1
  30. package/dist/production/index.d.mts +16 -14
  31. package/dist/production/index.d.ts +16 -14
  32. package/dist/production/index.js +784 -340
  33. package/dist/production/index.mjs +6 -2
  34. package/dist/production/lib/types/route-module.d.mts +25 -6
  35. package/dist/production/lib/types/route-module.d.ts +25 -6
  36. package/dist/production/lib/types/route-module.js +1 -1
  37. package/dist/production/lib/types/route-module.mjs +1 -1
  38. package/dist/{development/route-data-BmvbmBej.d.ts → production/route-data-H2S3hwhf.d.mts} +66 -13
  39. package/dist/production/{route-data-BmvbmBej.d.ts → route-data-H2S3hwhf.d.ts} +66 -13
  40. package/package.json +3 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.2.0
2
+ * react-router v7.3.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,6 +8,12 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
+ var __typeError = (msg) => {
12
+ throw TypeError(msg);
13
+ };
14
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
15
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
16
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
11
17
 
12
18
  // lib/router/history.ts
13
19
  var Action = /* @__PURE__ */ ((Action2) => {
@@ -350,6 +356,33 @@ function getUrlBasedHistory(getLocation, createHref2, validateLocation, options
350
356
  }
351
357
 
352
358
  // lib/router/utils.ts
359
+ function unstable_createContext(defaultValue) {
360
+ return { defaultValue };
361
+ }
362
+ var _map;
363
+ var unstable_RouterContextProvider = class {
364
+ constructor(init) {
365
+ __privateAdd(this, _map, /* @__PURE__ */ new Map());
366
+ if (init) {
367
+ for (let [context, value] of init) {
368
+ this.set(context, value);
369
+ }
370
+ }
371
+ }
372
+ get(context) {
373
+ if (__privateGet(this, _map).has(context)) {
374
+ return __privateGet(this, _map).get(context);
375
+ }
376
+ if (context.defaultValue !== void 0) {
377
+ return context.defaultValue;
378
+ }
379
+ throw new Error("No value found for context");
380
+ }
381
+ set(context, value) {
382
+ __privateGet(this, _map).set(context, value);
383
+ }
384
+ };
385
+ _map = new WeakMap();
353
386
  var immutableRouteKeys = /* @__PURE__ */ new Set([
354
387
  "lazy",
355
388
  "caseSensitive",
@@ -907,9 +940,9 @@ function createRouter(init) {
907
940
  );
908
941
  let inFlightDataRoutes;
909
942
  let basename = init.basename || "/";
910
- let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
911
- let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
943
+ let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
912
944
  let future = {
945
+ unstable_middleware: false,
913
946
  ...init.future
914
947
  };
915
948
  let unlistenHistory = null;
@@ -921,7 +954,7 @@ function createRouter(init) {
921
954
  let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
922
955
  let initialMatchesIsFOW = false;
923
956
  let initialErrors = null;
924
- if (initialMatches == null && !patchRoutesOnNavigationImpl) {
957
+ if (initialMatches == null && !init.patchRoutesOnNavigation) {
925
958
  let error = getInternalRouterError(404, {
926
959
  pathname: init.history.location.pathname
927
960
  });
@@ -1352,6 +1385,9 @@ function createRouter(init) {
1352
1385
  pendingNavigationController.signal,
1353
1386
  opts && opts.submission
1354
1387
  );
1388
+ let scopedContext = new unstable_RouterContextProvider(
1389
+ init.unstable_getContext ? await init.unstable_getContext() : void 0
1390
+ );
1355
1391
  let pendingActionResult;
1356
1392
  if (opts && opts.pendingError) {
1357
1393
  pendingActionResult = [
@@ -1364,6 +1400,7 @@ function createRouter(init) {
1364
1400
  location,
1365
1401
  opts.submission,
1366
1402
  matches,
1403
+ scopedContext,
1367
1404
  fogOfWar.active,
1368
1405
  { replace: opts.replace, flushSync }
1369
1406
  );
@@ -1404,6 +1441,7 @@ function createRouter(init) {
1404
1441
  request,
1405
1442
  location,
1406
1443
  matches,
1444
+ scopedContext,
1407
1445
  fogOfWar.active,
1408
1446
  loadingNavigation,
1409
1447
  opts && opts.submission,
@@ -1424,7 +1462,7 @@ function createRouter(init) {
1424
1462
  errors
1425
1463
  });
1426
1464
  }
1427
- async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
1465
+ async function handleAction(request, location, submission, matches, scopedContext, isFogOfWar, opts = {}) {
1428
1466
  interruptActiveLoads();
1429
1467
  let navigation = getSubmittingNavigation(location, submission);
1430
1468
  updateState({ navigation }, { flushSync: opts.flushSync === true });
@@ -1480,13 +1518,21 @@ function createRouter(init) {
1480
1518
  } else {
1481
1519
  let results = await callDataStrategy(
1482
1520
  "action",
1483
- state,
1484
1521
  request,
1485
1522
  [actionMatch],
1486
1523
  matches,
1524
+ scopedContext,
1487
1525
  null
1488
1526
  );
1489
1527
  result = results[actionMatch.route.id];
1528
+ if (!result) {
1529
+ for (let match of matches) {
1530
+ if (results[match.route.id]) {
1531
+ result = results[match.route.id];
1532
+ break;
1533
+ }
1534
+ }
1535
+ }
1490
1536
  if (request.signal.aborted) {
1491
1537
  return { shortCircuited: true };
1492
1538
  }
@@ -1524,7 +1570,7 @@ function createRouter(init) {
1524
1570
  pendingActionResult: [actionMatch.route.id, result]
1525
1571
  };
1526
1572
  }
1527
- async function handleLoaders(request, location, matches, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync, pendingActionResult) {
1573
+ async function handleLoaders(request, location, matches, scopedContext, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync, pendingActionResult) {
1528
1574
  let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
1529
1575
  let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
1530
1576
  let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
@@ -1634,11 +1680,11 @@ function createRouter(init) {
1634
1680
  );
1635
1681
  }
1636
1682
  let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1637
- state,
1638
1683
  matches,
1639
1684
  matchesToLoad,
1640
1685
  revalidatingFetchers,
1641
- request
1686
+ request,
1687
+ scopedContext
1642
1688
  );
1643
1689
  if (request.signal.aborted) {
1644
1690
  return { shortCircuited: true };
@@ -1746,6 +1792,9 @@ function createRouter(init) {
1746
1792
  return;
1747
1793
  }
1748
1794
  let match = getTargetMatch(matches, path);
1795
+ let scopedContext = new unstable_RouterContextProvider(
1796
+ init.unstable_getContext ? await init.unstable_getContext() : void 0
1797
+ );
1749
1798
  let preventScrollReset = (opts && opts.preventScrollReset) === true;
1750
1799
  if (submission && isMutationMethod(submission.formMethod)) {
1751
1800
  await handleFetcherAction(
@@ -1754,6 +1803,7 @@ function createRouter(init) {
1754
1803
  path,
1755
1804
  match,
1756
1805
  matches,
1806
+ scopedContext,
1757
1807
  fogOfWar.active,
1758
1808
  flushSync,
1759
1809
  preventScrollReset,
@@ -1768,13 +1818,14 @@ function createRouter(init) {
1768
1818
  path,
1769
1819
  match,
1770
1820
  matches,
1821
+ scopedContext,
1771
1822
  fogOfWar.active,
1772
1823
  flushSync,
1773
1824
  preventScrollReset,
1774
1825
  submission
1775
1826
  );
1776
1827
  }
1777
- async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) {
1828
+ async function handleFetcherAction(key, routeId, path, match, requestMatches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission) {
1778
1829
  interruptActiveLoads();
1779
1830
  fetchLoadMatches.delete(key);
1780
1831
  function detectAndHandle405Error(m) {
@@ -1807,7 +1858,8 @@ function createRouter(init) {
1807
1858
  let discoverResult = await discoverRoutes(
1808
1859
  requestMatches,
1809
1860
  path,
1810
- fetchRequest.signal
1861
+ fetchRequest.signal,
1862
+ key
1811
1863
  );
1812
1864
  if (discoverResult.type === "aborted") {
1813
1865
  return;
@@ -1834,10 +1886,10 @@ function createRouter(init) {
1834
1886
  let originatingLoadId = incrementingLoadId;
1835
1887
  let actionResults = await callDataStrategy(
1836
1888
  "action",
1837
- state,
1838
1889
  fetchRequest,
1839
1890
  [match],
1840
1891
  requestMatches,
1892
+ scopedContext,
1841
1893
  key
1842
1894
  );
1843
1895
  let actionResult = actionResults[match.route.id];
@@ -1921,11 +1973,11 @@ function createRouter(init) {
1921
1973
  abortPendingFetchRevalidations
1922
1974
  );
1923
1975
  let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1924
- state,
1925
1976
  matches,
1926
1977
  matchesToLoad,
1927
1978
  revalidatingFetchers,
1928
- revalidationRequest
1979
+ revalidationRequest,
1980
+ scopedContext
1929
1981
  );
1930
1982
  if (abortController.signal.aborted) {
1931
1983
  return;
@@ -1992,7 +2044,7 @@ function createRouter(init) {
1992
2044
  isRevalidationRequired = false;
1993
2045
  }
1994
2046
  }
1995
- async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) {
2047
+ async function handleFetcherLoader(key, routeId, path, match, matches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission) {
1996
2048
  let existingFetcher = state.fetchers.get(key);
1997
2049
  updateFetcherState(
1998
2050
  key,
@@ -2012,7 +2064,8 @@ function createRouter(init) {
2012
2064
  let discoverResult = await discoverRoutes(
2013
2065
  matches,
2014
2066
  path,
2015
- fetchRequest.signal
2067
+ fetchRequest.signal,
2068
+ key
2016
2069
  );
2017
2070
  if (discoverResult.type === "aborted") {
2018
2071
  return;
@@ -2036,10 +2089,10 @@ function createRouter(init) {
2036
2089
  let originatingLoadId = incrementingLoadId;
2037
2090
  let results = await callDataStrategy(
2038
2091
  "loader",
2039
- state,
2040
2092
  fetchRequest,
2041
2093
  [match],
2042
2094
  matches,
2095
+ scopedContext,
2043
2096
  key
2044
2097
  );
2045
2098
  let result = results[match.route.id];
@@ -2141,20 +2194,21 @@ function createRouter(init) {
2141
2194
  });
2142
2195
  }
2143
2196
  }
2144
- async function callDataStrategy(type, state2, request, matchesToLoad, matches, fetcherKey) {
2197
+ async function callDataStrategy(type, request, matchesToLoad, matches, scopedContext, fetcherKey) {
2145
2198
  let results;
2146
2199
  let dataResults = {};
2147
2200
  try {
2148
2201
  results = await callDataStrategyImpl(
2149
2202
  dataStrategyImpl,
2150
2203
  type,
2151
- state2,
2152
2204
  request,
2153
2205
  matchesToLoad,
2154
2206
  matches,
2155
2207
  fetcherKey,
2156
2208
  manifest,
2157
- mapRouteProperties2
2209
+ mapRouteProperties2,
2210
+ scopedContext,
2211
+ future.unstable_middleware
2158
2212
  );
2159
2213
  } catch (e) {
2160
2214
  matchesToLoad.forEach((m) => {
@@ -2186,13 +2240,13 @@ function createRouter(init) {
2186
2240
  }
2187
2241
  return dataResults;
2188
2242
  }
2189
- async function callLoadersAndMaybeResolveData(state2, matches, matchesToLoad, fetchersToLoad, request) {
2243
+ async function callLoadersAndMaybeResolveData(matches, matchesToLoad, fetchersToLoad, request, scopedContext) {
2190
2244
  let loaderResultsPromise = callDataStrategy(
2191
2245
  "loader",
2192
- state2,
2193
2246
  request,
2194
2247
  matchesToLoad,
2195
2248
  matches,
2249
+ scopedContext,
2196
2250
  null
2197
2251
  );
2198
2252
  let fetcherResultsPromise = Promise.all(
@@ -2200,10 +2254,10 @@ function createRouter(init) {
2200
2254
  if (f.matches && f.match && f.controller) {
2201
2255
  let results = await callDataStrategy(
2202
2256
  "loader",
2203
- state2,
2204
2257
  createClientSideRequest(init.history, f.path, f.controller.signal),
2205
2258
  [f.match],
2206
2259
  f.matches,
2260
+ scopedContext,
2207
2261
  f.key
2208
2262
  );
2209
2263
  let result = results[f.match.route.id];
@@ -2425,7 +2479,7 @@ function createRouter(init) {
2425
2479
  return null;
2426
2480
  }
2427
2481
  function checkFogOfWar(matches, routesToUse, pathname) {
2428
- if (patchRoutesOnNavigationImpl) {
2482
+ if (init.patchRoutesOnNavigation) {
2429
2483
  if (!matches) {
2430
2484
  let fogMatches = matchRoutesImpl(
2431
2485
  routesToUse,
@@ -2448,8 +2502,8 @@ function createRouter(init) {
2448
2502
  }
2449
2503
  return { active: false, matches: null };
2450
2504
  }
2451
- async function discoverRoutes(matches, pathname, signal) {
2452
- if (!patchRoutesOnNavigationImpl) {
2505
+ async function discoverRoutes(matches, pathname, signal, fetcherKey) {
2506
+ if (!init.patchRoutesOnNavigation) {
2453
2507
  return { type: "success", matches };
2454
2508
  }
2455
2509
  let partialMatches = matches;
@@ -2458,10 +2512,11 @@ function createRouter(init) {
2458
2512
  let routesToUse = inFlightDataRoutes || dataRoutes;
2459
2513
  let localManifest = manifest;
2460
2514
  try {
2461
- await patchRoutesOnNavigationImpl({
2515
+ await init.patchRoutesOnNavigation({
2462
2516
  signal,
2463
2517
  path: pathname,
2464
2518
  matches: partialMatches,
2519
+ fetcherKey,
2465
2520
  patch: (routeId, children) => {
2466
2521
  if (signal.aborted) return;
2467
2522
  patchRoutesImpl(
@@ -2580,17 +2635,21 @@ function createStaticHandler(routes, opts) {
2580
2635
  );
2581
2636
  async function query(request, {
2582
2637
  requestContext,
2638
+ filterMatchesToLoad,
2583
2639
  skipLoaderErrorBubbling,
2584
- dataStrategy
2640
+ skipRevalidation,
2641
+ dataStrategy,
2642
+ unstable_respond: respond
2585
2643
  } = {}) {
2586
2644
  let url = new URL(request.url);
2587
2645
  let method = request.method;
2588
2646
  let location = createLocation("", createPath(url), null, "default");
2589
2647
  let matches = matchRoutes(dataRoutes, location, basename);
2648
+ requestContext = requestContext != null ? requestContext : new unstable_RouterContextProvider();
2590
2649
  if (!isValidMethod(method) && method !== "HEAD") {
2591
2650
  let error = getInternalRouterError(405, { method });
2592
2651
  let { matches: methodNotAllowedMatches, route } = getShortCircuitMatches(dataRoutes);
2593
- return {
2652
+ let staticContext = {
2594
2653
  basename,
2595
2654
  location,
2596
2655
  matches: methodNotAllowedMatches,
@@ -2603,10 +2662,11 @@ function createStaticHandler(routes, opts) {
2603
2662
  loaderHeaders: {},
2604
2663
  actionHeaders: {}
2605
2664
  };
2665
+ return respond ? respond(staticContext) : staticContext;
2606
2666
  } else if (!matches) {
2607
2667
  let error = getInternalRouterError(404, { pathname: location.pathname });
2608
2668
  let { matches: notFoundMatches, route } = getShortCircuitMatches(dataRoutes);
2609
- return {
2669
+ let staticContext = {
2610
2670
  basename,
2611
2671
  location,
2612
2672
  matches: notFoundMatches,
@@ -2619,6 +2679,87 @@ function createStaticHandler(routes, opts) {
2619
2679
  loaderHeaders: {},
2620
2680
  actionHeaders: {}
2621
2681
  };
2682
+ return respond ? respond(staticContext) : staticContext;
2683
+ }
2684
+ if (respond && matches.some((m) => m.route.unstable_middleware)) {
2685
+ invariant(
2686
+ requestContext instanceof unstable_RouterContextProvider,
2687
+ "When using middleware in `staticHandler.query()`, any provided `requestContext` must bean instance of `unstable_RouterContextProvider`"
2688
+ );
2689
+ try {
2690
+ let renderedStaticContext;
2691
+ let response = await runMiddlewarePipeline(
2692
+ {
2693
+ request,
2694
+ matches,
2695
+ params: matches[0].params,
2696
+ // If we're calling middleware then it must be enabled so we can cast
2697
+ // this to the proper type knowing it's not an `AppLoadContext`
2698
+ context: requestContext
2699
+ },
2700
+ true,
2701
+ async () => {
2702
+ let result2 = await queryImpl(
2703
+ request,
2704
+ location,
2705
+ matches,
2706
+ requestContext,
2707
+ dataStrategy || null,
2708
+ skipLoaderErrorBubbling === true,
2709
+ null,
2710
+ filterMatchesToLoad || null,
2711
+ skipRevalidation === true
2712
+ );
2713
+ if (isResponse(result2)) {
2714
+ return result2;
2715
+ }
2716
+ renderedStaticContext = { location, basename, ...result2 };
2717
+ let res = await respond(renderedStaticContext);
2718
+ return res;
2719
+ },
2720
+ async (e) => {
2721
+ if (isResponse(e.error)) {
2722
+ return e.error;
2723
+ }
2724
+ if (renderedStaticContext) {
2725
+ if (e.routeId in renderedStaticContext.loaderData) {
2726
+ renderedStaticContext.loaderData[e.routeId] = void 0;
2727
+ }
2728
+ return respond(
2729
+ getStaticContextFromError(
2730
+ dataRoutes,
2731
+ renderedStaticContext,
2732
+ e.error,
2733
+ findNearestBoundary(matches, e.routeId).route.id
2734
+ )
2735
+ );
2736
+ } else {
2737
+ let loaderIdx = matches.findIndex((m) => m.route.loader);
2738
+ let boundary = loaderIdx >= 0 ? findNearestBoundary(matches, matches[loaderIdx].route.id) : findNearestBoundary(matches);
2739
+ return respond({
2740
+ matches,
2741
+ location,
2742
+ basename,
2743
+ loaderData: {},
2744
+ actionData: null,
2745
+ errors: {
2746
+ [boundary.route.id]: e.error
2747
+ },
2748
+ statusCode: isRouteErrorResponse(e.error) ? e.error.status : 500,
2749
+ actionHeaders: {},
2750
+ loaderHeaders: {}
2751
+ });
2752
+ }
2753
+ }
2754
+ );
2755
+ invariant(isResponse(response), "Expected a response in query()");
2756
+ return response;
2757
+ } catch (e) {
2758
+ if (isResponse(e)) {
2759
+ return e;
2760
+ }
2761
+ throw e;
2762
+ }
2622
2763
  }
2623
2764
  let result = await queryImpl(
2624
2765
  request,
@@ -2627,7 +2768,9 @@ function createStaticHandler(routes, opts) {
2627
2768
  requestContext,
2628
2769
  dataStrategy || null,
2629
2770
  skipLoaderErrorBubbling === true,
2630
- null
2771
+ null,
2772
+ filterMatchesToLoad || null,
2773
+ skipRevalidation === true
2631
2774
  );
2632
2775
  if (isResponse(result)) {
2633
2776
  return result;
@@ -2637,12 +2780,14 @@ function createStaticHandler(routes, opts) {
2637
2780
  async function queryRoute(request, {
2638
2781
  routeId,
2639
2782
  requestContext,
2640
- dataStrategy
2783
+ dataStrategy,
2784
+ unstable_respond: respond
2641
2785
  } = {}) {
2642
2786
  let url = new URL(request.url);
2643
2787
  let method = request.method;
2644
2788
  let location = createLocation("", createPath(url), null, "default");
2645
2789
  let matches = matchRoutes(dataRoutes, location, basename);
2790
+ requestContext = requestContext != null ? requestContext : new unstable_RouterContextProvider();
2646
2791
  if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
2647
2792
  throw getInternalRouterError(405, { method });
2648
2793
  } else if (!matches) {
@@ -2657,6 +2802,55 @@ function createStaticHandler(routes, opts) {
2657
2802
  } else if (!match) {
2658
2803
  throw getInternalRouterError(404, { pathname: location.pathname });
2659
2804
  }
2805
+ if (respond && matches.some((m) => m.route.unstable_middleware)) {
2806
+ invariant(
2807
+ requestContext instanceof unstable_RouterContextProvider,
2808
+ "When using middleware in `staticHandler.queryRoute()`, any provided `requestContext` must bean instance of `unstable_RouterContextProvider`"
2809
+ );
2810
+ let response = await runMiddlewarePipeline(
2811
+ {
2812
+ request,
2813
+ matches,
2814
+ params: matches[0].params,
2815
+ // If we're calling middleware then it must be enabled so we can cast
2816
+ // this to the proper type knowing it's not an `AppLoadContext`
2817
+ context: requestContext
2818
+ },
2819
+ true,
2820
+ async () => {
2821
+ let result2 = await queryImpl(
2822
+ request,
2823
+ location,
2824
+ matches,
2825
+ requestContext,
2826
+ dataStrategy || null,
2827
+ false,
2828
+ match,
2829
+ null,
2830
+ false
2831
+ );
2832
+ if (isResponse(result2)) {
2833
+ return respond(result2);
2834
+ }
2835
+ let error2 = result2.errors ? Object.values(result2.errors)[0] : void 0;
2836
+ if (error2 !== void 0) {
2837
+ throw error2;
2838
+ }
2839
+ let value = result2.actionData ? Object.values(result2.actionData)[0] : Object.values(result2.loaderData)[0];
2840
+ return typeof value === "string" ? new Response(value) : Response.json(value);
2841
+ },
2842
+ (e) => {
2843
+ if (isResponse(e.error)) {
2844
+ return respond(e.error);
2845
+ }
2846
+ return new Response(String(e.error), {
2847
+ status: 500,
2848
+ statusText: "Unexpected Server Error"
2849
+ });
2850
+ }
2851
+ );
2852
+ return response;
2853
+ }
2660
2854
  let result = await queryImpl(
2661
2855
  request,
2662
2856
  location,
@@ -2664,7 +2858,9 @@ function createStaticHandler(routes, opts) {
2664
2858
  requestContext,
2665
2859
  dataStrategy || null,
2666
2860
  false,
2667
- match
2861
+ match,
2862
+ null,
2863
+ false
2668
2864
  );
2669
2865
  if (isResponse(result)) {
2670
2866
  return result;
@@ -2681,7 +2877,7 @@ function createStaticHandler(routes, opts) {
2681
2877
  }
2682
2878
  return void 0;
2683
2879
  }
2684
- async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch) {
2880
+ async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, skipRevalidation) {
2685
2881
  invariant(
2686
2882
  request.signal,
2687
2883
  "query()/queryRoute() requests must contain an AbortController signal"
@@ -2695,7 +2891,9 @@ function createStaticHandler(routes, opts) {
2695
2891
  requestContext,
2696
2892
  dataStrategy,
2697
2893
  skipLoaderErrorBubbling,
2698
- routeMatch != null
2894
+ routeMatch != null,
2895
+ filterMatchesToLoad,
2896
+ skipRevalidation
2699
2897
  );
2700
2898
  return result2;
2701
2899
  }
@@ -2705,7 +2903,8 @@ function createStaticHandler(routes, opts) {
2705
2903
  requestContext,
2706
2904
  dataStrategy,
2707
2905
  skipLoaderErrorBubbling,
2708
- routeMatch
2906
+ routeMatch,
2907
+ filterMatchesToLoad
2709
2908
  );
2710
2909
  return isResponse(result) ? result : {
2711
2910
  ...result,
@@ -2725,7 +2924,7 @@ function createStaticHandler(routes, opts) {
2725
2924
  throw e;
2726
2925
  }
2727
2926
  }
2728
- async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest) {
2927
+ async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest, filterMatchesToLoad, skipRevalidation) {
2729
2928
  let result;
2730
2929
  if (!actionMatch.route.action && !actionMatch.route.lazy) {
2731
2930
  let error = getInternalRouterError(405, {
@@ -2779,6 +2978,36 @@ function createStaticHandler(routes, opts) {
2779
2978
  actionHeaders: {}
2780
2979
  };
2781
2980
  }
2981
+ if (skipRevalidation) {
2982
+ if (isErrorResult(result)) {
2983
+ let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
2984
+ return {
2985
+ statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
2986
+ actionData: null,
2987
+ actionHeaders: {
2988
+ ...result.headers ? { [actionMatch.route.id]: result.headers } : {}
2989
+ },
2990
+ matches,
2991
+ loaderData: {},
2992
+ errors: {
2993
+ [boundaryMatch.route.id]: result.error
2994
+ },
2995
+ loaderHeaders: {}
2996
+ };
2997
+ } else {
2998
+ return {
2999
+ actionData: {
3000
+ [actionMatch.route.id]: result.data
3001
+ },
3002
+ actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {},
3003
+ matches,
3004
+ loaderData: {},
3005
+ errors: null,
3006
+ statusCode: result.statusCode || 200,
3007
+ loaderHeaders: {}
3008
+ };
3009
+ }
3010
+ }
2782
3011
  let loaderRequest = new Request(request.url, {
2783
3012
  headers: request.headers,
2784
3013
  redirect: request.redirect,
@@ -2786,17 +3015,18 @@ function createStaticHandler(routes, opts) {
2786
3015
  });
2787
3016
  if (isErrorResult(result)) {
2788
3017
  let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
2789
- let context2 = await loadRouteData(
3018
+ let handlerContext2 = await loadRouteData(
2790
3019
  loaderRequest,
2791
3020
  matches,
2792
3021
  requestContext,
2793
3022
  dataStrategy,
2794
3023
  skipLoaderErrorBubbling,
2795
3024
  null,
3025
+ filterMatchesToLoad,
2796
3026
  [boundaryMatch.route.id, result]
2797
3027
  );
2798
3028
  return {
2799
- ...context2,
3029
+ ...handlerContext2,
2800
3030
  statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
2801
3031
  actionData: null,
2802
3032
  actionHeaders: {
@@ -2804,16 +3034,17 @@ function createStaticHandler(routes, opts) {
2804
3034
  }
2805
3035
  };
2806
3036
  }
2807
- let context = await loadRouteData(
3037
+ let handlerContext = await loadRouteData(
2808
3038
  loaderRequest,
2809
3039
  matches,
2810
3040
  requestContext,
2811
3041
  dataStrategy,
2812
3042
  skipLoaderErrorBubbling,
2813
- null
3043
+ null,
3044
+ filterMatchesToLoad
2814
3045
  );
2815
3046
  return {
2816
- ...context,
3047
+ ...handlerContext,
2817
3048
  actionData: {
2818
3049
  [actionMatch.route.id]: result.data
2819
3050
  },
@@ -2822,7 +3053,7 @@ function createStaticHandler(routes, opts) {
2822
3053
  actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {}
2823
3054
  };
2824
3055
  }
2825
- async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {
3056
+ async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, pendingActionResult) {
2826
3057
  let isRouteRequest = routeMatch != null;
2827
3058
  if (isRouteRequest && !routeMatch?.route.loader && !routeMatch?.route.lazy) {
2828
3059
  throw getInternalRouterError(400, {
@@ -2833,7 +3064,7 @@ function createStaticHandler(routes, opts) {
2833
3064
  }
2834
3065
  let requestMatches = routeMatch ? [routeMatch] : pendingActionResult && isErrorResult(pendingActionResult[1]) ? getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]) : matches;
2835
3066
  let matchesToLoad = requestMatches.filter(
2836
- (m) => m.route.loader || m.route.lazy
3067
+ (m) => (m.route.loader || m.route.lazy) && (!filterMatchesToLoad || filterMatchesToLoad(m))
2837
3068
  );
2838
3069
  if (matchesToLoad.length === 0) {
2839
3070
  return {
@@ -2862,7 +3093,7 @@ function createStaticHandler(routes, opts) {
2862
3093
  if (request.signal.aborted) {
2863
3094
  throwStaticHandlerAbortedError(request, isRouteRequest);
2864
3095
  }
2865
- let context = processRouteLoaderData(
3096
+ let handlerContext = processRouteLoaderData(
2866
3097
  matches,
2867
3098
  results,
2868
3099
  pendingActionResult,
@@ -2874,11 +3105,11 @@ function createStaticHandler(routes, opts) {
2874
3105
  );
2875
3106
  matches.forEach((match) => {
2876
3107
  if (!executedLoaders.has(match.route.id)) {
2877
- context.loaderData[match.route.id] = null;
3108
+ handlerContext.loaderData[match.route.id] = null;
2878
3109
  }
2879
3110
  });
2880
3111
  return {
2881
- ...context,
3112
+ ...handlerContext,
2882
3113
  matches
2883
3114
  };
2884
3115
  }
@@ -2886,14 +3117,15 @@ function createStaticHandler(routes, opts) {
2886
3117
  let results = await callDataStrategyImpl(
2887
3118
  dataStrategy || defaultDataStrategy,
2888
3119
  type,
2889
- null,
2890
3120
  request,
2891
3121
  matchesToLoad,
2892
3122
  matches,
2893
3123
  null,
2894
3124
  manifest,
2895
3125
  mapRouteProperties2,
2896
- requestContext
3126
+ requestContext,
3127
+ false
3128
+ // middleware not done via dataStrategy in the static handler
2897
3129
  );
2898
3130
  let dataResults = {};
2899
3131
  await Promise.all(
@@ -2926,15 +3158,15 @@ function createStaticHandler(routes, opts) {
2926
3158
  queryRoute
2927
3159
  };
2928
3160
  }
2929
- function getStaticContextFromError(routes, context, error) {
2930
- let newContext = {
2931
- ...context,
3161
+ function getStaticContextFromError(routes, handlerContext, error, boundaryId) {
3162
+ let errorBoundaryId = boundaryId || handlerContext._deepestRenderedBoundaryId || routes[0].id;
3163
+ return {
3164
+ ...handlerContext,
2932
3165
  statusCode: isRouteErrorResponse(error) ? error.status : 500,
2933
3166
  errors: {
2934
- [context._deepestRenderedBoundaryId || routes[0].id]: error
3167
+ [errorBoundaryId]: error
2935
3168
  }
2936
3169
  };
2937
- return newContext;
2938
3170
  }
2939
3171
  function throwStaticHandlerAbortedError(request, isRouteRequest) {
2940
3172
  if (request.signal.reason !== void 0) {
@@ -3327,20 +3559,127 @@ async function loadLazyRouteModule(route, mapRouteProperties2, manifest) {
3327
3559
  lazy: void 0
3328
3560
  });
3329
3561
  }
3330
- async function defaultDataStrategy({
3331
- matches
3332
- }) {
3333
- let matchesToLoad = matches.filter((m) => m.shouldLoad);
3562
+ async function defaultDataStrategy(args) {
3563
+ let matchesToLoad = args.matches.filter((m) => m.shouldLoad);
3564
+ let keyedResults = {};
3334
3565
  let results = await Promise.all(matchesToLoad.map((m) => m.resolve()));
3335
- return results.reduce(
3336
- (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
3337
- {}
3566
+ results.forEach((result, i) => {
3567
+ keyedResults[matchesToLoad[i].route.id] = result;
3568
+ });
3569
+ return keyedResults;
3570
+ }
3571
+ async function defaultDataStrategyWithMiddleware(args) {
3572
+ if (!args.matches.some((m) => m.route.unstable_middleware)) {
3573
+ return defaultDataStrategy(args);
3574
+ }
3575
+ return runMiddlewarePipeline(
3576
+ args,
3577
+ false,
3578
+ () => defaultDataStrategy(args),
3579
+ (e) => ({ [e.routeId]: { type: "error", result: e.error } })
3338
3580
  );
3339
3581
  }
3340
- async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, requestContext) {
3582
+ async function runMiddlewarePipeline(args, propagateResult, handler, errorHandler) {
3583
+ let { matches, request, params, context } = args;
3584
+ let middlewareState = {
3585
+ handlerResult: void 0,
3586
+ propagateResult
3587
+ };
3588
+ try {
3589
+ let tuples = matches.flatMap(
3590
+ (m) => m.route.unstable_middleware ? m.route.unstable_middleware.map((fn) => [m.route.id, fn]) : []
3591
+ );
3592
+ let result = await callRouteMiddleware(
3593
+ { request, params, context },
3594
+ tuples,
3595
+ middlewareState,
3596
+ handler
3597
+ );
3598
+ return middlewareState.propagateResult ? result : middlewareState.handlerResult;
3599
+ } catch (e) {
3600
+ if (!(e instanceof MiddlewareError)) {
3601
+ throw e;
3602
+ }
3603
+ let result = await errorHandler(e);
3604
+ if (propagateResult || !middlewareState.handlerResult) {
3605
+ return result;
3606
+ }
3607
+ return Object.assign(middlewareState.handlerResult, result);
3608
+ }
3609
+ }
3610
+ var MiddlewareError = class {
3611
+ constructor(routeId, error) {
3612
+ this.routeId = routeId;
3613
+ this.error = error;
3614
+ }
3615
+ };
3616
+ async function callRouteMiddleware(args, middlewares, middlewareState, handler, idx = 0) {
3617
+ let { request } = args;
3618
+ if (request.signal.aborted) {
3619
+ if (request.signal.reason) {
3620
+ throw request.signal.reason;
3621
+ }
3622
+ throw new Error(
3623
+ `Request aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
3624
+ );
3625
+ }
3626
+ let tuple = middlewares[idx];
3627
+ if (!tuple) {
3628
+ middlewareState.handlerResult = await handler();
3629
+ return middlewareState.handlerResult;
3630
+ }
3631
+ let [routeId, middleware] = tuple;
3632
+ let nextCalled = false;
3633
+ let nextResult = void 0;
3634
+ let next = async () => {
3635
+ if (nextCalled) {
3636
+ throw new Error("You may only call `next()` once per middleware");
3637
+ }
3638
+ nextCalled = true;
3639
+ let result = await callRouteMiddleware(
3640
+ args,
3641
+ middlewares,
3642
+ middlewareState,
3643
+ handler,
3644
+ idx + 1
3645
+ );
3646
+ if (middlewareState.propagateResult) {
3647
+ nextResult = result;
3648
+ return nextResult;
3649
+ }
3650
+ };
3651
+ try {
3652
+ let result = await middleware(
3653
+ {
3654
+ request: args.request,
3655
+ params: args.params,
3656
+ context: args.context
3657
+ },
3658
+ next
3659
+ );
3660
+ if (nextCalled) {
3661
+ if (result === void 0) {
3662
+ return nextResult;
3663
+ } else {
3664
+ return result;
3665
+ }
3666
+ } else {
3667
+ return next();
3668
+ }
3669
+ } catch (e) {
3670
+ if (e instanceof MiddlewareError) {
3671
+ throw e;
3672
+ }
3673
+ throw new MiddlewareError(routeId, e);
3674
+ }
3675
+ }
3676
+ async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, scopedContext, enableMiddleware) {
3341
3677
  let loadRouteDefinitionsPromises = matches.map(
3342
3678
  (m) => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties2, manifest) : void 0
3343
3679
  );
3680
+ if (enableMiddleware) {
3681
+ await Promise.all(loadRouteDefinitionsPromises);
3682
+ }
3344
3683
  let dsMatches = matches.map((match, i) => {
3345
3684
  let loadRoutePromise = loadRouteDefinitionsPromises[i];
3346
3685
  let shouldLoad = matchesToLoad.some((m) => m.route.id === match.route.id);
@@ -3354,7 +3693,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
3354
3693
  match,
3355
3694
  loadRoutePromise,
3356
3695
  handlerOverride,
3357
- requestContext
3696
+ scopedContext
3358
3697
  ) : Promise.resolve({ type: "data" /* data */, result: void 0 });
3359
3698
  };
3360
3699
  return {
@@ -3368,7 +3707,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
3368
3707
  request,
3369
3708
  params: matches[0].params,
3370
3709
  fetcherKey,
3371
- context: requestContext
3710
+ context: scopedContext
3372
3711
  });
3373
3712
  try {
3374
3713
  await Promise.all(loadRouteDefinitionsPromises);
@@ -3376,7 +3715,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
3376
3715
  }
3377
3716
  return results;
3378
3717
  }
3379
- async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
3718
+ async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, scopedContext) {
3380
3719
  let result;
3381
3720
  let onReject;
3382
3721
  let runHandler = (handler) => {
@@ -3396,7 +3735,7 @@ async function callLoaderOrAction(type, request, match, loadRoutePromise, handle
3396
3735
  {
3397
3736
  request,
3398
3737
  params: match.params,
3399
- context: staticContext
3738
+ context: scopedContext
3400
3739
  },
3401
3740
  ...ctx !== void 0 ? [ctx] : []
3402
3741
  );
@@ -4709,6 +5048,7 @@ function mapRouteProperties(route) {
4709
5048
  function createMemoryRouter(routes, opts) {
4710
5049
  return createRouter({
4711
5050
  basename: opts?.basename,
5051
+ unstable_getContext: opts?.unstable_getContext,
4712
5052
  future: opts?.future,
4713
5053
  history: createMemoryHistory({
4714
5054
  initialEntries: opts?.initialEntries,
@@ -5664,55 +6004,61 @@ function StreamTransfer({
5664
6004
  )));
5665
6005
  }
5666
6006
  }
5667
- function getSingleFetchDataStrategy(manifest, routeModules, ssr, getRouter) {
5668
- return async ({ request, matches, fetcherKey }) => {
6007
+ function getSingleFetchDataStrategy(manifest, routeModules, ssr, basename, getRouter) {
6008
+ return async (args) => {
6009
+ let { request, matches, fetcherKey } = args;
5669
6010
  if (request.method !== "GET") {
5670
- return singleFetchActionStrategy(request, matches);
6011
+ return runMiddlewarePipeline(
6012
+ args,
6013
+ false,
6014
+ () => singleFetchActionStrategy(request, matches, basename),
6015
+ (e) => ({ [e.routeId]: { type: "error", result: e.error } })
6016
+ );
5671
6017
  }
5672
6018
  if (!ssr) {
5673
6019
  let foundRevalidatingServerLoader = matches.some(
5674
6020
  (m) => m.shouldLoad && manifest.routes[m.route.id]?.hasLoader && !manifest.routes[m.route.id]?.hasClientLoader
5675
6021
  );
5676
6022
  if (!foundRevalidatingServerLoader) {
5677
- let matchesToLoad = matches.filter((m) => m.shouldLoad);
5678
- let url = stripIndexParam(singleFetchUrl(request.url));
5679
- let init = await createRequestInit(request);
5680
- let results = {};
5681
- await Promise.all(
5682
- matchesToLoad.map(
5683
- (m) => m.resolve(async (handler) => {
5684
- try {
5685
- let result = manifest.routes[m.route.id]?.hasClientLoader ? await fetchSingleLoader(handler, url, init, m.route.id) : await handler();
5686
- results[m.route.id] = { type: "data", result };
5687
- } catch (e) {
5688
- results[m.route.id] = { type: "error", result: e };
5689
- }
5690
- })
5691
- )
6023
+ return runMiddlewarePipeline(
6024
+ args,
6025
+ false,
6026
+ () => nonSsrStrategy(manifest, request, matches, basename),
6027
+ (e) => ({ [e.routeId]: { type: "error", result: e.error } })
5692
6028
  );
5693
- return results;
5694
6029
  }
5695
6030
  }
5696
6031
  if (fetcherKey) {
5697
- return singleFetchLoaderFetcherStrategy(request, matches);
6032
+ return runMiddlewarePipeline(
6033
+ args,
6034
+ false,
6035
+ () => singleFetchLoaderFetcherStrategy(request, matches, basename),
6036
+ (e) => ({ [e.routeId]: { type: "error", result: e.error } })
6037
+ );
5698
6038
  }
5699
- return singleFetchLoaderNavigationStrategy(
5700
- manifest,
5701
- routeModules,
5702
- ssr,
5703
- getRouter(),
5704
- request,
5705
- matches
6039
+ return runMiddlewarePipeline(
6040
+ args,
6041
+ false,
6042
+ () => singleFetchLoaderNavigationStrategy(
6043
+ manifest,
6044
+ routeModules,
6045
+ ssr,
6046
+ getRouter(),
6047
+ request,
6048
+ matches,
6049
+ basename
6050
+ ),
6051
+ (e) => ({ [e.routeId]: { type: "error", result: e.error } })
5706
6052
  );
5707
6053
  };
5708
6054
  }
5709
- async function singleFetchActionStrategy(request, matches) {
6055
+ async function singleFetchActionStrategy(request, matches, basename) {
5710
6056
  let actionMatch = matches.find((m) => m.shouldLoad);
5711
6057
  invariant2(actionMatch, "No action match found");
5712
6058
  let actionStatus = void 0;
5713
6059
  let result = await actionMatch.resolve(async (handler) => {
5714
6060
  let result2 = await handler(async () => {
5715
- let url = singleFetchUrl(request.url);
6061
+ let url = singleFetchUrl(request.url, basename);
5716
6062
  let init = await createRequestInit(request);
5717
6063
  let { data: data2, status } = await fetchAndDecode(url, init);
5718
6064
  actionStatus = status;
@@ -5733,13 +6079,35 @@ async function singleFetchActionStrategy(request, matches) {
5733
6079
  }
5734
6080
  };
5735
6081
  }
5736
- async function singleFetchLoaderNavigationStrategy(manifest, routeModules, ssr, router, request, matches) {
6082
+ async function nonSsrStrategy(manifest, request, matches, basename) {
6083
+ let matchesToLoad = matches.filter((m) => m.shouldLoad);
6084
+ let url = stripIndexParam(singleFetchUrl(request.url, basename));
6085
+ let init = await createRequestInit(request);
6086
+ let results = {};
6087
+ await Promise.all(
6088
+ matchesToLoad.map(
6089
+ (m) => m.resolve(async (handler) => {
6090
+ try {
6091
+ let result = manifest.routes[m.route.id]?.hasClientLoader ? await fetchSingleLoader(handler, url, init, m.route.id) : await handler();
6092
+ results[m.route.id] = { type: "data", result };
6093
+ } catch (e) {
6094
+ results[m.route.id] = { type: "error", result: e };
6095
+ }
6096
+ })
6097
+ )
6098
+ );
6099
+ return results;
6100
+ }
6101
+ function isOptedOut(manifestRoute, routeModule, match, router) {
6102
+ return match.route.id in router.state.loaderData && manifestRoute && manifestRoute.hasLoader && routeModule && routeModule.shouldRevalidate;
6103
+ }
6104
+ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, ssr, router, request, matches, basename) {
5737
6105
  let routesParams = /* @__PURE__ */ new Set();
5738
6106
  let foundOptOutRoute = false;
5739
6107
  let routeDfds = matches.map(() => createDeferred2());
5740
6108
  let routesLoadedPromise = Promise.all(routeDfds.map((d) => d.promise));
5741
6109
  let singleFetchDfd = createDeferred2();
5742
- let url = stripIndexParam(singleFetchUrl(request.url));
6110
+ let url = stripIndexParam(singleFetchUrl(request.url, basename));
5743
6111
  let init = await createRequestInit(request);
5744
6112
  let results = {};
5745
6113
  let resolvePromise = Promise.all(
@@ -5751,7 +6119,7 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, ssr,
5751
6119
  if (!router.state.initialized) {
5752
6120
  return;
5753
6121
  }
5754
- if (m.route.id in router.state.loaderData && manifestRoute && manifestRoute.hasLoader && routeModules[m.route.id]?.shouldRevalidate) {
6122
+ if (isOptedOut(manifestRoute, routeModules[m.route.id], m, router)) {
5755
6123
  foundOptOutRoute = true;
5756
6124
  return;
5757
6125
  }
@@ -5814,11 +6182,11 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, ssr,
5814
6182
  await resolvePromise;
5815
6183
  return results;
5816
6184
  }
5817
- async function singleFetchLoaderFetcherStrategy(request, matches) {
6185
+ async function singleFetchLoaderFetcherStrategy(request, matches, basename) {
5818
6186
  let fetcherMatch = matches.find((m) => m.shouldLoad);
5819
6187
  invariant2(fetcherMatch, "No fetcher match found");
5820
6188
  let result = await fetcherMatch.resolve(async (handler) => {
5821
- let url = stripIndexParam(singleFetchUrl(request.url));
6189
+ let url = stripIndexParam(singleFetchUrl(request.url, basename));
5822
6190
  let init = await createRequestInit(request);
5823
6191
  return fetchSingleLoader(handler, url, init, fetcherMatch.route.id);
5824
6192
  });
@@ -5846,7 +6214,7 @@ function stripIndexParam(url) {
5846
6214
  }
5847
6215
  return url;
5848
6216
  }
5849
- function singleFetchUrl(reqUrl) {
6217
+ function singleFetchUrl(reqUrl, basename) {
5850
6218
  let url = typeof reqUrl === "string" ? new URL(
5851
6219
  reqUrl,
5852
6220
  // This can be called during the SSR flow via PrefetchPageLinksImpl so
@@ -5855,6 +6223,8 @@ function singleFetchUrl(reqUrl) {
5855
6223
  ) : reqUrl;
5856
6224
  if (url.pathname === "/") {
5857
6225
  url.pathname = "_root.data";
6226
+ } else if (basename && stripBasename(url.pathname, basename) === "/") {
6227
+ url.pathname = `${basename.replace(/\/$/, "")}/_root.data`;
5858
6228
  } else {
5859
6229
  url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
5860
6230
  }
@@ -6151,8 +6521,8 @@ function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId
6151
6521
  // render, so just give it a no-op function so we can render down to the
6152
6522
  // proper fallback
6153
6523
  loader: route.hasLoader || route.hasClientLoader ? () => null : void 0
6154
- // We don't need action/shouldRevalidate on these routes since they're
6155
- // for a static render
6524
+ // We don't need middleware/action/shouldRevalidate on these routes since
6525
+ // they're for a static render
6156
6526
  };
6157
6527
  let children = createServerRoutes(
6158
6528
  manifest,
@@ -6246,6 +6616,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6246
6616
  Object.assign(dataRoute, {
6247
6617
  ...dataRoute,
6248
6618
  ...getRouteComponents(route, routeModule, isSpaMode),
6619
+ unstable_middleware: routeModule.unstable_clientMiddleware,
6249
6620
  handle: routeModule.handle,
6250
6621
  shouldRevalidate: getShouldRevalidateFunction(
6251
6622
  routeModule,
@@ -6259,7 +6630,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6259
6630
  let hasInitialError = initialState && initialState.errors && route.id in initialState.errors;
6260
6631
  let initialError = hasInitialError ? initialState?.errors?.[route.id] : void 0;
6261
6632
  let isHydrationRequest = needsRevalidation == null && (routeModule.clientLoader?.hydrate === true || !route.hasLoader);
6262
- dataRoute.loader = async ({ request, params }, singleFetch) => {
6633
+ dataRoute.loader = async ({ request, params, context }, singleFetch) => {
6263
6634
  try {
6264
6635
  let result = await prefetchStylesAndCallHandler(async () => {
6265
6636
  invariant2(
@@ -6272,6 +6643,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6272
6643
  return routeModule.clientLoader({
6273
6644
  request,
6274
6645
  params,
6646
+ context,
6275
6647
  async serverLoader() {
6276
6648
  preventInvalidServerHandlerCall("loader", route);
6277
6649
  if (isHydrationRequest) {
@@ -6296,7 +6668,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6296
6668
  routeModule,
6297
6669
  isSpaMode
6298
6670
  );
6299
- dataRoute.action = ({ request, params }, singleFetch) => {
6671
+ dataRoute.action = ({ request, params, context }, singleFetch) => {
6300
6672
  return prefetchStylesAndCallHandler(async () => {
6301
6673
  invariant2(
6302
6674
  routeModule,
@@ -6311,6 +6683,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6311
6683
  return routeModule.clientAction({
6312
6684
  request,
6313
6685
  params,
6686
+ context,
6314
6687
  async serverAction() {
6315
6688
  preventInvalidServerHandlerCall("action", route);
6316
6689
  return fetchServerAction(singleFetch);
@@ -6320,7 +6693,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6320
6693
  };
6321
6694
  } else {
6322
6695
  if (!route.hasClientLoader) {
6323
- dataRoute.loader = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6696
+ dataRoute.loader = (_, singleFetch) => prefetchStylesAndCallHandler(() => {
6324
6697
  return fetchServerLoader(singleFetch);
6325
6698
  });
6326
6699
  } else if (route.clientLoaderModule) {
@@ -6341,7 +6714,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6341
6714
  };
6342
6715
  }
6343
6716
  if (!route.hasClientAction) {
6344
- dataRoute.action = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6717
+ dataRoute.action = (_, singleFetch) => prefetchStylesAndCallHandler(() => {
6345
6718
  if (isSpaMode) {
6346
6719
  throw noActionDefinedError("clientAction", route.id);
6347
6720
  }
@@ -6399,6 +6772,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSp
6399
6772
  return {
6400
6773
  ...lazyRoute.loader ? { loader: lazyRoute.loader } : {},
6401
6774
  ...lazyRoute.action ? { action: lazyRoute.action } : {},
6775
+ unstable_middleware: mod.unstable_clientMiddleware,
6402
6776
  hasErrorBoundary: lazyRoute.hasErrorBoundary,
6403
6777
  shouldRevalidate: getShouldRevalidateFunction(
6404
6778
  lazyRoute,
@@ -6471,6 +6845,7 @@ async function loadRouteModuleWithBlockingLinks(route, routeModules) {
6471
6845
  return {
6472
6846
  Component: getRouteModuleComponent(routeModule),
6473
6847
  ErrorBoundary: routeModule.ErrorBoundary,
6848
+ unstable_clientMiddleware: routeModule.unstable_clientMiddleware,
6474
6849
  clientAction: routeModule.clientAction,
6475
6850
  clientLoader: routeModule.clientLoader,
6476
6851
  handle: routeModule.handle,
@@ -6526,12 +6901,13 @@ function getPatchRoutesOnNavigationFunction(manifest, routeModules, ssr, isSpaMo
6526
6901
  if (!isFogOfWarEnabled(ssr)) {
6527
6902
  return void 0;
6528
6903
  }
6529
- return async ({ path, patch, signal }) => {
6904
+ return async ({ path, patch, signal, fetcherKey }) => {
6530
6905
  if (discoveredPaths.has(path)) {
6531
6906
  return;
6532
6907
  }
6533
6908
  await fetchAndApplyManifestPatches(
6534
6909
  [path],
6910
+ fetcherKey ? window.location.href : path,
6535
6911
  manifest,
6536
6912
  routeModules,
6537
6913
  ssr,
@@ -6572,6 +6948,7 @@ function useFogOFWarDiscovery(router, manifest, routeModules, ssr, isSpaMode) {
6572
6948
  try {
6573
6949
  await fetchAndApplyManifestPatches(
6574
6950
  lazyPaths,
6951
+ null,
6575
6952
  manifest,
6576
6953
  routeModules,
6577
6954
  ssr,
@@ -6595,7 +6972,8 @@ function useFogOFWarDiscovery(router, manifest, routeModules, ssr, isSpaMode) {
6595
6972
  return () => observer.disconnect();
6596
6973
  }, [ssr, isSpaMode, manifest, routeModules, router]);
6597
6974
  }
6598
- async function fetchAndApplyManifestPatches(paths, manifest, routeModules, ssr, isSpaMode, basename, patchRoutes, signal) {
6975
+ var MANIFEST_VERSION_STORAGE_KEY = "react-router-manifest-version";
6976
+ async function fetchAndApplyManifestPatches(paths, errorReloadPath, manifest, routeModules, ssr, isSpaMode, basename, patchRoutes, signal) {
6599
6977
  let manifestPath = `${basename != null ? basename : "/"}/__manifest`.replace(
6600
6978
  /\/+/g,
6601
6979
  "/"
@@ -6612,9 +6990,26 @@ async function fetchAndApplyManifestPatches(paths, manifest, routeModules, ssr,
6612
6990
  let res = await fetch(url, { signal });
6613
6991
  if (!res.ok) {
6614
6992
  throw new Error(`${res.status} ${res.statusText}`);
6993
+ } else if (res.status === 204 && res.headers.has("X-Remix-Reload-Document")) {
6994
+ if (!errorReloadPath) {
6995
+ console.warn(
6996
+ "Detected a manifest version mismatch during eager route discovery. The next navigation/fetch to an undiscovered route will result in a new document navigation to sync up with the latest manifest."
6997
+ );
6998
+ return;
6999
+ }
7000
+ if (sessionStorage.getItem(MANIFEST_VERSION_STORAGE_KEY) === manifest.version) {
7001
+ console.error(
7002
+ "Unable to discover routes due to manifest version mismatch."
7003
+ );
7004
+ return;
7005
+ }
7006
+ sessionStorage.setItem(MANIFEST_VERSION_STORAGE_KEY, manifest.version);
7007
+ window.location.href = errorReloadPath;
7008
+ throw new Error("Detected manifest version mismatch, reloading...");
6615
7009
  } else if (res.status >= 400) {
6616
7010
  throw new Error(await res.text());
6617
7011
  }
7012
+ sessionStorage.removeItem(MANIFEST_VERSION_STORAGE_KEY);
6618
7013
  serverPatches = await res.json();
6619
7014
  } catch (e) {
6620
7015
  if (signal?.aborted) return;
@@ -6768,7 +7163,7 @@ function Links() {
6768
7163
  () => getKeyedLinksForMatches(matches, routeModules, manifest),
6769
7164
  [matches, routeModules, manifest]
6770
7165
  );
6771
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, criticalCss ? /* @__PURE__ */ React9.createElement("style", { dangerouslySetInnerHTML: { __html: criticalCss } }) : null, keyedLinks.map(
7166
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, typeof criticalCss === "string" ? /* @__PURE__ */ React9.createElement("style", { dangerouslySetInnerHTML: { __html: criticalCss } }) : null, typeof criticalCss === "object" ? /* @__PURE__ */ React9.createElement("link", { rel: "stylesheet", href: criticalCss.href }) : null, keyedLinks.map(
6772
7167
  ({ key, link }) => isPageLinkDescriptor(link) ? /* @__PURE__ */ React9.createElement(PrefetchPageLinks, { key, ...link }) : /* @__PURE__ */ React9.createElement("link", { key, ...link })
6773
7168
  ));
6774
7169
  }
@@ -6811,6 +7206,7 @@ function PrefetchPageLinksImpl({
6811
7206
  }) {
6812
7207
  let location = useLocation();
6813
7208
  let { manifest, routeModules } = useFrameworkContext();
7209
+ let { basename } = useDataRouterContext2();
6814
7210
  let { loaderData, matches } = useDataRouterStateContext();
6815
7211
  let newMatchesForData = React9.useMemo(
6816
7212
  () => getNewMatchesForLinks(
@@ -6856,7 +7252,7 @@ function PrefetchPageLinksImpl({
6856
7252
  if (routesParams.size === 0) {
6857
7253
  return [];
6858
7254
  }
6859
- let url = singleFetchUrl(page);
7255
+ let url = singleFetchUrl(page, basename);
6860
7256
  if (foundOptOutRoute && routesParams.size > 0) {
6861
7257
  url.searchParams.set(
6862
7258
  "_routes",
@@ -6865,6 +7261,7 @@ function PrefetchPageLinksImpl({
6865
7261
  }
6866
7262
  return [url.pathname + url.search];
6867
7263
  }, [
7264
+ basename,
6868
7265
  loaderData,
6869
7266
  location,
6870
7267
  manifest,
@@ -7118,13 +7515,14 @@ function mergeRefs(...refs) {
7118
7515
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
7119
7516
  try {
7120
7517
  if (isBrowser) {
7121
- window.__reactRouterVersion = "7.2.0";
7518
+ window.__reactRouterVersion = "7.3.0-pre.1";
7122
7519
  }
7123
7520
  } catch (e) {
7124
7521
  }
7125
7522
  function createBrowserRouter(routes, opts) {
7126
7523
  return createRouter({
7127
7524
  basename: opts?.basename,
7525
+ unstable_getContext: opts?.unstable_getContext,
7128
7526
  future: opts?.future,
7129
7527
  history: createBrowserHistory({ window: opts?.window }),
7130
7528
  hydrationData: opts?.hydrationData || parseHydrationData(),
@@ -7138,6 +7536,7 @@ function createBrowserRouter(routes, opts) {
7138
7536
  function createHashRouter(routes, opts) {
7139
7537
  return createRouter({
7140
7538
  basename: opts?.basename,
7539
+ unstable_getContext: opts?.unstable_getContext,
7141
7540
  future: opts?.future,
7142
7541
  history: createHashHistory({ window: opts?.window }),
7143
7542
  hydrationData: opts?.hydrationData || parseHydrationData(),
@@ -8096,6 +8495,7 @@ function createStaticRouter(routes, context, opts = {}) {
8096
8495
  },
8097
8496
  get future() {
8098
8497
  return {
8498
+ unstable_middleware: false,
8099
8499
  ...opts?.future
8100
8500
  };
8101
8501
  },
@@ -8258,7 +8658,7 @@ function ServerRouter({
8258
8658
 
8259
8659
  // lib/dom/ssr/routes-test-stub.tsx
8260
8660
  import * as React13 from "react";
8261
- function createRoutesStub(routes, context = {}) {
8661
+ function createRoutesStub(routes, unstable_getContext) {
8262
8662
  return function RoutesTestStub({
8263
8663
  initialEntries,
8264
8664
  initialIndex,
@@ -8269,7 +8669,9 @@ function createRoutesStub(routes, context = {}) {
8269
8669
  let remixContextRef = React13.useRef();
8270
8670
  if (routerRef.current == null) {
8271
8671
  remixContextRef.current = {
8272
- future: {},
8672
+ future: {
8673
+ unstable_middleware: future?.unstable_middleware === true
8674
+ },
8273
8675
  manifest: {
8274
8676
  routes: {},
8275
8677
  entry: { imports: [], module: "" },
@@ -8281,13 +8683,14 @@ function createRoutesStub(routes, context = {}) {
8281
8683
  isSpaMode: false
8282
8684
  };
8283
8685
  let patched = processRoutes(
8284
- // @ts-expect-error loader/action context types don't match :/
8686
+ // @ts-expect-error `StubRouteObject` is stricter about `loader`/`action`
8687
+ // types compared to `AgnosticRouteObject`
8285
8688
  convertRoutesToDataRoutes(routes, (r) => r),
8286
- context,
8287
8689
  remixContextRef.current.manifest,
8288
8690
  remixContextRef.current.routeModules
8289
8691
  );
8290
8692
  routerRef.current = createMemoryRouter(patched, {
8693
+ unstable_getContext,
8291
8694
  initialEntries,
8292
8695
  initialIndex,
8293
8696
  hydrationData
@@ -8296,14 +8699,13 @@ function createRoutesStub(routes, context = {}) {
8296
8699
  return /* @__PURE__ */ React13.createElement(FrameworkContext.Provider, { value: remixContextRef.current }, /* @__PURE__ */ React13.createElement(RouterProvider, { router: routerRef.current }));
8297
8700
  };
8298
8701
  }
8299
- function processRoutes(routes, context, manifest, routeModules, parentId) {
8702
+ function processRoutes(routes, manifest, routeModules, parentId) {
8300
8703
  return routes.map((route) => {
8301
8704
  if (!route.id) {
8302
8705
  throw new Error(
8303
8706
  "Expected a route.id in @remix-run/testing processRoutes() function"
8304
8707
  );
8305
8708
  }
8306
- let { loader, action } = route;
8307
8709
  let newRoute = {
8308
8710
  id: route.id,
8309
8711
  path: route.path,
@@ -8311,8 +8713,8 @@ function processRoutes(routes, context, manifest, routeModules, parentId) {
8311
8713
  Component: route.Component,
8312
8714
  HydrateFallback: route.HydrateFallback,
8313
8715
  ErrorBoundary: route.ErrorBoundary,
8314
- action: action ? (args) => action({ ...args, context }) : void 0,
8315
- loader: loader ? (args) => loader({ ...args, context }) : void 0,
8716
+ action: route.action,
8717
+ loader: route.loader,
8316
8718
  handle: route.handle,
8317
8719
  shouldRevalidate: route.shouldRevalidate
8318
8720
  };
@@ -8347,7 +8749,6 @@ function processRoutes(routes, context, manifest, routeModules, parentId) {
8347
8749
  if (route.children) {
8348
8750
  newRoute.children = processRoutes(
8349
8751
  route.children,
8350
- context,
8351
8752
  manifest,
8352
8753
  routeModules,
8353
8754
  newRoute.id
@@ -8708,6 +9109,7 @@ function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesBy
8708
9109
  hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
8709
9110
  id: route.id,
8710
9111
  path: route.path,
9112
+ unstable_middleware: route.module.unstable_middleware,
8711
9113
  // Need to use RR's version in the param typed here to permit the optional
8712
9114
  // context even though we know it'll always be provided in remix
8713
9115
  loader: route.module.loader ? async (args) => {
@@ -8853,27 +9255,46 @@ function prependCookies(parentHeaders, childHeaders) {
8853
9255
  }
8854
9256
 
8855
9257
  // lib/server-runtime/single-fetch.ts
9258
+ var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([100, 101, 204, 205, 304]);
8856
9259
  var SINGLE_FETCH_REDIRECT_STATUS = 202;
8857
- function getSingleFetchDataStrategy2({
8858
- isActionDataRequest,
8859
- loadRouteIds
8860
- } = {}) {
8861
- return async ({ request, matches }) => {
8862
- if (isActionDataRequest && request.method === "GET") {
8863
- return {};
8864
- }
8865
- let matchesToLoad = loadRouteIds ? matches.filter((m) => loadRouteIds.includes(m.route.id)) : matches;
8866
- let results = await Promise.all(
8867
- matchesToLoad.map((match) => match.resolve())
8868
- );
8869
- return results.reduce(
8870
- (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
8871
- {}
8872
- );
8873
- };
8874
- }
8875
9260
  async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8876
9261
  try {
9262
+ let respond2 = function(context) {
9263
+ let headers = getDocumentHeaders(build, context);
9264
+ if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
9265
+ return generateSingleFetchResponse(request, build, serverMode, {
9266
+ result: getSingleFetchRedirect(
9267
+ context.statusCode,
9268
+ headers,
9269
+ build.basename
9270
+ ),
9271
+ headers,
9272
+ status: SINGLE_FETCH_REDIRECT_STATUS
9273
+ });
9274
+ }
9275
+ if (context.errors) {
9276
+ Object.values(context.errors).forEach((err) => {
9277
+ if (!isRouteErrorResponse(err) || err.error) {
9278
+ handleError(err);
9279
+ }
9280
+ });
9281
+ context.errors = sanitizeErrors(context.errors, serverMode);
9282
+ }
9283
+ let singleFetchResult;
9284
+ if (context.errors) {
9285
+ singleFetchResult = { error: Object.values(context.errors)[0] };
9286
+ } else {
9287
+ singleFetchResult = {
9288
+ data: Object.values(context.actionData || {})[0]
9289
+ };
9290
+ }
9291
+ return generateSingleFetchResponse(request, build, serverMode, {
9292
+ result: singleFetchResult,
9293
+ headers,
9294
+ status: context.statusCode
9295
+ });
9296
+ };
9297
+ var respond = respond2;
8877
9298
  let handlerRequest = new Request(handlerUrl, {
8878
9299
  method: request.method,
8879
9300
  body: request.body,
@@ -8884,12 +9305,14 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
8884
9305
  let result = await staticHandler.query(handlerRequest, {
8885
9306
  requestContext: loadContext,
8886
9307
  skipLoaderErrorBubbling: true,
8887
- dataStrategy: getSingleFetchDataStrategy2({
8888
- isActionDataRequest: true
8889
- })
9308
+ skipRevalidation: true,
9309
+ unstable_respond: respond2
8890
9310
  });
8891
- if (isResponse(result)) {
8892
- return {
9311
+ if (!isResponse(result)) {
9312
+ result = respond2(result);
9313
+ }
9314
+ if (isRedirectResponse(result)) {
9315
+ return generateSingleFetchResponse(request, build, serverMode, {
8893
9316
  result: getSingleFetchRedirect(
8894
9317
  result.status,
8895
9318
  result.headers,
@@ -8897,65 +9320,83 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
8897
9320
  ),
8898
9321
  headers: result.headers,
8899
9322
  status: SINGLE_FETCH_REDIRECT_STATUS
8900
- };
8901
- }
8902
- let context = result;
8903
- let headers = getDocumentHeaders(build, context);
8904
- if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8905
- return {
8906
- result: getSingleFetchRedirect(
8907
- context.statusCode,
8908
- headers,
8909
- build.basename
8910
- ),
8911
- headers,
8912
- status: SINGLE_FETCH_REDIRECT_STATUS
8913
- };
8914
- }
8915
- if (context.errors) {
8916
- Object.values(context.errors).forEach((err) => {
8917
- if (!isRouteErrorResponse(err) || err.error) {
8918
- handleError(err);
8919
- }
8920
9323
  });
8921
- context.errors = sanitizeErrors(context.errors, serverMode);
8922
- }
8923
- let singleFetchResult;
8924
- if (context.errors) {
8925
- singleFetchResult = { error: Object.values(context.errors)[0] };
8926
- } else {
8927
- singleFetchResult = { data: Object.values(context.actionData || {})[0] };
8928
9324
  }
8929
- return {
8930
- result: singleFetchResult,
8931
- headers,
8932
- status: context.statusCode
8933
- };
9325
+ return result;
8934
9326
  } catch (error) {
8935
9327
  handleError(error);
8936
- return {
9328
+ return generateSingleFetchResponse(request, build, serverMode, {
8937
9329
  result: { error },
8938
9330
  headers: new Headers(),
8939
9331
  status: 500
8940
- };
9332
+ });
8941
9333
  }
8942
9334
  }
8943
9335
  async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8944
9336
  try {
9337
+ let respond2 = function(context) {
9338
+ let headers = getDocumentHeaders(build, context);
9339
+ if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
9340
+ return generateSingleFetchResponse(request, build, serverMode, {
9341
+ result: {
9342
+ [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
9343
+ context.statusCode,
9344
+ headers,
9345
+ build.basename
9346
+ )
9347
+ },
9348
+ headers,
9349
+ status: SINGLE_FETCH_REDIRECT_STATUS
9350
+ });
9351
+ }
9352
+ if (context.errors) {
9353
+ Object.values(context.errors).forEach((err) => {
9354
+ if (!isRouteErrorResponse(err) || err.error) {
9355
+ handleError(err);
9356
+ }
9357
+ });
9358
+ context.errors = sanitizeErrors(context.errors, serverMode);
9359
+ }
9360
+ let results = {};
9361
+ let loadedMatches = new Set(
9362
+ context.matches.filter(
9363
+ (m) => loadRouteIds ? loadRouteIds.has(m.route.id) : m.route.loader != null
9364
+ ).map((m) => m.route.id)
9365
+ );
9366
+ if (context.errors) {
9367
+ for (let [id, error] of Object.entries(context.errors)) {
9368
+ results[id] = { error };
9369
+ }
9370
+ }
9371
+ for (let [id, data2] of Object.entries(context.loaderData)) {
9372
+ if (!(id in results) && loadedMatches.has(id)) {
9373
+ results[id] = { data: data2 };
9374
+ }
9375
+ }
9376
+ return generateSingleFetchResponse(request, build, serverMode, {
9377
+ result: results,
9378
+ headers,
9379
+ status: context.statusCode
9380
+ });
9381
+ };
9382
+ var respond = respond2;
8945
9383
  let handlerRequest = new Request(handlerUrl, {
8946
9384
  headers: request.headers,
8947
9385
  signal: request.signal
8948
9386
  });
8949
- let loadRouteIds = new URL(request.url).searchParams.get("_routes")?.split(",") || void 0;
9387
+ let routesParam = new URL(request.url).searchParams.get("_routes");
9388
+ let loadRouteIds = routesParam ? new Set(routesParam.split(",")) : null;
8950
9389
  let result = await staticHandler.query(handlerRequest, {
8951
9390
  requestContext: loadContext,
9391
+ filterMatchesToLoad: (m) => !loadRouteIds || loadRouteIds.has(m.route.id),
8952
9392
  skipLoaderErrorBubbling: true,
8953
- dataStrategy: getSingleFetchDataStrategy2({
8954
- loadRouteIds
8955
- })
9393
+ unstable_respond: respond2
8956
9394
  });
8957
- if (isResponse(result)) {
8958
- return {
9395
+ if (!isResponse(result)) {
9396
+ result = respond2(result);
9397
+ }
9398
+ if (isRedirectResponse(result)) {
9399
+ return generateSingleFetchResponse(request, build, serverMode, {
8959
9400
  result: {
8960
9401
  [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8961
9402
  result.status,
@@ -8965,56 +9406,41 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, han
8965
9406
  },
8966
9407
  headers: result.headers,
8967
9408
  status: SINGLE_FETCH_REDIRECT_STATUS
8968
- };
8969
- }
8970
- let context = result;
8971
- let headers = getDocumentHeaders(build, context);
8972
- if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8973
- return {
8974
- result: {
8975
- [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8976
- context.statusCode,
8977
- headers,
8978
- build.basename
8979
- )
8980
- },
8981
- headers,
8982
- status: SINGLE_FETCH_REDIRECT_STATUS
8983
- };
8984
- }
8985
- if (context.errors) {
8986
- Object.values(context.errors).forEach((err) => {
8987
- if (!isRouteErrorResponse(err) || err.error) {
8988
- handleError(err);
8989
- }
8990
9409
  });
8991
- context.errors = sanitizeErrors(context.errors, serverMode);
8992
9410
  }
8993
- let results = {};
8994
- let loadedMatches = loadRouteIds ? context.matches.filter(
8995
- (m) => m.route.loader && loadRouteIds.includes(m.route.id)
8996
- ) : context.matches;
8997
- loadedMatches.forEach((m) => {
8998
- let { id } = m.route;
8999
- if (context.errors && context.errors.hasOwnProperty(id)) {
9000
- results[id] = { error: context.errors[id] };
9001
- } else if (context.loaderData.hasOwnProperty(id)) {
9002
- results[id] = { data: context.loaderData[id] };
9003
- }
9004
- });
9005
- return {
9006
- result: results,
9007
- headers,
9008
- status: context.statusCode
9009
- };
9411
+ return result;
9010
9412
  } catch (error) {
9011
9413
  handleError(error);
9012
- return {
9414
+ return generateSingleFetchResponse(request, build, serverMode, {
9013
9415
  result: { root: { error } },
9014
9416
  headers: new Headers(),
9015
9417
  status: 500
9016
- };
9418
+ });
9419
+ }
9420
+ }
9421
+ function generateSingleFetchResponse(request, build, serverMode, {
9422
+ result,
9423
+ headers,
9424
+ status
9425
+ }) {
9426
+ let resultHeaders = new Headers(headers);
9427
+ resultHeaders.set("X-Remix-Response", "yes");
9428
+ if (NO_BODY_STATUS_CODES.has(status)) {
9429
+ return new Response(null, { status, headers: resultHeaders });
9017
9430
  }
9431
+ resultHeaders.set("Content-Type", "text/x-script");
9432
+ return new Response(
9433
+ encodeViaTurboStream(
9434
+ result,
9435
+ request.signal,
9436
+ build.entry.module.streamTimeout,
9437
+ serverMode
9438
+ ),
9439
+ {
9440
+ status: status || 200,
9441
+ headers: resultHeaders
9442
+ }
9443
+ );
9018
9444
  }
9019
9445
  function getSingleFetchRedirect(status, headers, basename) {
9020
9446
  let redirect2 = headers.get("Location");
@@ -9077,7 +9503,6 @@ function encodeViaTurboStream(data2, requestSignal, streamTimeout, serverMode) {
9077
9503
  }
9078
9504
 
9079
9505
  // lib/server-runtime/server.ts
9080
- var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([100, 101, 204, 205, 304]);
9081
9506
  function derive(build, mode) {
9082
9507
  let routes = createRoutes(build.routes);
9083
9508
  let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
@@ -9107,8 +9532,11 @@ var createRequestHandler = (build, mode) => {
9107
9532
  let serverMode;
9108
9533
  let staticHandler;
9109
9534
  let errorHandler;
9110
- return async function requestHandler(request, loadContext = {}) {
9535
+ return async function requestHandler(request, initialContext) {
9111
9536
  _build = typeof build === "function" ? await build() : build;
9537
+ let loadContext = _build.future.unstable_middleware ? new unstable_RouterContextProvider(
9538
+ initialContext
9539
+ ) : initialContext || {};
9112
9540
  if (typeof build === "function") {
9113
9541
  let derived = derive(_build, mode);
9114
9542
  routes = derived.routes;
@@ -9123,8 +9551,14 @@ var createRequestHandler = (build, mode) => {
9123
9551
  errorHandler = derived.errorHandler;
9124
9552
  }
9125
9553
  let url = new URL(request.url);
9126
- let normalizedPath = url.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");
9127
- if (normalizedPath !== "/" && normalizedPath.endsWith("/")) {
9554
+ let normalizedBasename = _build.basename || "/";
9555
+ let normalizedPath = url.pathname;
9556
+ if (stripBasename(normalizedPath, normalizedBasename) === "/_root.data") {
9557
+ normalizedPath = normalizedBasename;
9558
+ } else if (normalizedPath.endsWith(".data")) {
9559
+ normalizedPath = normalizedPath.replace(/\.data$/, "");
9560
+ }
9561
+ if (stripBasename(normalizedPath, normalizedBasename) !== "/" && normalizedPath.endsWith("/")) {
9128
9562
  normalizedPath = normalizedPath.slice(0, -1);
9129
9563
  }
9130
9564
  let params = {};
@@ -9164,10 +9598,7 @@ var createRequestHandler = (build, mode) => {
9164
9598
  }
9165
9599
  }
9166
9600
  }
9167
- let manifestUrl = `${_build.basename ?? "/"}/__manifest`.replace(
9168
- /\/+/g,
9169
- "/"
9170
- );
9601
+ let manifestUrl = `${normalizedBasename}/__manifest`.replace(/\/+/g, "/");
9171
9602
  if (url.pathname === manifestUrl) {
9172
9603
  try {
9173
9604
  let res = await handleManifestRequest(_build, routes, url);
@@ -9232,9 +9663,10 @@ var createRequestHandler = (build, mode) => {
9232
9663
  );
9233
9664
  }
9234
9665
  }
9235
- } else if (matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
9666
+ } else if (!request.headers.has("X-React-Router-SPA-Mode") && matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
9236
9667
  response = await handleResourceRequest(
9237
9668
  serverMode,
9669
+ _build,
9238
9670
  staticHandler,
9239
9671
  matches.slice(-1)[0].route.id,
9240
9672
  request,
@@ -9242,7 +9674,13 @@ var createRequestHandler = (build, mode) => {
9242
9674
  handleError
9243
9675
  );
9244
9676
  } else {
9245
- let criticalCss = mode === "development" /* Development */ ? await getDevServerHooks()?.getCriticalCss?.(_build, url.pathname) : void 0;
9677
+ let { pathname } = url;
9678
+ let criticalCss = void 0;
9679
+ if (_build.getCriticalCss) {
9680
+ criticalCss = await _build.getCriticalCss({ pathname });
9681
+ } else if (mode === "development" /* Development */ && getDevServerHooks()?.getCriticalCss) {
9682
+ criticalCss = await getDevServerHooks()?.getCriticalCss?.(pathname);
9683
+ }
9246
9684
  response = await handleDocumentRequest(
9247
9685
  serverMode,
9248
9686
  _build,
@@ -9264,6 +9702,14 @@ var createRequestHandler = (build, mode) => {
9264
9702
  };
9265
9703
  };
9266
9704
  async function handleManifestRequest(build, routes, url) {
9705
+ if (build.assets.version !== url.searchParams.get("version")) {
9706
+ return new Response(null, {
9707
+ status: 204,
9708
+ headers: {
9709
+ "X-Remix-Reload-Document": "true"
9710
+ }
9711
+ });
9712
+ }
9267
9713
  let patches = {};
9268
9714
  if (url.searchParams.has("p")) {
9269
9715
  for (let path of url.searchParams.getAll("p")) {
@@ -9287,7 +9733,7 @@ async function handleManifestRequest(build, routes, url) {
9287
9733
  return new Response("Invalid Request", { status: 400 });
9288
9734
  }
9289
9735
  async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
9290
- let { result, headers, status } = request.method !== "GET" ? await singleFetchAction(
9736
+ let response = request.method !== "GET" ? await singleFetchAction(
9291
9737
  build,
9292
9738
  serverMode,
9293
9739
  staticHandler,
@@ -9304,133 +9750,66 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
9304
9750
  loadContext,
9305
9751
  handleError
9306
9752
  );
9307
- let resultHeaders = new Headers(headers);
9308
- resultHeaders.set("X-Remix-Response", "yes");
9309
- if (NO_BODY_STATUS_CODES.has(status)) {
9310
- return new Response(null, { status, headers: resultHeaders });
9311
- }
9312
- resultHeaders.set("Content-Type", "text/x-script");
9313
- return new Response(
9314
- encodeViaTurboStream(
9315
- result,
9316
- request.signal,
9317
- build.entry.module.streamTimeout,
9318
- serverMode
9319
- ),
9320
- {
9321
- status: status || 200,
9322
- headers: resultHeaders
9323
- }
9324
- );
9753
+ return response;
9325
9754
  }
9326
9755
  async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
9327
9756
  let isSpaMode = request.headers.has("X-React-Router-SPA-Mode");
9328
- let context;
9329
9757
  try {
9330
- context = await staticHandler.query(request, {
9331
- requestContext: loadContext
9758
+ let response = await staticHandler.query(request, {
9759
+ requestContext: loadContext,
9760
+ unstable_respond: build.future.unstable_middleware ? (ctx) => renderHtml(ctx, isSpaMode) : void 0
9332
9761
  });
9762
+ return isResponse(response) ? response : renderHtml(response, isSpaMode);
9333
9763
  } catch (error) {
9334
9764
  handleError(error);
9335
9765
  return new Response(null, { status: 500 });
9336
9766
  }
9337
- if (isResponse(context)) {
9338
- return context;
9339
- }
9340
- let headers = getDocumentHeaders(build, context);
9341
- if (NO_BODY_STATUS_CODES.has(context.statusCode)) {
9342
- return new Response(null, { status: context.statusCode, headers });
9343
- }
9344
- if (context.errors) {
9345
- Object.values(context.errors).forEach((err) => {
9346
- if (!isRouteErrorResponse(err) || err.error) {
9347
- handleError(err);
9348
- }
9349
- });
9350
- context.errors = sanitizeErrors(context.errors, serverMode);
9351
- }
9352
- let state = {
9353
- loaderData: context.loaderData,
9354
- actionData: context.actionData,
9355
- errors: serializeErrors2(context.errors, serverMode)
9356
- };
9357
- let entryContext = {
9358
- manifest: build.assets,
9359
- routeModules: createEntryRouteModules(build.routes),
9360
- staticHandlerContext: context,
9361
- criticalCss,
9362
- serverHandoffString: createServerHandoffString({
9363
- basename: build.basename,
9364
- criticalCss,
9365
- future: build.future,
9366
- ssr: build.ssr,
9367
- isSpaMode
9368
- }),
9369
- serverHandoffStream: encodeViaTurboStream(
9370
- state,
9371
- request.signal,
9372
- build.entry.module.streamTimeout,
9373
- serverMode
9374
- ),
9375
- renderMeta: {},
9376
- future: build.future,
9377
- ssr: build.ssr,
9378
- isSpaMode,
9379
- serializeError: (err) => serializeError(err, serverMode)
9380
- };
9381
- let handleDocumentRequestFunction = build.entry.module.default;
9382
- try {
9383
- return await handleDocumentRequestFunction(
9384
- request,
9385
- context.statusCode,
9386
- headers,
9387
- entryContext,
9388
- loadContext
9389
- );
9390
- } catch (error) {
9391
- handleError(error);
9392
- let errorForSecondRender = error;
9393
- if (isResponse(error)) {
9394
- try {
9395
- let data2 = await unwrapResponse(error);
9396
- errorForSecondRender = new ErrorResponseImpl(
9397
- error.status,
9398
- error.statusText,
9399
- data2
9400
- );
9401
- } catch (e) {
9402
- }
9767
+ async function renderHtml(context, isSpaMode2) {
9768
+ if (isResponse(context)) {
9769
+ return context;
9770
+ }
9771
+ let headers = getDocumentHeaders(build, context);
9772
+ if (NO_BODY_STATUS_CODES.has(context.statusCode)) {
9773
+ return new Response(null, { status: context.statusCode, headers });
9403
9774
  }
9404
- context = getStaticContextFromError(
9405
- staticHandler.dataRoutes,
9406
- context,
9407
- errorForSecondRender
9408
- );
9409
9775
  if (context.errors) {
9776
+ Object.values(context.errors).forEach((err) => {
9777
+ if (!isRouteErrorResponse(err) || err.error) {
9778
+ handleError(err);
9779
+ }
9780
+ });
9410
9781
  context.errors = sanitizeErrors(context.errors, serverMode);
9411
9782
  }
9412
- let state2 = {
9783
+ let state = {
9413
9784
  loaderData: context.loaderData,
9414
9785
  actionData: context.actionData,
9415
9786
  errors: serializeErrors2(context.errors, serverMode)
9416
9787
  };
9417
- entryContext = {
9418
- ...entryContext,
9788
+ let entryContext = {
9789
+ manifest: build.assets,
9790
+ routeModules: createEntryRouteModules(build.routes),
9419
9791
  staticHandlerContext: context,
9792
+ criticalCss,
9420
9793
  serverHandoffString: createServerHandoffString({
9421
9794
  basename: build.basename,
9795
+ criticalCss,
9422
9796
  future: build.future,
9423
9797
  ssr: build.ssr,
9424
- isSpaMode
9798
+ isSpaMode: isSpaMode2
9425
9799
  }),
9426
9800
  serverHandoffStream: encodeViaTurboStream(
9427
- state2,
9801
+ state,
9428
9802
  request.signal,
9429
9803
  build.entry.module.streamTimeout,
9430
9804
  serverMode
9431
9805
  ),
9432
- renderMeta: {}
9806
+ renderMeta: {},
9807
+ future: build.future,
9808
+ ssr: build.ssr,
9809
+ isSpaMode: isSpaMode2,
9810
+ serializeError: (err) => serializeError(err, serverMode)
9433
9811
  };
9812
+ let handleDocumentRequestFunction = build.entry.module.default;
9434
9813
  try {
9435
9814
  return await handleDocumentRequestFunction(
9436
9815
  request,
@@ -9439,17 +9818,71 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
9439
9818
  entryContext,
9440
9819
  loadContext
9441
9820
  );
9442
- } catch (error2) {
9443
- handleError(error2);
9444
- return returnLastResortErrorResponse(error2, serverMode);
9821
+ } catch (error) {
9822
+ handleError(error);
9823
+ let errorForSecondRender = error;
9824
+ if (isResponse(error)) {
9825
+ try {
9826
+ let data2 = await unwrapResponse(error);
9827
+ errorForSecondRender = new ErrorResponseImpl(
9828
+ error.status,
9829
+ error.statusText,
9830
+ data2
9831
+ );
9832
+ } catch (e) {
9833
+ }
9834
+ }
9835
+ context = getStaticContextFromError(
9836
+ staticHandler.dataRoutes,
9837
+ context,
9838
+ errorForSecondRender
9839
+ );
9840
+ if (context.errors) {
9841
+ context.errors = sanitizeErrors(context.errors, serverMode);
9842
+ }
9843
+ let state2 = {
9844
+ loaderData: context.loaderData,
9845
+ actionData: context.actionData,
9846
+ errors: serializeErrors2(context.errors, serverMode)
9847
+ };
9848
+ entryContext = {
9849
+ ...entryContext,
9850
+ staticHandlerContext: context,
9851
+ serverHandoffString: createServerHandoffString({
9852
+ basename: build.basename,
9853
+ future: build.future,
9854
+ ssr: build.ssr,
9855
+ isSpaMode: isSpaMode2
9856
+ }),
9857
+ serverHandoffStream: encodeViaTurboStream(
9858
+ state2,
9859
+ request.signal,
9860
+ build.entry.module.streamTimeout,
9861
+ serverMode
9862
+ ),
9863
+ renderMeta: {}
9864
+ };
9865
+ try {
9866
+ return await handleDocumentRequestFunction(
9867
+ request,
9868
+ context.statusCode,
9869
+ headers,
9870
+ entryContext,
9871
+ loadContext
9872
+ );
9873
+ } catch (error2) {
9874
+ handleError(error2);
9875
+ return returnLastResortErrorResponse(error2, serverMode);
9876
+ }
9445
9877
  }
9446
9878
  }
9447
9879
  }
9448
- async function handleResourceRequest(serverMode, staticHandler, routeId, request, loadContext, handleError) {
9880
+ async function handleResourceRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
9449
9881
  try {
9450
9882
  let response = await staticHandler.queryRoute(request, {
9451
9883
  routeId,
9452
- requestContext: loadContext
9884
+ requestContext: loadContext,
9885
+ unstable_respond: build.future.unstable_middleware ? (ctx) => ctx : void 0
9453
9886
  });
9454
9887
  if (isResponse(response)) {
9455
9888
  return response;
@@ -9469,6 +9902,13 @@ async function handleResourceRequest(serverMode, staticHandler, routeId, request
9469
9902
  }
9470
9903
  return errorResponseToJson(error, serverMode);
9471
9904
  }
9905
+ if (error instanceof Error && error.message === "Expected a response from queryRoute") {
9906
+ let newError = new Error(
9907
+ "Expected a Response to be returned from resource route handler"
9908
+ );
9909
+ handleError(newError);
9910
+ return returnLastResortErrorResponse(newError, serverMode);
9911
+ }
9472
9912
  handleError(error);
9473
9913
  return returnLastResortErrorResponse(error, serverMode);
9474
9914
  }
@@ -9709,6 +10149,8 @@ export {
9709
10149
  invariant,
9710
10150
  createPath,
9711
10151
  parsePath,
10152
+ unstable_createContext,
10153
+ unstable_RouterContextProvider,
9712
10154
  matchRoutes,
9713
10155
  generatePath,
9714
10156
  matchPath,