react-router 0.0.0-experimental-8c9575952 → 0.0.0-experimental-e7eb25a7b

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 (31) hide show
  1. package/dist/development/{browser-BhRqpkqg.d.mts → browser-BM9EKN98.d.mts} +2 -2
  2. package/dist/development/{chunk-4SZKM7GJ.mjs → chunk-SHQJZRZ7.mjs} +127 -36
  3. package/dist/development/dom-export.d.mts +1 -1
  4. package/dist/development/dom-export.js +1 -1
  5. package/dist/development/dom-export.mjs +2 -2
  6. package/dist/development/index.d.mts +2 -2
  7. package/dist/development/index.d.ts +2 -2
  8. package/dist/development/index.js +127 -36
  9. package/dist/development/index.mjs +2 -2
  10. package/dist/development/lib/types/internal.js +1 -1
  11. package/dist/development/lib/types/internal.mjs +1 -1
  12. package/dist/development/rsc-export.d.mts +0 -1
  13. package/dist/development/rsc-export.d.ts +0 -1
  14. package/dist/development/rsc-export.js +50 -31
  15. package/dist/development/rsc-export.mjs +50 -31
  16. package/dist/production/{browser-BhRqpkqg.d.mts → browser-BM9EKN98.d.mts} +2 -2
  17. package/dist/production/{chunk-ZPFN2BUI.mjs → chunk-VMGK4BUZ.mjs} +127 -36
  18. package/dist/production/dom-export.d.mts +1 -1
  19. package/dist/production/dom-export.js +1 -1
  20. package/dist/production/dom-export.mjs +2 -2
  21. package/dist/production/index.d.mts +2 -2
  22. package/dist/production/index.d.ts +2 -2
  23. package/dist/production/index.js +127 -36
  24. package/dist/production/index.mjs +2 -2
  25. package/dist/production/lib/types/internal.js +1 -1
  26. package/dist/production/lib/types/internal.mjs +1 -1
  27. package/dist/production/rsc-export.d.mts +0 -1
  28. package/dist/production/rsc-export.d.ts +0 -1
  29. package/dist/production/rsc-export.js +50 -31
  30. package/dist/production/rsc-export.mjs +50 -31
  31. package/package.json +1 -1
@@ -2170,7 +2170,6 @@ type ServerRenderPayload = {
2170
2170
  };
2171
2171
  type ServerManifestPayload = {
2172
2172
  type: "manifest";
2173
- matches: RenderedRoute[];
2174
2173
  patches: RenderedRoute[];
2175
2174
  };
2176
2175
  type ServerActionPayload = {
@@ -2200,9 +2199,10 @@ declare function createCallServer({ decode, encodeAction, }: {
2200
2199
  decode: DecodeServerResponseFunction;
2201
2200
  encodeAction: EncodeActionFunction;
2202
2201
  }): (id: string, args: unknown[]) => Promise<unknown>;
2203
- declare function RSCHydratedRouter({ decode, payload, }: {
2202
+ declare function RSCHydratedRouter({ decode, payload, routeDiscovery, }: {
2204
2203
  decode: DecodeServerResponseFunction;
2205
2204
  payload: ServerPayload;
2205
+ routeDiscovery?: "eager" | "lazy";
2206
2206
  }): React.JSX.Element;
2207
2207
 
2208
2208
  declare global {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -7197,7 +7197,7 @@ function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules
7197
7197
  );
7198
7198
  return async (args) => args.unstable_runClientMiddleware(dataStrategy);
7199
7199
  }
7200
- function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename) {
7200
+ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7201
7201
  return async (args) => {
7202
7202
  let { request, matches, fetcherKey } = args;
7203
7203
  let router = getRouter();
@@ -7220,7 +7220,8 @@ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode,
7220
7220
  getRouteInfo,
7221
7221
  fetchAndDecode,
7222
7222
  ssr,
7223
- basename
7223
+ basename,
7224
+ shouldAllowOptOut
7224
7225
  );
7225
7226
  };
7226
7227
  }
@@ -7272,7 +7273,7 @@ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
7272
7273
  );
7273
7274
  return results;
7274
7275
  }
7275
- async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename) {
7276
+ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7276
7277
  let routesParams = /* @__PURE__ */ new Set();
7277
7278
  let foundOptOutRoute = false;
7278
7279
  let routeDfds = args.matches.map(() => createDeferred2());
@@ -7292,7 +7293,7 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
7292
7293
  hasShouldRevalidate === true);
7293
7294
  return;
7294
7295
  }
7295
- if (hasClientLoader) {
7296
+ if (shouldAllowOptOut(m) && hasClientLoader) {
7296
7297
  if (hasLoader) {
7297
7298
  foundOptOutRoute = true;
7298
7299
  }
@@ -8793,7 +8794,7 @@ function mergeRefs(...refs) {
8793
8794
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
8794
8795
  try {
8795
8796
  if (isBrowser) {
8796
- window.__reactRouterVersion = "0.0.0-experimental-8c9575952";
8797
+ window.__reactRouterVersion = "0.0.0-experimental-e7eb25a7b";
8797
8798
  }
8798
8799
  } catch (e) {
8799
8800
  }
@@ -11619,23 +11620,11 @@ function createRouterFromPayload({
11619
11620
  void 0,
11620
11621
  false
11621
11622
  ),
11622
- async patchRoutesOnNavigation({ patch, path, signal }) {
11623
- let response = await fetch(`${path}.manifest`, { signal });
11624
- if (!response.body || response.status < 200 || response.status >= 300) {
11625
- throw new Error("Unable to fetch new route matches from the server");
11626
- }
11627
- let payload2 = await decode2(response.body);
11628
- if (payload2.type !== "manifest") {
11629
- throw new Error("Failed to patch routes on navigation");
11630
- }
11631
- payload2.matches.forEach(
11632
- (match, i) => patch(payload2.matches[i - 1]?.id ?? null, [
11633
- createRouteFromServerManifest(match)
11634
- ])
11635
- );
11636
- payload2.patches.forEach((p) => {
11637
- patch(p.parentId ?? null, [createRouteFromServerManifest(p)]);
11638
- });
11623
+ async patchRoutesOnNavigation({ path, signal }) {
11624
+ if (discoveredPaths2.has(path)) {
11625
+ return;
11626
+ }
11627
+ await fetchAndApplyManifestPatches2([path], decode2, signal);
11639
11628
  },
11640
11629
  // FIXME: Pass `build.ssr` and `build.basename` into this function
11641
11630
  dataStrategy: getRSCSingleFetchDataStrategy(
@@ -11676,23 +11665,35 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, basename, decode2) {
11676
11665
  // pass map into fetchAndDecode so it can add payloads
11677
11666
  getFetchAndDecodeViaRSC(decode2),
11678
11667
  ssr,
11679
- basename
11668
+ basename,
11669
+ // If we don't have an element, we need to hit the server loader flow
11670
+ // regardless of whether the client loader calls `serverLoader` or not,
11671
+ // otherwise we'll have nothing to render.
11672
+ // TODO: Do we need to account for API routes? Do we need a
11673
+ // `match.hasComponent` flag?
11674
+ (match) => match.route.element != null
11680
11675
  );
11681
11676
  return async (args) => args.unstable_runClientMiddleware(async () => {
11682
11677
  let context = args.context;
11683
11678
  context.set(renderedRoutesContext, []);
11684
11679
  let results = await dataStrategy(args);
11685
- const renderedRouteById = new Map(
11686
- context.get(renderedRoutesContext).map((r) => [r.id, r])
11687
- );
11680
+ const renderedRoutesById = /* @__PURE__ */ new Map();
11681
+ for (const route of context.get(renderedRoutesContext)) {
11682
+ if (!renderedRoutesById.has(route.id)) {
11683
+ renderedRoutesById.set(route.id, []);
11684
+ }
11685
+ renderedRoutesById.get(route.id).push(route);
11686
+ }
11688
11687
  for (const match of args.matches) {
11689
- const rendered = renderedRouteById.get(match.route.id);
11690
- if (rendered) {
11691
- window.__router.patchRoutes(
11692
- rendered.parentId ?? null,
11693
- [createRouteFromServerManifest(rendered)],
11694
- true
11695
- );
11688
+ const renderedRoutes = renderedRoutesById.get(match.route.id);
11689
+ if (renderedRoutes) {
11690
+ for (const rendered of renderedRoutes) {
11691
+ window.__router.patchRoutes(
11692
+ rendered.parentId ?? null,
11693
+ [createRouteFromServerManifest(rendered)],
11694
+ true
11695
+ );
11696
+ }
11696
11697
  }
11697
11698
  }
11698
11699
  return results;
@@ -11751,7 +11752,8 @@ function getFetchAndDecodeViaRSC(decode2) {
11751
11752
  }
11752
11753
  function RSCHydratedRouter({
11753
11754
  decode: decode2,
11754
- payload
11755
+ payload,
11756
+ routeDiscovery = "eager"
11755
11757
  }) {
11756
11758
  if (payload.type !== "render") throw new Error("Invalid payload type");
11757
11759
  let router = React14.useMemo(
@@ -11765,6 +11767,49 @@ function RSCHydratedRouter({
11765
11767
  window.__router.initialize();
11766
11768
  }
11767
11769
  }, []);
11770
+ React14.useEffect(() => {
11771
+ if (routeDiscovery === "lazy" || // @ts-expect-error - TS doesn't know about this yet
11772
+ window.navigator?.connection?.saveData === true) {
11773
+ return;
11774
+ }
11775
+ function registerElement(el) {
11776
+ let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
11777
+ if (!path) {
11778
+ return;
11779
+ }
11780
+ let pathname = el.tagName === "A" ? el.pathname : new URL(path, window.location.origin).pathname;
11781
+ if (!discoveredPaths2.has(pathname)) {
11782
+ nextPaths2.add(pathname);
11783
+ }
11784
+ }
11785
+ async function fetchPatches() {
11786
+ document.querySelectorAll("a[data-discover], form[data-discover]").forEach(registerElement);
11787
+ let paths = Array.from(nextPaths2.keys()).filter((path) => {
11788
+ if (discoveredPaths2.has(path)) {
11789
+ nextPaths2.delete(path);
11790
+ return false;
11791
+ }
11792
+ return true;
11793
+ });
11794
+ if (paths.length === 0) {
11795
+ return;
11796
+ }
11797
+ try {
11798
+ await fetchAndApplyManifestPatches2(paths, decode2);
11799
+ } catch (e) {
11800
+ console.error("Failed to fetch manifest patches", e);
11801
+ }
11802
+ }
11803
+ let debouncedFetchPatches = debounce2(fetchPatches, 100);
11804
+ fetchPatches();
11805
+ let observer = new MutationObserver(() => debouncedFetchPatches());
11806
+ observer.observe(document.documentElement, {
11807
+ subtree: true,
11808
+ childList: true,
11809
+ attributes: true,
11810
+ attributeFilter: ["data-discover", "href", "action"]
11811
+ });
11812
+ }, [routeDiscovery, decode2]);
11768
11813
  const frameworkContext = {
11769
11814
  future: {
11770
11815
  // These flags have no runtime impact so can always be false. If we add
@@ -11794,7 +11839,12 @@ function createRouteFromServerManifest(match, payload) {
11794
11839
  let initialData = payload?.loaderData[match.id];
11795
11840
  let hasInitialError = payload?.errors && match.id in payload.errors;
11796
11841
  let initialError = payload?.errors?.[match.id];
11797
- let isHydrationRequest = match.clientLoader?.hydrate === true || !match.hasLoader;
11842
+ let isHydrationRequest = match.clientLoader?.hydrate === true || !match.hasLoader || // If we don't have an element, we need to hit the server loader flow
11843
+ // regardless of whether the client loader calls `serverLoader` or not,
11844
+ // otherwise we'll have nothing to render.
11845
+ // TODO: Do we need to account for API routes? Do we need a
11846
+ // `match.hasComponent` flag?
11847
+ !match.element;
11798
11848
  let dataRoute = {
11799
11849
  id: match.id,
11800
11850
  element: match.element,
@@ -11876,6 +11926,47 @@ function preventInvalidServerHandlerCall2(type, routeId, hasHandler) {
11876
11926
  throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
11877
11927
  }
11878
11928
  }
11929
+ var nextPaths2 = /* @__PURE__ */ new Set();
11930
+ var discoveredPathsMaxSize2 = 1e3;
11931
+ var discoveredPaths2 = /* @__PURE__ */ new Set();
11932
+ var URL_LIMIT2 = 7680;
11933
+ async function fetchAndApplyManifestPatches2(paths, decode2, signal) {
11934
+ let basename = (window.__router.basename ?? "").replace(/^\/|\/$/g, "");
11935
+ let url = new URL(`${basename}/.manifest`, window.location.origin);
11936
+ paths.sort().forEach((path) => url.searchParams.append("p", path));
11937
+ if (url.toString().length > URL_LIMIT2) {
11938
+ nextPaths2.clear();
11939
+ return;
11940
+ }
11941
+ let response = await fetch(url, { signal });
11942
+ if (!response.body || response.status < 200 || response.status >= 300) {
11943
+ throw new Error("Unable to fetch new route matches from the server");
11944
+ }
11945
+ let payload = await decode2(response.body);
11946
+ if (payload.type !== "manifest") {
11947
+ throw new Error("Failed to patch routes");
11948
+ }
11949
+ paths.forEach((p) => addToFifoQueue2(p, discoveredPaths2));
11950
+ payload.patches.forEach((p) => {
11951
+ window.__router.patchRoutes(p.parentId ?? null, [
11952
+ createRouteFromServerManifest(p)
11953
+ ]);
11954
+ });
11955
+ }
11956
+ function addToFifoQueue2(path, queue) {
11957
+ if (queue.size >= discoveredPathsMaxSize2) {
11958
+ let first = queue.values().next().value;
11959
+ queue.delete(first);
11960
+ }
11961
+ queue.add(path);
11962
+ }
11963
+ function debounce2(callback, wait) {
11964
+ let timeoutId;
11965
+ return (...args) => {
11966
+ window.clearTimeout(timeoutId);
11967
+ timeoutId = window.setTimeout(() => callback(...args), wait);
11968
+ };
11969
+ }
11879
11970
 
11880
11971
  // lib/rsc/server.ssr.tsx
11881
11972
  import * as React15 from "react";
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { R as RouterProviderProps$1 } from './browser-BhRqpkqg.mjs';
2
+ import { R as RouterProviderProps$1 } from './browser-BM9EKN98.mjs';
3
3
  import { R as RouterInit } from './route-data-B3YkvRuy.mjs';
4
4
 
5
5
  type RouterProviderProps = Omit<RouterProviderProps$1, "flushSync">;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -26,7 +26,7 @@ import {
26
26
  invariant,
27
27
  mapRouteProperties,
28
28
  useFogOFWarDiscovery
29
- } from "./chunk-4SZKM7GJ.mjs";
29
+ } from "./chunk-SHQJZRZ7.mjs";
30
30
 
31
31
  // lib/dom-export/dom-router-provider.tsx
32
32
  import * as React from "react";
@@ -1,7 +1,7 @@
1
1
  import { a as Router, b as RouteModules, D as DataStrategyFunction, L as Location, S as StaticHandlerContext, c as RouteObject, C as CreateStaticHandlerOptions$1, d as StaticHandler, F as FutureConfig, I as InitialEntry, H as HydrationState, e as IndexRouteObject, f as LoaderFunction, A as ActionFunction, M as MetaFunction, g as LinksFunction, N as NonIndexRouteObject, u as unstable_InitialContext, h as MiddlewareEnabled, i as AppLoadContext, E as Equal, j as RouterState, P as PatchRoutesOnNavigationFunction, k as DataRouteObject, l as ClientLoaderFunction, m as Path } from './route-data-B3YkvRuy.mjs';
2
2
  export { y as ActionFunctionArgs, B as Blocker, s as BlockerFunction, au as ClientActionFunction, av as ClientActionFunctionArgs, aw as ClientLoaderFunctionArgs, ap as DataRouteMatch, z as DataStrategyFunctionArgs, J as DataStrategyMatch, K as DataStrategyResult, Q as ErrorResponse, o as Fetcher, U as FormEncType, V as FormMethod, aE as Future, G as GetScrollPositionFunction, n as GetScrollRestorationKeyFunction, W as HTMLFormMethod, ax as HeadersArgs, ay as HeadersFunction, aC as HtmlLinkDescriptor, af as IDLE_BLOCKER, ae as IDLE_FETCHER, ad as IDLE_NAVIGATION, X as LazyRouteFunction, aD as LinkDescriptor, Y as LoaderFunctionArgs, az as MetaArgs, aA as MetaDescriptor, aq as NavigateOptions, p as Navigation, q as NavigationStates, aa as NavigationType, ar as Navigator, aB as PageLinkDescriptor, _ as ParamParseKey, $ as Params, as as PatchRoutesOnNavigationFunctionArgs, a0 as PathMatch, a1 as PathParam, a2 as PathPattern, a3 as RedirectFunction, r as RelativeRoutingType, x as RevalidationState, at as RouteMatch, w as RouterFetchOptions, R as RouterInit, v as RouterNavigateOptions, t as RouterSubscriber, a5 as ShouldRevalidateFunction, a6 as ShouldRevalidateFunctionArgs, T as To, a7 as UIMatch, aK as UNSAFE_DataRouterContext, aL as UNSAFE_DataRouterStateContext, O as UNSAFE_DataWithResponseInit, aJ as UNSAFE_ErrorResponseImpl, aM as UNSAFE_FetchersContext, aN as UNSAFE_LocationContext, aO as UNSAFE_NavigationContext, aP as UNSAFE_RouteContext, aQ as UNSAFE_ViewTransitionContext, aG as UNSAFE_createBrowserHistory, aI as UNSAFE_createRouter, aH as UNSAFE_invariant, ab as createPath, ag as data, ah as generatePath, ai as isRouteErrorResponse, aj as matchPath, ak as matchRoutes, ac as parsePath, al as redirect, am as redirectDocument, an as replace, ao as resolvePath, Z as unstable_MiddlewareFunction, a4 as unstable_RouterContext, a9 as unstable_RouterContextProvider, aF as unstable_SerializesTo, a8 as unstable_createContext } from './route-data-B3YkvRuy.mjs';
3
- import { A as AssetsManifest, E as EntryContext, F as FutureConfig$1, a as RouteComponentType, H as HydrateFallbackType, b as ErrorBoundaryType, S as ServerBuild, c as ServerPayload } from './browser-BhRqpkqg.mjs';
4
- export { i as Await, d as AwaitProps, ag as BrowserRouter, a0 as BrowserRouterProps, a1 as DOMRouterOpts, a7 as FetcherFormProps, ac as FetcherSubmitFunction, aw as FetcherSubmitOptions, ad as FetcherWithComponents, al as Form, a8 as FormProps, aH as HandleDataRequestFunction, aI as HandleDocumentRequestFunction, aJ as HandleErrorFunction, ah as HashRouter, a2 as HashRouterProps, a3 as HistoryRouterProps, I as IndexRouteProps, L as LayoutRouteProps, ai as Link, a4 as LinkProps, aD as Links, j as MemoryRouter, M as MemoryRouterOpts, e as MemoryRouterProps, aC as Meta, ak as NavLink, a5 as NavLinkProps, a6 as NavLinkRenderProps, k as Navigate, u as NavigateFunction, N as NavigateProps, l as Outlet, O as OutletProps, ax as ParamKeyValuePair, P as PathRouteProps, aF as PrefetchPageLinks, m as Route, f as RouteProps, n as Router, g as RouterProps, o as RouterProvider, R as RouterProviderProps, p as Routes, h as RoutesProps, aE as Scripts, aG as ScriptsProps, am as ScrollRestoration, a9 as ScrollRestorationProps, aK as ServerEntryModule, aa as SetURLSearchParams, ab as SubmitFunction, ay as SubmitOptions, aA as SubmitTarget, aV as UNSAFE_FrameworkContext, aW as UNSAFE_createClientRoutes, aX as UNSAFE_createClientRoutesWithHMRRevalidationOptOut, aQ as UNSAFE_hydrationRouteProperties, aR as UNSAFE_mapRouteProperties, aY as UNSAFE_shouldHydrateRouteLoader, aZ as UNSAFE_useScrollRestoration, aS as UNSAFE_withComponentProps, aU as UNSAFE_withErrorBoundaryProps, aT as UNSAFE_withHydrateFallbackProps, az as URLSearchParamsInit, ae as createBrowserRouter, af as createHashRouter, q as createMemoryRouter, r as createRoutesFromChildren, s as createRoutesFromElements, aB as createSearchParams, t as renderMatches, aL as unstable_DecodeServerResponseFunction, aM as unstable_EncodeActionFunction, aj as unstable_HistoryRouter, aO as unstable_RSCHydratedRouter, aN as unstable_createCallServer, aP as unstable_getServerStream, au as unstable_usePrompt, w as useActionData, x as useAsyncError, y as useAsyncValue, at as useBeforeUnload, v as useBlocker, ar as useFetcher, as as useFetchers, aq as useFormAction, z as useHref, B as useInRouterContext, an as useLinkClickHandler, C as useLoaderData, D as useLocation, G as useMatch, J as useMatches, K as useNavigate, Q as useNavigation, T as useNavigationType, U as useOutlet, V as useOutletContext, W as useParams, X as useResolvedPath, Y as useRevalidator, Z as useRouteError, _ as useRouteLoaderData, $ as useRoutes, ao as useSearchParams, ap as useSubmit, av as useViewTransitionState } from './browser-BhRqpkqg.mjs';
3
+ import { A as AssetsManifest, E as EntryContext, F as FutureConfig$1, a as RouteComponentType, H as HydrateFallbackType, b as ErrorBoundaryType, S as ServerBuild, c as ServerPayload } from './browser-BM9EKN98.mjs';
4
+ export { i as Await, d as AwaitProps, ag as BrowserRouter, a0 as BrowserRouterProps, a1 as DOMRouterOpts, a7 as FetcherFormProps, ac as FetcherSubmitFunction, aw as FetcherSubmitOptions, ad as FetcherWithComponents, al as Form, a8 as FormProps, aH as HandleDataRequestFunction, aI as HandleDocumentRequestFunction, aJ as HandleErrorFunction, ah as HashRouter, a2 as HashRouterProps, a3 as HistoryRouterProps, I as IndexRouteProps, L as LayoutRouteProps, ai as Link, a4 as LinkProps, aD as Links, j as MemoryRouter, M as MemoryRouterOpts, e as MemoryRouterProps, aC as Meta, ak as NavLink, a5 as NavLinkProps, a6 as NavLinkRenderProps, k as Navigate, u as NavigateFunction, N as NavigateProps, l as Outlet, O as OutletProps, ax as ParamKeyValuePair, P as PathRouteProps, aF as PrefetchPageLinks, m as Route, f as RouteProps, n as Router, g as RouterProps, o as RouterProvider, R as RouterProviderProps, p as Routes, h as RoutesProps, aE as Scripts, aG as ScriptsProps, am as ScrollRestoration, a9 as ScrollRestorationProps, aK as ServerEntryModule, aa as SetURLSearchParams, ab as SubmitFunction, ay as SubmitOptions, aA as SubmitTarget, aV as UNSAFE_FrameworkContext, aW as UNSAFE_createClientRoutes, aX as UNSAFE_createClientRoutesWithHMRRevalidationOptOut, aQ as UNSAFE_hydrationRouteProperties, aR as UNSAFE_mapRouteProperties, aY as UNSAFE_shouldHydrateRouteLoader, aZ as UNSAFE_useScrollRestoration, aS as UNSAFE_withComponentProps, aU as UNSAFE_withErrorBoundaryProps, aT as UNSAFE_withHydrateFallbackProps, az as URLSearchParamsInit, ae as createBrowserRouter, af as createHashRouter, q as createMemoryRouter, r as createRoutesFromChildren, s as createRoutesFromElements, aB as createSearchParams, t as renderMatches, aL as unstable_DecodeServerResponseFunction, aM as unstable_EncodeActionFunction, aj as unstable_HistoryRouter, aO as unstable_RSCHydratedRouter, aN as unstable_createCallServer, aP as unstable_getServerStream, au as unstable_usePrompt, w as useActionData, x as useAsyncError, y as useAsyncValue, at as useBeforeUnload, v as useBlocker, ar as useFetcher, as as useFetchers, aq as useFormAction, z as useHref, B as useInRouterContext, an as useLinkClickHandler, C as useLoaderData, D as useLocation, G as useMatch, J as useMatches, K as useNavigate, Q as useNavigation, T as useNavigationType, U as useOutlet, V as useOutletContext, W as useParams, X as useResolvedPath, Y as useRevalidator, Z as useRouteError, _ as useRouteLoaderData, $ as useRoutes, ao as useSearchParams, ap as useSubmit, av as useViewTransitionState } from './browser-BM9EKN98.mjs';
5
5
  import * as React from 'react';
6
6
  import { ReactElement } from 'react';
7
7
  import { ParseOptions, SerializeOptions } from 'cookie';
@@ -2548,7 +2548,6 @@ type ServerRenderPayload = {
2548
2548
  };
2549
2549
  type ServerManifestPayload = {
2550
2550
  type: "manifest";
2551
- matches: RenderedRoute[];
2552
2551
  patches: RenderedRoute[];
2553
2552
  };
2554
2553
  type ServerActionPayload = {
@@ -2578,9 +2577,10 @@ declare function createCallServer({ decode, encodeAction, }: {
2578
2577
  decode: DecodeServerResponseFunction;
2579
2578
  encodeAction: EncodeActionFunction;
2580
2579
  }): (id: string, args: unknown[]) => Promise<unknown>;
2581
- declare function RSCHydratedRouter({ decode, payload, }: {
2580
+ declare function RSCHydratedRouter({ decode, payload, routeDiscovery, }: {
2582
2581
  decode: DecodeServerResponseFunction;
2583
2582
  payload: ServerPayload;
2583
+ routeDiscovery?: "eager" | "lazy";
2584
2584
  }): React.JSX.Element;
2585
2585
 
2586
2586
  declare function routeRSCServerRequest({ request, callServer, decode, renderHTML, hydrate, }: {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -7356,7 +7356,7 @@ function getTurboStreamSingleFetchDataStrategy(getRouter, manifest, routeModules
7356
7356
  );
7357
7357
  return async (args) => args.unstable_runClientMiddleware(dataStrategy);
7358
7358
  }
7359
- function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename) {
7359
+ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7360
7360
  return async (args) => {
7361
7361
  let { request, matches, fetcherKey } = args;
7362
7362
  let router = getRouter();
@@ -7379,7 +7379,8 @@ function getSingleFetchDataStrategyImpl(getRouter, getRouteInfo, fetchAndDecode,
7379
7379
  getRouteInfo,
7380
7380
  fetchAndDecode,
7381
7381
  ssr,
7382
- basename
7382
+ basename,
7383
+ shouldAllowOptOut
7383
7384
  );
7384
7385
  };
7385
7386
  }
@@ -7431,7 +7432,7 @@ async function nonSsrStrategy(args, getRouteInfo, fetchAndDecode, basename) {
7431
7432
  );
7432
7433
  return results;
7433
7434
  }
7434
- async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename) {
7435
+ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, fetchAndDecode, ssr, basename, shouldAllowOptOut = () => true) {
7435
7436
  let routesParams = /* @__PURE__ */ new Set();
7436
7437
  let foundOptOutRoute = false;
7437
7438
  let routeDfds = args.matches.map(() => createDeferred2());
@@ -7451,7 +7452,7 @@ async function singleFetchLoaderNavigationStrategy(args, router, getRouteInfo, f
7451
7452
  hasShouldRevalidate === true);
7452
7453
  return;
7453
7454
  }
7454
- if (hasClientLoader) {
7455
+ if (shouldAllowOptOut(m) && hasClientLoader) {
7455
7456
  if (hasLoader) {
7456
7457
  foundOptOutRoute = true;
7457
7458
  }
@@ -8952,7 +8953,7 @@ function mergeRefs(...refs) {
8952
8953
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
8953
8954
  try {
8954
8955
  if (isBrowser) {
8955
- window.__reactRouterVersion = "0.0.0-experimental-8c9575952";
8956
+ window.__reactRouterVersion = "0.0.0-experimental-e7eb25a7b";
8956
8957
  }
8957
8958
  } catch (e) {
8958
8959
  }
@@ -11778,23 +11779,11 @@ function createRouterFromPayload({
11778
11779
  void 0,
11779
11780
  false
11780
11781
  ),
11781
- async patchRoutesOnNavigation({ patch, path, signal }) {
11782
- let response = await fetch(`${path}.manifest`, { signal });
11783
- if (!response.body || response.status < 200 || response.status >= 300) {
11784
- throw new Error("Unable to fetch new route matches from the server");
11785
- }
11786
- let payload2 = await decode2(response.body);
11787
- if (payload2.type !== "manifest") {
11788
- throw new Error("Failed to patch routes on navigation");
11789
- }
11790
- payload2.matches.forEach(
11791
- (match, i) => patch(payload2.matches[i - 1]?.id ?? null, [
11792
- createRouteFromServerManifest(match)
11793
- ])
11794
- );
11795
- payload2.patches.forEach((p) => {
11796
- patch(p.parentId ?? null, [createRouteFromServerManifest(p)]);
11797
- });
11782
+ async patchRoutesOnNavigation({ path, signal }) {
11783
+ if (discoveredPaths2.has(path)) {
11784
+ return;
11785
+ }
11786
+ await fetchAndApplyManifestPatches2([path], decode2, signal);
11798
11787
  },
11799
11788
  // FIXME: Pass `build.ssr` and `build.basename` into this function
11800
11789
  dataStrategy: getRSCSingleFetchDataStrategy(
@@ -11835,23 +11824,35 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, basename, decode2) {
11835
11824
  // pass map into fetchAndDecode so it can add payloads
11836
11825
  getFetchAndDecodeViaRSC(decode2),
11837
11826
  ssr,
11838
- basename
11827
+ basename,
11828
+ // If we don't have an element, we need to hit the server loader flow
11829
+ // regardless of whether the client loader calls `serverLoader` or not,
11830
+ // otherwise we'll have nothing to render.
11831
+ // TODO: Do we need to account for API routes? Do we need a
11832
+ // `match.hasComponent` flag?
11833
+ (match) => match.route.element != null
11839
11834
  );
11840
11835
  return async (args) => args.unstable_runClientMiddleware(async () => {
11841
11836
  let context = args.context;
11842
11837
  context.set(renderedRoutesContext, []);
11843
11838
  let results = await dataStrategy(args);
11844
- const renderedRouteById = new Map(
11845
- context.get(renderedRoutesContext).map((r) => [r.id, r])
11846
- );
11839
+ const renderedRoutesById = /* @__PURE__ */ new Map();
11840
+ for (const route of context.get(renderedRoutesContext)) {
11841
+ if (!renderedRoutesById.has(route.id)) {
11842
+ renderedRoutesById.set(route.id, []);
11843
+ }
11844
+ renderedRoutesById.get(route.id).push(route);
11845
+ }
11847
11846
  for (const match of args.matches) {
11848
- const rendered = renderedRouteById.get(match.route.id);
11849
- if (rendered) {
11850
- window.__router.patchRoutes(
11851
- rendered.parentId ?? null,
11852
- [createRouteFromServerManifest(rendered)],
11853
- true
11854
- );
11847
+ const renderedRoutes = renderedRoutesById.get(match.route.id);
11848
+ if (renderedRoutes) {
11849
+ for (const rendered of renderedRoutes) {
11850
+ window.__router.patchRoutes(
11851
+ rendered.parentId ?? null,
11852
+ [createRouteFromServerManifest(rendered)],
11853
+ true
11854
+ );
11855
+ }
11855
11856
  }
11856
11857
  }
11857
11858
  return results;
@@ -11910,7 +11911,8 @@ function getFetchAndDecodeViaRSC(decode2) {
11910
11911
  }
11911
11912
  function RSCHydratedRouter({
11912
11913
  decode: decode2,
11913
- payload
11914
+ payload,
11915
+ routeDiscovery = "eager"
11914
11916
  }) {
11915
11917
  if (payload.type !== "render") throw new Error("Invalid payload type");
11916
11918
  let router = React14.useMemo(
@@ -11924,6 +11926,49 @@ function RSCHydratedRouter({
11924
11926
  window.__router.initialize();
11925
11927
  }
11926
11928
  }, []);
11929
+ React14.useEffect(() => {
11930
+ if (routeDiscovery === "lazy" || // @ts-expect-error - TS doesn't know about this yet
11931
+ window.navigator?.connection?.saveData === true) {
11932
+ return;
11933
+ }
11934
+ function registerElement(el) {
11935
+ let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
11936
+ if (!path) {
11937
+ return;
11938
+ }
11939
+ let pathname = el.tagName === "A" ? el.pathname : new URL(path, window.location.origin).pathname;
11940
+ if (!discoveredPaths2.has(pathname)) {
11941
+ nextPaths2.add(pathname);
11942
+ }
11943
+ }
11944
+ async function fetchPatches() {
11945
+ document.querySelectorAll("a[data-discover], form[data-discover]").forEach(registerElement);
11946
+ let paths = Array.from(nextPaths2.keys()).filter((path) => {
11947
+ if (discoveredPaths2.has(path)) {
11948
+ nextPaths2.delete(path);
11949
+ return false;
11950
+ }
11951
+ return true;
11952
+ });
11953
+ if (paths.length === 0) {
11954
+ return;
11955
+ }
11956
+ try {
11957
+ await fetchAndApplyManifestPatches2(paths, decode2);
11958
+ } catch (e) {
11959
+ console.error("Failed to fetch manifest patches", e);
11960
+ }
11961
+ }
11962
+ let debouncedFetchPatches = debounce2(fetchPatches, 100);
11963
+ fetchPatches();
11964
+ let observer = new MutationObserver(() => debouncedFetchPatches());
11965
+ observer.observe(document.documentElement, {
11966
+ subtree: true,
11967
+ childList: true,
11968
+ attributes: true,
11969
+ attributeFilter: ["data-discover", "href", "action"]
11970
+ });
11971
+ }, [routeDiscovery, decode2]);
11927
11972
  const frameworkContext = {
11928
11973
  future: {
11929
11974
  // These flags have no runtime impact so can always be false. If we add
@@ -11953,7 +11998,12 @@ function createRouteFromServerManifest(match, payload) {
11953
11998
  let initialData = payload?.loaderData[match.id];
11954
11999
  let hasInitialError = payload?.errors && match.id in payload.errors;
11955
12000
  let initialError = payload?.errors?.[match.id];
11956
- let isHydrationRequest = match.clientLoader?.hydrate === true || !match.hasLoader;
12001
+ let isHydrationRequest = match.clientLoader?.hydrate === true || !match.hasLoader || // If we don't have an element, we need to hit the server loader flow
12002
+ // regardless of whether the client loader calls `serverLoader` or not,
12003
+ // otherwise we'll have nothing to render.
12004
+ // TODO: Do we need to account for API routes? Do we need a
12005
+ // `match.hasComponent` flag?
12006
+ !match.element;
11957
12007
  let dataRoute = {
11958
12008
  id: match.id,
11959
12009
  element: match.element,
@@ -12035,6 +12085,47 @@ function preventInvalidServerHandlerCall2(type, routeId, hasHandler) {
12035
12085
  throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
12036
12086
  }
12037
12087
  }
12088
+ var nextPaths2 = /* @__PURE__ */ new Set();
12089
+ var discoveredPathsMaxSize2 = 1e3;
12090
+ var discoveredPaths2 = /* @__PURE__ */ new Set();
12091
+ var URL_LIMIT2 = 7680;
12092
+ async function fetchAndApplyManifestPatches2(paths, decode2, signal) {
12093
+ let basename = (window.__router.basename ?? "").replace(/^\/|\/$/g, "");
12094
+ let url = new URL(`${basename}/.manifest`, window.location.origin);
12095
+ paths.sort().forEach((path) => url.searchParams.append("p", path));
12096
+ if (url.toString().length > URL_LIMIT2) {
12097
+ nextPaths2.clear();
12098
+ return;
12099
+ }
12100
+ let response = await fetch(url, { signal });
12101
+ if (!response.body || response.status < 200 || response.status >= 300) {
12102
+ throw new Error("Unable to fetch new route matches from the server");
12103
+ }
12104
+ let payload = await decode2(response.body);
12105
+ if (payload.type !== "manifest") {
12106
+ throw new Error("Failed to patch routes");
12107
+ }
12108
+ paths.forEach((p) => addToFifoQueue2(p, discoveredPaths2));
12109
+ payload.patches.forEach((p) => {
12110
+ window.__router.patchRoutes(p.parentId ?? null, [
12111
+ createRouteFromServerManifest(p)
12112
+ ]);
12113
+ });
12114
+ }
12115
+ function addToFifoQueue2(path, queue) {
12116
+ if (queue.size >= discoveredPathsMaxSize2) {
12117
+ let first = queue.values().next().value;
12118
+ queue.delete(first);
12119
+ }
12120
+ queue.add(path);
12121
+ }
12122
+ function debounce2(callback, wait) {
12123
+ let timeoutId;
12124
+ return (...args) => {
12125
+ window.clearTimeout(timeoutId);
12126
+ timeoutId = window.setTimeout(() => callback(...args), wait);
12127
+ };
12128
+ }
12038
12129
 
12039
12130
  // lib/rsc/server.ssr.tsx
12040
12131
  var React15 = __toESM(require("react"));
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -134,7 +134,7 @@ import {
134
134
  withComponentProps,
135
135
  withErrorBoundaryProps,
136
136
  withHydrateFallbackProps
137
- } from "./chunk-4SZKM7GJ.mjs";
137
+ } from "./chunk-SHQJZRZ7.mjs";
138
138
  export {
139
139
  Await,
140
140
  BrowserRouter,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v0.0.0-experimental-8c9575952
2
+ * react-router v0.0.0-experimental-e7eb25a7b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1763,7 +1763,6 @@ type ServerRenderPayload = {
1763
1763
  };
1764
1764
  type ServerManifestPayload = {
1765
1765
  type: "manifest";
1766
- matches: RenderedRoute[];
1767
1766
  patches: RenderedRoute[];
1768
1767
  };
1769
1768
  type ServerActionPayload = {
@@ -1763,7 +1763,6 @@ type ServerRenderPayload = {
1763
1763
  };
1764
1764
  type ServerManifestPayload = {
1765
1765
  type: "manifest";
1766
- matches: RenderedRoute[];
1767
1766
  patches: RenderedRoute[];
1768
1767
  };
1769
1768
  type ServerActionPayload = {