@agg-build/hooks 1.2.0 → 1.2.11

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.
package/dist/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  useRampQuotes,
3
3
  useRampSession
4
- } from "./chunk-FKTRXKYA.mjs";
4
+ } from "./chunk-JWPZNCGY.mjs";
5
5
  import {
6
+ useWithdrawEstimate,
6
7
  useWithdrawFlow,
7
8
  useWithdrawalLifecycle
8
- } from "./chunk-KSSPFJM2.mjs";
9
+ } from "./chunk-CWEJLBYY.mjs";
9
10
  import {
10
11
  AggAuthContext,
11
12
  AggBalanceProvider,
@@ -19,6 +20,8 @@ import {
19
20
  MarketStatus,
20
21
  MatchStatus,
21
22
  MatchType,
23
+ RedeemRejectedError,
24
+ TradeSide,
22
25
  Venue,
23
26
  __async,
24
27
  __objRest,
@@ -34,10 +37,13 @@ import {
34
37
  executionKeys,
35
38
  getBuilder,
36
39
  getDepositAddress,
40
+ getIntervalSeconds,
37
41
  getOrCreateBuilder,
38
42
  getWalletAddressFromUserProfile,
39
43
  invalidateBalanceQueries,
40
44
  invalidatePositionQueries,
45
+ invalidateUserActivityQueries,
46
+ invalidateUserMoneyState,
41
47
  marketDataKeys,
42
48
  marketOrderbookDataToResponse,
43
49
  mergeMarketChartData,
@@ -78,11 +84,14 @@ import {
78
84
  useQuoteManaged,
79
85
  useRedeem,
80
86
  useRedeemEligibleCount,
87
+ useRedeemLifecycle,
88
+ useRedeemLifecycles,
81
89
  useSdkLabels,
82
90
  useSdkUiConfig,
83
91
  useSyncBalances,
84
- useWithdrawManaged
85
- } from "./chunk-U3DRHUR5.mjs";
92
+ useWithdrawManaged,
93
+ userActivityQueryKeys
94
+ } from "./chunk-553OI6M2.mjs";
86
95
 
87
96
  // src/index.ts
88
97
  import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
@@ -226,11 +235,22 @@ import { useInfiniteQuery as useInfiniteQuery2 } from "@tanstack/react-query";
226
235
  function useExecutionOrders(options = {}) {
227
236
  var _a, _b;
228
237
  const client = useAggClient();
229
- const { status, limit = 50, enabled = true, refetchIntervalMs = false } = options;
238
+ const {
239
+ status,
240
+ orderId,
241
+ quoteId,
242
+ limit = 50,
243
+ enabled = true,
244
+ refetchIntervalMs = false
245
+ } = options;
230
246
  const query = useInfiniteQuery2({
231
- queryKey: ["execution-orders", status != null ? status : "all", limit],
247
+ // quoteId + orderId are part of the cache key — different filters
248
+ // produce different result sets, so they have to vary the key.
249
+ queryKey: ["execution-orders", status != null ? status : "all", quoteId != null ? quoteId : null, orderId != null ? orderId : null, limit],
232
250
  queryFn: ({ pageParam }) => client.getExecutionOrders({
233
251
  status,
252
+ orderId,
253
+ quoteId,
234
254
  limit,
235
255
  cursor: pageParam
236
256
  }),
@@ -251,11 +271,37 @@ function useExecutionOrders(options = {}) {
251
271
  }
252
272
 
253
273
  // src/use-user-activity.ts
254
- import { useInfiniteQuery as useInfiniteQuery3 } from "@tanstack/react-query";
274
+ import { keepPreviousData, useInfiniteQuery as useInfiniteQuery3 } from "@tanstack/react-query";
275
+ var DEFAULT_PENDING_REFETCH_INTERVAL_MS = 15e3;
276
+ var PENDING_ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
277
+ "pending",
278
+ // trade pre-fill lifecycle
279
+ "signing",
280
+ "pending_bridge",
281
+ "submitting",
282
+ "submitted",
283
+ // withdrawal lifecycle
284
+ "bridging",
285
+ "transferring"
286
+ ]);
287
+ var hasPendingActivity = (pages) => {
288
+ if (!pages) return false;
289
+ for (const page of pages) {
290
+ for (const item of page.data) {
291
+ if (PENDING_ACTIVITY_STATUSES.has(item.status.toLowerCase())) return true;
292
+ }
293
+ }
294
+ return false;
295
+ };
255
296
  function useUserActivity(options = {}) {
256
297
  var _a, _b;
257
298
  const client = useAggClient();
258
- const { type, limit = 50, enabled = true } = options;
299
+ const {
300
+ type,
301
+ limit = 50,
302
+ enabled = true,
303
+ pendingRefetchIntervalMs = DEFAULT_PENDING_REFETCH_INTERVAL_MS
304
+ } = options;
259
305
  const query = useInfiniteQuery3({
260
306
  queryKey: ["user-activity", type != null ? type : "all", limit],
261
307
  queryFn: ({ pageParam }) => client.getUserActivity({
@@ -268,7 +314,17 @@ function useUserActivity(options = {}) {
268
314
  var _a2;
269
315
  return lastPage.hasMore ? (_a2 = lastPage.nextCursor) != null ? _a2 : void 0 : void 0;
270
316
  },
271
- enabled
317
+ enabled,
318
+ // Keep the previously-loaded pages visible while a refetch is in
319
+ // flight (typically after a deposit / withdraw cache invalidation).
320
+ // Without this the feed flashes to the skeleton mid-session, which
321
+ // is worse UX than briefly showing slightly-stale rows.
322
+ placeholderData: keepPreviousData,
323
+ refetchInterval: (q) => {
324
+ if (pendingRefetchIntervalMs === false) return false;
325
+ const data = q.state.data;
326
+ return hasPendingActivity(data == null ? void 0 : data.pages) ? pendingRefetchIntervalMs : false;
327
+ }
272
328
  });
273
329
  const activities = (_b = (_a = query.data) == null ? void 0 : _a.pages.flatMap((page) => page.data)) != null ? _b : [];
274
330
  const hasNextPage = !!query.hasNextPage;
@@ -343,7 +399,7 @@ import { useMemo as useMemo3 } from "react";
343
399
  import { mergeCandles, mergeClosedCandles } from "@agg-build/sdk";
344
400
 
345
401
  // src/use-market-chart.ts
346
- import { keepPreviousData, useQueries } from "@tanstack/react-query";
402
+ import { keepPreviousData as keepPreviousData2, useQueries } from "@tanstack/react-query";
347
403
 
348
404
  // src/market-data/subscription.ts
349
405
  import { useEffect as useEffect2, useMemo } from "react";
@@ -403,24 +459,23 @@ function useMarketChart(options) {
403
459
  endTs = null,
404
460
  countBack = null,
405
461
  enabled = true,
406
- live
462
+ live,
463
+ refetchIntervalMs = null,
464
+ rangeKey
407
465
  } = options;
466
+ const resolvedRangeKey = rangeKey != null ? rangeKey : interval;
408
467
  const liveEnabled = live != null ? live : enableLiveUpdates;
409
468
  const outcomeIds = (() => {
410
469
  const ids = /* @__PURE__ */ new Set();
411
- if (marketId) {
412
- ids.add(marketId);
413
- }
470
+ if (marketId) ids.add(marketId);
414
471
  if (venueMarketIds) {
415
472
  for (const venueMarketId of venueMarketIds) {
416
- if (venueMarketId) {
417
- ids.add(venueMarketId);
418
- }
473
+ if (venueMarketId) ids.add(venueMarketId);
419
474
  }
420
475
  }
421
- return [...ids];
476
+ return [...ids].sort();
422
477
  })();
423
- const primaryOutcomeId = (_a = outcomeIds[0]) != null ? _a : null;
478
+ const primaryOutcomeId = (_a = marketId != null ? marketId : venueMarketIds == null ? void 0 : venueMarketIds.find(Boolean)) != null ? _a : null;
424
479
  const isQueryEnabled = enabled && outcomeIds.length > 0 && endTs != null && (startTs != null || countBack != null);
425
480
  useMarketDataSubscription({
426
481
  marketId: primaryOutcomeId,
@@ -431,7 +486,11 @@ function useMarketChart(options) {
431
486
  });
432
487
  const queries = useQueries({
433
488
  queries: outcomeIds.map((outcomeId) => ({
434
- queryKey: marketDataKeys.chart(outcomeId, interval, startTs, endTs, countBack),
489
+ // Cache key is intentionally time-free. The rolling window's
490
+ // startTs/endTs advance on every bucket but the user expects the same
491
+ // chart on revisit — see comment on `marketDataKeys.chart`. queryFn
492
+ // closes over the current window so refetches still fetch fresh data.
493
+ queryKey: marketDataKeys.chart(outcomeId, interval, resolvedRangeKey, countBack),
435
494
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
436
495
  const response = yield client.getChartBars(
437
496
  {
@@ -452,11 +511,17 @@ function useMarketChart(options) {
452
511
  });
453
512
  }),
454
513
  enabled: isQueryEnabled,
455
- staleTime: 3e4,
456
- gcTime: 5 * 6e4,
514
+ // Treat data as fresh for one bucket — within that window the
515
+ // existing entry serves remounts without a refetch, and the
516
+ // `refetchInterval` below schedules the next bucket's refresh.
517
+ staleTime: refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : 3e4,
518
+ // 60 min — survives typical tab/page revisits without re-fetching.
519
+ gcTime: 60 * 6e4,
457
520
  refetchOnWindowFocus: false,
458
521
  retry: 1,
459
- placeholderData: keepPreviousData
522
+ placeholderData: keepPreviousData2,
523
+ refetchInterval: refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : false,
524
+ refetchIntervalInBackground: false
460
525
  }))
461
526
  });
462
527
  const successfulDatasets = queries.flatMap((query) => {
@@ -854,6 +919,128 @@ function findLivePriceById(livePrices, id) {
854
919
  return livePrices.get(id);
855
920
  }
856
921
 
922
+ // src/use-live-best-prices.ts
923
+ import { useMemo as useMemo7, useRef as useRef3 } from "react";
924
+ import { useQueries as useQueries3 } from "@tanstack/react-query";
925
+ var EMPTY = /* @__PURE__ */ new Map();
926
+ var extractOutcomeBestPrices = (state) => {
927
+ var _a, _b;
928
+ const ob = state == null ? void 0 : state.orderbook;
929
+ if (!ob) return {};
930
+ const bestBid = (_a = ob.bids[0]) == null ? void 0 : _a.price;
931
+ const bestAsk = (_b = ob.asks[0]) == null ? void 0 : _b.price;
932
+ return {
933
+ bestBid: bestBid != null ? bestBid : void 0,
934
+ bestAsk: bestAsk != null ? bestAsk : void 0
935
+ };
936
+ };
937
+ var buildFingerprint = (outcomeIds, queries) => {
938
+ var _a, _b, _c, _d;
939
+ const parts = [];
940
+ for (let i = 0; i < outcomeIds.length; i++) {
941
+ const ob = (_b = (_a = queries[i]) == null ? void 0 : _a.data) == null ? void 0 : _b.orderbook;
942
+ const bid = (_c = ob == null ? void 0 : ob.bids[0]) == null ? void 0 : _c.price;
943
+ const ask = (_d = ob == null ? void 0 : ob.asks[0]) == null ? void 0 : _d.price;
944
+ parts.push(`${outcomeIds[i]}:${bid != null ? bid : "_"}:${ask != null ? ask : "_"}`);
945
+ }
946
+ return parts.join("|");
947
+ };
948
+ function useLiveBestPrices(venueMarkets) {
949
+ const {
950
+ features: { enableLiveUpdates }
951
+ } = useAggUiConfig();
952
+ const outcomeIds = useMemo7(() => {
953
+ var _a, _b;
954
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
955
+ const ids = /* @__PURE__ */ new Set();
956
+ for (const vm of venueMarkets) {
957
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
958
+ if (outcome.id) ids.add(outcome.id);
959
+ for (const ref of (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : []) {
960
+ if (ref.venueMarketOutcomeId) ids.add(ref.venueMarketOutcomeId);
961
+ }
962
+ }
963
+ }
964
+ return [...ids].sort();
965
+ }, [venueMarkets]);
966
+ const queries = useQueries3({
967
+ queries: outcomeIds.map((id) => ({
968
+ queryKey: marketDataKeys.live(id),
969
+ queryFn: () => createMarketLiveState(id),
970
+ enabled: false,
971
+ staleTime: Infinity,
972
+ gcTime: 5 * 6e4,
973
+ initialData: () => createMarketLiveState(id)
974
+ }))
975
+ });
976
+ const fingerprint = buildFingerprint(outcomeIds, queries);
977
+ const prevRef = useRef3({
978
+ fingerprint: "",
979
+ result: EMPTY
980
+ });
981
+ return useMemo7(() => {
982
+ var _a, _b, _c, _d;
983
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length) || !enableLiveUpdates) return EMPTY;
984
+ if (fingerprint === prevRef.current.fingerprint) return prevRef.current.result;
985
+ const perOutcome = /* @__PURE__ */ new Map();
986
+ for (let i = 0; i < outcomeIds.length; i++) {
987
+ const state = (_a = queries[i]) == null ? void 0 : _a.data;
988
+ const best = extractOutcomeBestPrices(state);
989
+ if (best.bestBid != null || best.bestAsk != null) {
990
+ perOutcome.set(outcomeIds[i], best);
991
+ }
992
+ }
993
+ if (perOutcome.size === 0) {
994
+ prevRef.current = { fingerprint, result: EMPTY };
995
+ return EMPTY;
996
+ }
997
+ const result = new Map(perOutcome);
998
+ for (const vm of venueMarkets) {
999
+ for (const outcome of (_b = vm.venueMarketOutcomes) != null ? _b : []) {
1000
+ const refs = (_c = outcome.matchedVenueMarketOutcomes) != null ? _c : [];
1001
+ if (!refs.length) continue;
1002
+ const group = [outcome.id, ...refs.map((ref) => ref.venueMarketOutcomeId)];
1003
+ let groupBestAsk;
1004
+ let groupBestBid;
1005
+ for (const id of group) {
1006
+ const entry = perOutcome.get(id);
1007
+ if (!entry) continue;
1008
+ if (entry.bestAsk != null && (groupBestAsk == null || entry.bestAsk < groupBestAsk)) {
1009
+ groupBestAsk = entry.bestAsk;
1010
+ }
1011
+ if (entry.bestBid != null && (groupBestBid == null || entry.bestBid > groupBestBid)) {
1012
+ groupBestBid = entry.bestBid;
1013
+ }
1014
+ }
1015
+ if (groupBestAsk == null && groupBestBid == null) continue;
1016
+ for (const id of group) {
1017
+ const prev = (_d = result.get(id)) != null ? _d : {};
1018
+ const nextBid = groupBestBid != null ? groupBestBid : prev.bestBid;
1019
+ const nextAsk = groupBestAsk != null ? groupBestAsk : prev.bestAsk;
1020
+ if (nextBid == null && nextAsk == null) continue;
1021
+ result.set(id, __spreadValues(__spreadValues({}, nextBid != null ? { bestBid: nextBid } : {}), nextAsk != null ? { bestAsk: nextAsk } : {}));
1022
+ }
1023
+ }
1024
+ }
1025
+ prevRef.current = { fingerprint, result };
1026
+ return result;
1027
+ }, [venueMarkets, enableLiveUpdates, fingerprint, outcomeIds, queries]);
1028
+ }
1029
+ function mergeBestPricesPreferringLive(rest, live) {
1030
+ var _a, _b, _c;
1031
+ if (!live.size) return rest != null ? rest : EMPTY;
1032
+ if (!rest || !rest.size) return live;
1033
+ const merged = new Map(rest);
1034
+ for (const [id, liveEntry] of live) {
1035
+ const prev = (_a = merged.get(id)) != null ? _a : {};
1036
+ merged.set(id, {
1037
+ bestBid: (_b = liveEntry.bestBid) != null ? _b : prev.bestBid,
1038
+ bestAsk: (_c = liveEntry.bestAsk) != null ? _c : prev.bestAsk
1039
+ });
1040
+ }
1041
+ return merged;
1042
+ }
1043
+
857
1044
  // src/use-live-trades.ts
858
1045
  function useLiveTrades(canonicalMarketId) {
859
1046
  const {
@@ -870,19 +1057,146 @@ function useLiveTrades(canonicalMarketId) {
870
1057
  }
871
1058
 
872
1059
  // src/use-midpoints.ts
873
- import { useMemo as useMemo7 } from "react";
874
1060
  import { useQuery as useQuery2 } from "@tanstack/react-query";
1061
+ import { useMemo as useMemo8 } from "react";
875
1062
  var normalizeVenueMarketIds = (venueMarkets) => {
876
- return [...new Set((venueMarkets != null ? venueMarkets : []).map((market) => market.id).filter(Boolean))].sort(
877
- (left, right) => left.localeCompare(right)
1063
+ var _a;
1064
+ const ids = /* @__PURE__ */ new Set();
1065
+ for (const market of venueMarkets != null ? venueMarkets : []) {
1066
+ if (market.id) ids.add(market.id);
1067
+ for (const sibling of (_a = market.matchedVenueMarkets) != null ? _a : []) {
1068
+ if (sibling.id) ids.add(sibling.id);
1069
+ }
1070
+ }
1071
+ return [...ids].sort((left, right) => left.localeCompare(right));
1072
+ };
1073
+ var normalizeOutcomeLabel = (label) => {
1074
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
1075
+ };
1076
+ var resolveBestMidpointCandidateOutcomeIds = (venueMarkets) => {
1077
+ var _a, _b;
1078
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
1079
+ const candidateIds = [];
1080
+ for (const market of venueMarkets) {
1081
+ const outcomes = (_a = market.venueMarketOutcomes) != null ? _a : [];
1082
+ const yesOutcome = outcomes.find((outcome) => normalizeOutcomeLabel(outcome.label) === "yes");
1083
+ if (yesOutcome == null ? void 0 : yesOutcome.id) {
1084
+ candidateIds.push(yesOutcome.id);
1085
+ continue;
1086
+ }
1087
+ const firstOutcomeId = (_b = outcomes[0]) == null ? void 0 : _b.id;
1088
+ if (firstOutcomeId) {
1089
+ candidateIds.push(firstOutcomeId);
1090
+ }
1091
+ }
1092
+ return [...new Set(candidateIds)];
1093
+ };
1094
+ var resolveSiblingOutcomeMidpoint = (matched, ref) => {
1095
+ var _a, _b;
1096
+ if (!(matched == null ? void 0 : matched.length)) return null;
1097
+ const sibling = matched.find((m) => m.venueMarketId === ref.venueMarketId);
1098
+ if (!((_a = sibling == null ? void 0 : sibling.outcomes) == null ? void 0 : _a.length)) return null;
1099
+ const sibOutcome = sibling.outcomes.find(
1100
+ (o) => o.venueMarketOutcomeId === ref.venueMarketOutcomeId
878
1101
  );
1102
+ if ((sibOutcome == null ? void 0 : sibOutcome.midpoint) == null) return null;
1103
+ return { midpoint: sibOutcome.midpoint, venue: (_b = sibling.venue) != null ? _b : null };
1104
+ };
1105
+ var extractBestPrices = (data, venueMarkets) => {
1106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1107
+ const bestPrices = /* @__PURE__ */ new Map();
1108
+ const venuesByOutcome = /* @__PURE__ */ new Map();
1109
+ if (!(data == null ? void 0 : data.length)) return { bestPrices, bestPriceVenuesByOutcomeId: venuesByOutcome };
1110
+ const setEntry = (outcomeId, next) => {
1111
+ const prev = bestPrices.get(outcomeId);
1112
+ const merged = __spreadValues({}, prev != null ? prev : {});
1113
+ if (next.bestBid != null) merged.bestBid = next.bestBid;
1114
+ if (next.bestAsk != null) merged.bestAsk = next.bestAsk;
1115
+ if (merged.bestBid != null || merged.bestAsk != null) bestPrices.set(outcomeId, merged);
1116
+ const prevVenues = venuesByOutcome.get(outcomeId);
1117
+ const mergedVenues = __spreadValues({}, prevVenues != null ? prevVenues : {});
1118
+ if (next.bestBidVenue != null) mergedVenues.bestBidVenue = next.bestBidVenue;
1119
+ if (next.bestAskVenue != null) mergedVenues.bestAskVenue = next.bestAskVenue;
1120
+ if (mergedVenues.bestBidVenue || mergedVenues.bestAskVenue) {
1121
+ venuesByOutcome.set(outcomeId, mergedVenues);
1122
+ }
1123
+ };
1124
+ for (const item of data) {
1125
+ const venue = (_a = item.venue) != null ? _a : null;
1126
+ for (const o of (_b = item.outcomes) != null ? _b : []) {
1127
+ if (o.bestBid != null || o.bestAsk != null) {
1128
+ setEntry(o.venueMarketOutcomeId, {
1129
+ bestBid: o.bestBid,
1130
+ bestAsk: o.bestAsk,
1131
+ bestBidVenue: o.bestBid != null ? venue : null,
1132
+ bestAskVenue: o.bestAsk != null ? venue : null
1133
+ });
1134
+ }
1135
+ }
1136
+ }
1137
+ for (const item of data) {
1138
+ for (const m of (_c = item.matched) != null ? _c : []) {
1139
+ const venue = (_d = m.venue) != null ? _d : null;
1140
+ for (const o of (_e = m.outcomes) != null ? _e : []) {
1141
+ if (bestPrices.has(o.venueMarketOutcomeId)) continue;
1142
+ if (o.bestBid != null || o.bestAsk != null) {
1143
+ setEntry(o.venueMarketOutcomeId, {
1144
+ bestBid: o.bestBid,
1145
+ bestAsk: o.bestAsk,
1146
+ bestBidVenue: o.bestBid != null ? venue : null,
1147
+ bestAskVenue: o.bestAsk != null ? venue : null
1148
+ });
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+ if (venueMarkets == null ? void 0 : venueMarkets.length) {
1154
+ for (const market of venueMarkets) {
1155
+ for (const outcome of (_f = market.venueMarketOutcomes) != null ? _f : []) {
1156
+ const refs = (_g = outcome.matchedVenueMarketOutcomes) != null ? _g : [];
1157
+ if (!refs.length) continue;
1158
+ const group = [outcome.id, ...refs.map((ref) => ref.venueMarketOutcomeId)];
1159
+ let bestAsk;
1160
+ let bestBid;
1161
+ let bestAskVenue;
1162
+ let bestBidVenue;
1163
+ for (const id of group) {
1164
+ const entry = bestPrices.get(id);
1165
+ const venues = venuesByOutcome.get(id);
1166
+ if (!entry) continue;
1167
+ if (entry.bestAsk != null && (bestAsk == null || entry.bestAsk < bestAsk)) {
1168
+ bestAsk = entry.bestAsk;
1169
+ bestAskVenue = (_h = venues == null ? void 0 : venues.bestAskVenue) != null ? _h : bestAskVenue;
1170
+ }
1171
+ if (entry.bestBid != null && (bestBid == null || entry.bestBid > bestBid)) {
1172
+ bestBid = entry.bestBid;
1173
+ bestBidVenue = (_i = venues == null ? void 0 : venues.bestBidVenue) != null ? _i : bestBidVenue;
1174
+ }
1175
+ }
1176
+ if (bestAsk == null && bestBid == null) continue;
1177
+ for (const id of group) {
1178
+ setEntry(id, {
1179
+ bestBid,
1180
+ bestAsk,
1181
+ bestBidVenue,
1182
+ bestAskVenue
1183
+ });
1184
+ }
1185
+ }
1186
+ }
1187
+ }
1188
+ return { bestPrices, bestPriceVenuesByOutcomeId: venuesByOutcome };
879
1189
  };
880
1190
  function useMidpoints(venueMarkets) {
881
1191
  const client = useAggClient();
882
- const ids = useMemo7(() => normalizeVenueMarketIds(venueMarkets), [venueMarkets]);
1192
+ const ids = useMemo8(() => normalizeVenueMarketIds(venueMarkets), [venueMarkets]);
1193
+ const bestMidpointCandidateOutcomeIds = useMemo8(
1194
+ () => resolveBestMidpointCandidateOutcomeIds(venueMarkets),
1195
+ [venueMarkets]
1196
+ );
883
1197
  const { data, isLoading } = useQuery2({
884
1198
  queryKey: ["midpoints", ids],
885
- queryFn: () => client.getMidpoints(ids),
1199
+ queryFn: () => client.getMidpoints(ids, { bestPrice: true }),
886
1200
  enabled: ids.length > 0,
887
1201
  staleTime: Infinity,
888
1202
  gcTime: 30 * 6e4,
@@ -890,70 +1204,153 @@ function useMidpoints(venueMarkets) {
890
1204
  refetchOnWindowFocus: false,
891
1205
  refetchOnReconnect: false
892
1206
  });
893
- const result = useMemo7(() => {
894
- var _a, _b, _c, _d, _e, _f;
1207
+ const result = useMemo8(() => {
1208
+ var _a, _b, _c, _d, _e;
895
1209
  const map = /* @__PURE__ */ new Map();
896
1210
  const venueMap = /* @__PURE__ */ new Map();
897
1211
  if (!(data == null ? void 0 : data.data) || !venueMarkets) return { map, venueMap };
1212
+ const itemByMarketId = new Map(data.data.map((item) => [item.venueMarketId, item]));
898
1213
  for (const item of data.data) {
899
- if ((_a = item.outcomes) == null ? void 0 : _a.length) {
900
- for (const o of item.outcomes) {
901
- if (o.midpoint != null) {
902
- map.set(o.venueMarketOutcomeId, o.midpoint);
903
- if (item.venue) venueMap.set(o.venueMarketOutcomeId, item.venue);
904
- }
905
- }
906
- if ((_b = item.matched) == null ? void 0 : _b.length) {
907
- const market = venueMarkets.find((vm) => vm.id === item.venueMarketId);
908
- if (market) {
909
- const primaryYesOutcome = market.venueMarketOutcomes.find(
910
- (o) => {
911
- var _a2;
912
- return ((_a2 = o.label) == null ? void 0 : _a2.toLowerCase()) === "yes";
913
- }
914
- );
915
- const primaryYesMidpoint = primaryYesOutcome ? (_c = map.get(primaryYesOutcome.id)) != null ? _c : null : null;
916
- let bestMatchedMidpoint = null;
917
- let bestMatchedVenue = null;
918
- for (const m of item.matched) {
919
- if (m.midpoint == null) continue;
920
- if (bestMatchedMidpoint == null || m.midpoint < bestMatchedMidpoint) {
921
- bestMatchedMidpoint = m.midpoint;
922
- bestMatchedVenue = (_d = m.venue) != null ? _d : null;
923
- }
924
- }
925
- if (bestMatchedMidpoint != null && (primaryYesMidpoint == null || bestMatchedMidpoint < primaryYesMidpoint)) {
926
- for (const outcome of market.venueMarketOutcomes) {
927
- const isYes = ((_e = outcome.label) == null ? void 0 : _e.toLowerCase()) === "yes";
928
- map.set(outcome.id, isYes ? bestMatchedMidpoint : 1 - bestMatchedMidpoint);
929
- if (bestMatchedVenue) venueMap.set(outcome.id, bestMatchedVenue);
930
- }
931
- }
1214
+ if (!((_a = item.outcomes) == null ? void 0 : _a.length)) continue;
1215
+ for (const o of item.outcomes) {
1216
+ if (o.midpoint == null) continue;
1217
+ map.set(o.venueMarketOutcomeId, o.midpoint);
1218
+ if (item.venue) venueMap.set(o.venueMarketOutcomeId, item.venue);
1219
+ }
1220
+ }
1221
+ for (const market of venueMarkets) {
1222
+ const item = itemByMarketId.get(market.id);
1223
+ if (!item) continue;
1224
+ for (const outcome of market.venueMarketOutcomes) {
1225
+ const refs = (_b = outcome.matchedVenueMarketOutcomes) != null ? _b : [];
1226
+ if (!refs.length) continue;
1227
+ let best = (_c = map.get(outcome.id)) != null ? _c : null;
1228
+ let bestVenue = (_d = item.venue) != null ? _d : null;
1229
+ for (const ref of refs) {
1230
+ const sib = resolveSiblingOutcomeMidpoint(item.matched, ref);
1231
+ if (sib == null) continue;
1232
+ if (best == null || sib.midpoint < best) {
1233
+ best = sib.midpoint;
1234
+ bestVenue = (_e = sib.venue) != null ? _e : bestVenue;
932
1235
  }
933
1236
  }
934
- continue;
935
- }
936
- if (item.midpoint != null) {
937
- const market = venueMarkets.find((vm) => vm.id === item.venueMarketId);
938
- if (!market) continue;
939
- for (const outcome of market.venueMarketOutcomes) {
940
- const isYes = ((_f = outcome.label) == null ? void 0 : _f.toLowerCase()) === "yes";
941
- map.set(outcome.id, isYes ? item.midpoint : 1 - item.midpoint);
942
- if (item.venue) venueMap.set(outcome.id, item.venue);
1237
+ if (best != null) {
1238
+ map.set(outcome.id, best);
1239
+ if (bestVenue) venueMap.set(outcome.id, bestVenue);
943
1240
  }
944
1241
  }
945
1242
  }
946
1243
  return { map, venueMap };
947
1244
  }, [data, venueMarkets]);
1245
+ const { bestMidpoint, bestMidpointVenue } = useMemo8(() => {
1246
+ let value;
1247
+ let venue;
1248
+ for (const outcomeId of bestMidpointCandidateOutcomeIds) {
1249
+ const midpoint = result.map.get(outcomeId);
1250
+ if (midpoint == null) continue;
1251
+ if (value == null || midpoint < value) {
1252
+ value = midpoint;
1253
+ venue = result.venueMap.get(outcomeId);
1254
+ }
1255
+ }
1256
+ if (value == null) {
1257
+ for (const [outcomeId, midpoint] of result.map) {
1258
+ if (value == null || midpoint < value) {
1259
+ value = midpoint;
1260
+ venue = result.venueMap.get(outcomeId);
1261
+ }
1262
+ }
1263
+ }
1264
+ return { bestMidpoint: value, bestMidpointVenue: venue };
1265
+ }, [bestMidpointCandidateOutcomeIds, result.map, result.venueMap]);
1266
+ const { bestPrices, bestPriceVenuesByOutcomeId } = useMemo8(
1267
+ () => extractBestPrices(data == null ? void 0 : data.data, venueMarkets),
1268
+ [data == null ? void 0 : data.data, venueMarkets]
1269
+ );
948
1270
  return {
949
1271
  prices: result.map,
1272
+ bestMidpointsByOutcomeId: result.map,
950
1273
  venueByOutcomeId: result.venueMap,
951
- isLoading: isLoading && ids.length > 0
1274
+ bestPrices,
1275
+ bestPriceVenuesByOutcomeId,
1276
+ isLoading: isLoading && ids.length > 0,
1277
+ bestMidpoint,
1278
+ bestMidpointVenue
952
1279
  };
953
1280
  }
954
1281
 
1282
+ // src/use-tradable-venues.ts
1283
+ import { useMemo as useMemo9 } from "react";
1284
+ function useTradableVenues(venueMarkets) {
1285
+ const { prices, isLoading } = useMidpoints(venueMarkets);
1286
+ const tradableVenues = useMemo9(() => {
1287
+ var _a;
1288
+ if (isLoading) return null;
1289
+ if (!venueMarkets || venueMarkets.length === 0) return /* @__PURE__ */ new Set();
1290
+ const set = /* @__PURE__ */ new Set();
1291
+ for (const market of venueMarkets) {
1292
+ const outcomes = (_a = market.venueMarketOutcomes) != null ? _a : [];
1293
+ for (const outcome of outcomes) {
1294
+ if (prices.has(outcome.id)) {
1295
+ set.add(market.venue);
1296
+ break;
1297
+ }
1298
+ }
1299
+ }
1300
+ return set;
1301
+ }, [venueMarkets, prices, isLoading]);
1302
+ return { tradableVenues, isLoading };
1303
+ }
1304
+
1305
+ // src/use-rolling-chart-window.ts
1306
+ import { useEffect as useEffect5, useMemo as useMemo10, useState as useState4 } from "react";
1307
+ var RANGE_SECONDS_BY_RANGE = {
1308
+ "1H": 60 * 60,
1309
+ "6H": 6 * 60 * 60,
1310
+ "1D": 24 * 60 * 60,
1311
+ "1W": 7 * 24 * 60 * 60,
1312
+ "1M": 30 * 24 * 60 * 60,
1313
+ ALL: 6 * 30 * 24 * 60 * 60
1314
+ };
1315
+ var rangeToSeconds = (range) => RANGE_SECONDS_BY_RANGE[range];
1316
+ var resolveRollingWindow = (params) => {
1317
+ var _a;
1318
+ const interval = (_a = params.interval) != null ? _a : timeRangeToInterval(params.range);
1319
+ const intervalSeconds = getIntervalSeconds(interval);
1320
+ const rangeSeconds = rangeToSeconds(params.range);
1321
+ const endTs = Math.ceil(params.nowSec / intervalSeconds) * intervalSeconds;
1322
+ return {
1323
+ range: params.range,
1324
+ interval,
1325
+ rangeSeconds,
1326
+ intervalSeconds,
1327
+ nowSec: params.nowSec,
1328
+ endTs,
1329
+ startTs: endTs - rangeSeconds,
1330
+ refetchIntervalMs: intervalSeconds * 1e3
1331
+ };
1332
+ };
1333
+ var useRollingChartWindow = (options) => {
1334
+ var _a;
1335
+ const tickMs = (_a = options.tickMs) != null ? _a : 1e3;
1336
+ const optionsNowMs = options.nowMs;
1337
+ const nowMs = useMemo10(() => optionsNowMs != null ? optionsNowMs : (() => Date.now()), [optionsNowMs]);
1338
+ const [nowSec, setNowSec] = useState4(() => Math.floor(nowMs() / 1e3));
1339
+ useEffect5(() => {
1340
+ setNowSec(Math.floor(nowMs() / 1e3));
1341
+ const handle = setInterval(() => {
1342
+ setNowSec(Math.floor(nowMs() / 1e3));
1343
+ }, tickMs);
1344
+ return () => clearInterval(handle);
1345
+ }, [tickMs, nowMs]);
1346
+ return useMemo10(
1347
+ () => resolveRollingWindow({ range: options.range, nowSec, interval: options.interval }),
1348
+ [options.range, options.interval, nowSec]
1349
+ );
1350
+ };
1351
+
955
1352
  // src/use-market-orderbook.ts
956
- import { useQueries as useQueries3, useQueryClient } from "@tanstack/react-query";
1353
+ import { useQueries as useQueries4, useQueryClient } from "@tanstack/react-query";
957
1354
  function useMarketOrderbook(options) {
958
1355
  var _a, _b, _c, _d, _e, _f, _g;
959
1356
  const queryClient = useQueryClient();
@@ -973,7 +1370,7 @@ function useMarketOrderbook(options) {
973
1370
  enabled: enabled && !!selectedOutcomeId,
974
1371
  orderbook: true
975
1372
  });
976
- const liveQueries = useQueries3({
1373
+ const liveQueries = useQueries4({
977
1374
  queries: subscriptionIds.map((subscriptionId) => ({
978
1375
  queryKey: marketDataKeys.live(subscriptionId),
979
1376
  queryFn: () => createMarketLiveState(subscriptionId),
@@ -1039,7 +1436,7 @@ function useMarketOrderbook(options) {
1039
1436
  }
1040
1437
 
1041
1438
  // src/use-order-book.ts
1042
- import { keepPreviousData as keepPreviousData2, useQuery as useQuery3 } from "@tanstack/react-query";
1439
+ import { keepPreviousData as keepPreviousData3, useQuery as useQuery3 } from "@tanstack/react-query";
1043
1440
  function useOrderBook(options) {
1044
1441
  const client = useAggClient();
1045
1442
  const { orderbooks, enabled = true, canonicalMarketId } = options;
@@ -1065,7 +1462,7 @@ function useOrderBook(options) {
1065
1462
  gcTime: 5 * 6e4,
1066
1463
  refetchOnWindowFocus: false,
1067
1464
  retry: 1,
1068
- placeholderData: keepPreviousData2
1465
+ placeholderData: keepPreviousData3
1069
1466
  });
1070
1467
  const data = (() => {
1071
1468
  var _a, _b;
@@ -1120,7 +1517,7 @@ function useOrderBook(options) {
1120
1517
  }
1121
1518
 
1122
1519
  // src/use-orderbook-quote.ts
1123
- import { keepPreviousData as keepPreviousData3, useQuery as useQuery4 } from "@tanstack/react-query";
1520
+ import { keepPreviousData as keepPreviousData4, useQuery as useQuery4 } from "@tanstack/react-query";
1124
1521
  var QUOTE_DEBOUNCE_MS = 300;
1125
1522
  var createUnavailableOrderbookError = (message, code, retryable) => {
1126
1523
  const error = new Error(message);
@@ -1213,7 +1610,7 @@ function useOrderbookQuote(options) {
1213
1610
  staleTime: 1e4,
1214
1611
  gcTime: 5 * 6e4,
1215
1612
  retry: 1,
1216
- placeholderData: keepPreviousData3
1613
+ placeholderData: keepPreviousData4
1217
1614
  });
1218
1615
  return {
1219
1616
  data: (_a = query.data) != null ? _a : null,
@@ -1249,18 +1646,18 @@ function useOrders(options = {}) {
1249
1646
  import {
1250
1647
  QueryClient,
1251
1648
  QueryClientContext,
1252
- keepPreviousData as keepPreviousData4,
1649
+ keepPreviousData as keepPreviousData5,
1253
1650
  useInfiniteQuery as useInfiniteQuery5
1254
1651
  } from "@tanstack/react-query";
1255
- import { useContext as useContext2, useEffect as useEffect5, useState as useState4 } from "react";
1652
+ import { useContext as useContext2, useEffect as useEffect6, useState as useState5 } from "react";
1256
1653
  function useSearch(options) {
1257
1654
  var _a, _b, _c;
1258
1655
  const client = useContext2(AggClientContext);
1259
1656
  const queryClient = useContext2(QueryClientContext);
1260
- const [fallbackQueryClient] = useState4(() => new QueryClient());
1261
- const { q, type, categoryIds, limit = 20, enabled = true } = options;
1657
+ const [fallbackQueryClient] = useState5(() => new QueryClient());
1658
+ const { q, type, categoryIds, limit = 20, enabled = true, deep = false } = options;
1262
1659
  const isEnabled = enabled && q.length > 0;
1263
- useEffect5(() => {
1660
+ useEffect6(() => {
1264
1661
  if (queryClient) return void 0;
1265
1662
  fallbackQueryClient.mount();
1266
1663
  return () => {
@@ -1272,7 +1669,9 @@ function useSearch(options) {
1272
1669
  }
1273
1670
  const query = useInfiniteQuery5(
1274
1671
  {
1275
- queryKey: ["search", q, type, (_a = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _a : "", limit],
1672
+ // deep is part of the key TanStack treats deep vs light as
1673
+ // independent queries so users can have both modes cached side-by-side.
1674
+ queryKey: ["search", q, type, (_a = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _a : "", limit, deep],
1276
1675
  queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
1277
1676
  if (!client) {
1278
1677
  throw new Error("useSearch must be used within an <AggProvider>");
@@ -1282,7 +1681,8 @@ function useSearch(options) {
1282
1681
  type,
1283
1682
  categoryIds,
1284
1683
  limit,
1285
- cursor: pageParam
1684
+ cursor: pageParam,
1685
+ deep
1286
1686
  });
1287
1687
  return res;
1288
1688
  }),
@@ -1292,7 +1692,7 @@ function useSearch(options) {
1292
1692
  if (!lastPage.hasMore) return void 0;
1293
1693
  return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1294
1694
  },
1295
- placeholderData: keepPreviousData4,
1695
+ placeholderData: keepPreviousData5,
1296
1696
  enabled: isEnabled && !!client
1297
1697
  },
1298
1698
  queryClient != null ? queryClient : fallbackQueryClient
@@ -1310,8 +1710,95 @@ function useSearch(options) {
1310
1710
  };
1311
1711
  }
1312
1712
 
1713
+ // src/use-market-search.ts
1714
+ import { useCallback as useCallback5, useState as useState6 } from "react";
1715
+ function useMarketSearch(options) {
1716
+ var _a;
1717
+ const {
1718
+ type,
1719
+ categoryIds,
1720
+ limit = 20,
1721
+ debounceMs = 200,
1722
+ enableSuggestions = true,
1723
+ minLength = 1
1724
+ } = options;
1725
+ const [query, setQueryState] = useState6("");
1726
+ const [submittedQuery, setSubmittedQuery] = useState6(null);
1727
+ const debouncedQuery = useDebouncedValue(query, debounceMs);
1728
+ const trimmedDebounced = debouncedQuery.trim();
1729
+ const suggestionsEnabled = enableSuggestions && trimmedDebounced.length >= minLength;
1730
+ const suggestionsQuery = useSearch({
1731
+ q: trimmedDebounced,
1732
+ type,
1733
+ categoryIds,
1734
+ limit,
1735
+ enabled: suggestionsEnabled,
1736
+ deep: false
1737
+ });
1738
+ const submittedQ = (_a = submittedQuery == null ? void 0 : submittedQuery.trim()) != null ? _a : "";
1739
+ const resultsQuery = useSearch({
1740
+ q: submittedQ,
1741
+ type,
1742
+ categoryIds,
1743
+ limit,
1744
+ enabled: submittedQ.length > 0,
1745
+ deep: true
1746
+ });
1747
+ const setQuery = useCallback5((value) => {
1748
+ setQueryState(value);
1749
+ }, []);
1750
+ const submit = useCallback5(
1751
+ (q) => {
1752
+ const target = (q != null ? q : query).trim();
1753
+ if (target.length === 0) return;
1754
+ setSubmittedQuery(target);
1755
+ },
1756
+ [query]
1757
+ );
1758
+ const clear = useCallback5(() => {
1759
+ setQueryState("");
1760
+ setSubmittedQuery(null);
1761
+ }, []);
1762
+ return {
1763
+ /** Current input value (controlled). */
1764
+ query,
1765
+ /** Update the input value. Triggers the debounced typeahead. */
1766
+ setQuery,
1767
+ /** The query value that produced the current `results`, or null if none. */
1768
+ submittedQuery,
1769
+ /** Fire a deep search. Use this on Enter / Search button. */
1770
+ submit,
1771
+ /** Reset both input and results state. */
1772
+ clear,
1773
+ /**
1774
+ * Typeahead state. Backed by a light /search call (no reranker).
1775
+ * `data` is paginated like `useSearch.data` (flattened across pages).
1776
+ */
1777
+ suggestions: {
1778
+ data: suggestionsQuery.data,
1779
+ isLoading: suggestionsQuery.isLoading,
1780
+ isError: suggestionsQuery.isError,
1781
+ error: suggestionsQuery.error
1782
+ },
1783
+ /**
1784
+ * Full-page results state. Backed by a deep /search call (reranker on).
1785
+ * Cursor pagination is exposed via `fetchNextPage` / `hasNextPage`.
1786
+ */
1787
+ results: {
1788
+ data: resultsQuery.data,
1789
+ isLoading: resultsQuery.isLoading,
1790
+ isError: resultsQuery.isError,
1791
+ error: resultsQuery.error,
1792
+ hasNextPage: resultsQuery.hasNextPage,
1793
+ fetchNextPage: resultsQuery.fetchNextPage,
1794
+ isFetchingNextPage: resultsQuery.isFetchingNextPage
1795
+ }
1796
+ };
1797
+ }
1798
+
1313
1799
  // src/use-smart-route.ts
1314
- import { useQuery as useQuery6, keepPreviousData as keepPreviousData5 } from "@tanstack/react-query";
1800
+ import { keepPreviousData as keepPreviousData6, useQuery as useQuery6 } from "@tanstack/react-query";
1801
+ var SMART_ROUTE_STALE_TIME_MS = 2e4;
1315
1802
  function useSmartRoute(options) {
1316
1803
  var _a, _b;
1317
1804
  const client = useAggClient();
@@ -1326,7 +1813,9 @@ function useSmartRoute(options) {
1326
1813
  chainBalances,
1327
1814
  slipCapBps,
1328
1815
  compareVenues,
1329
- enabled = true
1816
+ deepEstimate,
1817
+ enabled = true,
1818
+ staleTimeMs = SMART_ROUTE_STALE_TIME_MS
1330
1819
  } = options;
1331
1820
  const resolvedVenueMarketOutcomeId = (_a = venueMarketOutcomeId != null ? venueMarketOutcomeId : venueMarketId) != null ? _a : outcomeId;
1332
1821
  const query = useQuery6({
@@ -1339,7 +1828,8 @@ function useSmartRoute(options) {
1339
1828
  sellShares != null ? sellShares : null,
1340
1829
  chainBalances ? JSON.stringify(chainBalances) : null,
1341
1830
  slipCapBps != null ? slipCapBps : null,
1342
- compareVenues != null ? compareVenues : false
1831
+ compareVenues != null ? compareVenues : false,
1832
+ deepEstimate != null ? deepEstimate : false
1343
1833
  ],
1344
1834
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
1345
1835
  return client.getSmartRoute(
@@ -1351,17 +1841,19 @@ function useSmartRoute(options) {
1351
1841
  sellShares,
1352
1842
  chainBalances,
1353
1843
  slipCapBps,
1354
- compareVenues
1844
+ compareVenues,
1845
+ deepEstimate
1355
1846
  },
1356
1847
  { signal }
1357
1848
  );
1358
1849
  }),
1359
1850
  enabled: enabled && !!resolvedVenueMarketOutcomeId && ((maxSpend != null ? maxSpend : 0) > 0 || (sellShares != null ? sellShares : 0) > 0),
1360
- staleTime: 1e4,
1851
+ staleTime: staleTimeMs,
1852
+ refetchInterval: staleTimeMs > 0 ? staleTimeMs : false,
1361
1853
  gcTime: 6e4,
1362
1854
  refetchOnWindowFocus: false,
1363
1855
  retry: 1,
1364
- placeholderData: keepPreviousData5
1856
+ placeholderData: keepPreviousData6
1365
1857
  });
1366
1858
  const error = query.error;
1367
1859
  return {
@@ -1405,7 +1897,7 @@ function useUserHoldings(options) {
1405
1897
  }
1406
1898
 
1407
1899
  // src/use-enriched-venue-event.ts
1408
- import { useMemo as useMemo8 } from "react";
1900
+ import { useMemo as useMemo11 } from "react";
1409
1901
 
1410
1902
  // src/use-venue-event.ts
1411
1903
  import { useQuery as useQuery7 } from "@tanstack/react-query";
@@ -1433,12 +1925,12 @@ function useVenueEvent(options) {
1433
1925
 
1434
1926
  // src/use-venue-markets.ts
1435
1927
  import { QueryClient as QueryClient2, QueryClientContext as QueryClientContext2, useInfiniteQuery as useInfiniteQuery7 } from "@tanstack/react-query";
1436
- import { useContext as useContext3, useEffect as useEffect6, useState as useState5 } from "react";
1928
+ import { useContext as useContext3, useEffect as useEffect7, useState as useState7 } from "react";
1437
1929
  function useVenueMarkets(options) {
1438
1930
  var _a, _b, _c, _d, _e;
1439
1931
  const client = useContext3(AggClientContext);
1440
1932
  const queryClient = useContext3(QueryClientContext2);
1441
- const [fallbackQueryClient] = useState5(() => new QueryClient2());
1933
+ const [fallbackQueryClient] = useState7(() => new QueryClient2());
1442
1934
  const venue = options == null ? void 0 : options.venue;
1443
1935
  const venueEventId = options == null ? void 0 : options.venueEventId;
1444
1936
  const search = options == null ? void 0 : options.search;
@@ -1449,7 +1941,7 @@ function useVenueMarkets(options) {
1449
1941
  const limit = (_b = options == null ? void 0 : options.limit) != null ? _b : 20;
1450
1942
  const sortBy = options == null ? void 0 : options.sortBy;
1451
1943
  const sortDir = options == null ? void 0 : options.sortDir;
1452
- useEffect6(() => {
1944
+ useEffect7(() => {
1453
1945
  if (queryClient) return void 0;
1454
1946
  fallbackQueryClient.mount();
1455
1947
  return () => {
@@ -1529,7 +2021,7 @@ function useEnrichedVenueEvent(options) {
1529
2021
  sortBy: "yesPrice",
1530
2022
  sortDir: "desc"
1531
2023
  });
1532
- const enrichedEvent = useMemo8(() => {
2024
+ const enrichedEvent = useMemo11(() => {
1533
2025
  if (!event) return void 0;
1534
2026
  if (markets.length === 0) return event;
1535
2027
  return mergeEventWithFullMarkets(event, markets);
@@ -1546,15 +2038,15 @@ function useEnrichedVenueEvent(options) {
1546
2038
  import {
1547
2039
  QueryClient as QueryClient3,
1548
2040
  QueryClientContext as QueryClientContext3,
1549
- keepPreviousData as keepPreviousData6,
2041
+ keepPreviousData as keepPreviousData7,
1550
2042
  useInfiniteQuery as useInfiniteQuery8
1551
2043
  } from "@tanstack/react-query";
1552
- import { useContext as useContext4, useEffect as useEffect7, useMemo as useMemo9, useRef as useRef3, useState as useState6 } from "react";
2044
+ import { useContext as useContext4, useEffect as useEffect8, useMemo as useMemo12, useRef as useRef4, useState as useState8 } from "react";
1553
2045
  function useVenueEvents(options) {
1554
2046
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1555
2047
  const client = useContext4(AggClientContext);
1556
2048
  const queryClient = useContext4(QueryClientContext3);
1557
- const [fallbackQueryClient] = useState6(() => new QueryClient3());
2049
+ const [fallbackQueryClient] = useState8(() => new QueryClient3());
1558
2050
  const venues = options == null ? void 0 : options.venues;
1559
2051
  const search = options == null ? void 0 : options.search;
1560
2052
  const categoryIds = options == null ? void 0 : options.categoryIds;
@@ -1569,7 +2061,7 @@ function useVenueEvents(options) {
1569
2061
  const maxYesPrice = options == null ? void 0 : options.maxYesPrice;
1570
2062
  const endDateFrom = options == null ? void 0 : options.endDateFrom;
1571
2063
  const initialPages = options == null ? void 0 : options.initialPages;
1572
- useEffect7(() => {
2064
+ useEffect8(() => {
1573
2065
  if (queryClient) return void 0;
1574
2066
  fallbackQueryClient.mount();
1575
2067
  return () => {
@@ -1622,13 +2114,13 @@ function useVenueEvents(options) {
1622
2114
  return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1623
2115
  },
1624
2116
  // TODO: RMIK - Comment out to show skeletons on category switch
1625
- placeholderData: keepPreviousData6,
2117
+ placeholderData: keepPreviousData7,
1626
2118
  enabled: enabled && !!client
1627
2119
  },
1628
2120
  queryClient != null ? queryClient : fallbackQueryClient
1629
2121
  );
1630
- const prefetchedRef = useRef3(false);
1631
- useEffect7(() => {
2122
+ const prefetchedRef = useRef4(false);
2123
+ useEffect8(() => {
1632
2124
  var _a2, _b2;
1633
2125
  if (prefetchedRef.current) return;
1634
2126
  if (!initialPages || initialPages <= 1) return;
@@ -1646,7 +2138,7 @@ function useVenueEvents(options) {
1646
2138
  query.hasNextPage,
1647
2139
  query.fetchNextPage
1648
2140
  ]);
1649
- const events = useMemo9(
2141
+ const events = useMemo12(
1650
2142
  () => {
1651
2143
  var _a2, _b2;
1652
2144
  return (_b2 = (_a2 = query.data) == null ? void 0 : _a2.pages.flatMap((page) => page.data)) != null ? _b2 : [];
@@ -1664,7 +2156,7 @@ function useVenueEvents(options) {
1664
2156
  }
1665
2157
 
1666
2158
  // src/use-venue-market-midpoints.ts
1667
- import { keepPreviousData as keepPreviousData7, useQuery as useQuery8 } from "@tanstack/react-query";
2159
+ import { keepPreviousData as keepPreviousData8, useQuery as useQuery8 } from "@tanstack/react-query";
1668
2160
  var MAX_VENUE_MARKET_IDS_PER_REQUEST = 200;
1669
2161
  var normalizeVenueMarketIds2 = (venueMarketIds) => {
1670
2162
  return [
@@ -1709,7 +2201,7 @@ function useVenueMarketMidpoints(options) {
1709
2201
  }
1710
2202
  const chunkResponses = yield Promise.all(
1711
2203
  venueMarketIdChunks.map((venueMarketIds) => {
1712
- return client.getMidpoints({ venueMarketIds }, { signal });
2204
+ return client.getMidpoints({ venueMarketIds, bestPrice: true }, { signal });
1713
2205
  })
1714
2206
  );
1715
2207
  return mergeMidpointResponses(chunkResponses);
@@ -1719,7 +2211,7 @@ function useVenueMarketMidpoints(options) {
1719
2211
  gcTime: 5 * 6e4,
1720
2212
  refetchOnWindowFocus: false,
1721
2213
  retry: 1,
1722
- placeholderData: keepPreviousData7
2214
+ placeholderData: keepPreviousData8
1723
2215
  });
1724
2216
  const midpointRows = (_c = (_b = query.data) == null ? void 0 : _b.data) != null ? _c : [];
1725
2217
  const midpointsByVenueMarketId = mapMidpointsByVenueMarketId(midpointRows);
@@ -1754,60 +2246,68 @@ function computePriceGaps(input) {
1754
2246
  }
1755
2247
 
1756
2248
  // src/use-viewport-midpoints.ts
1757
- import { useEffect as useEffect8, useMemo as useMemo10, useRef as useRef4, useState as useState7 } from "react";
1758
- var normalizeOutcomeLabel = (value) => value.trim().toLowerCase();
1759
- var resolveYesMidpoint = (outcomes) => {
1760
- if (!(outcomes == null ? void 0 : outcomes.length)) return void 0;
1761
- const yesOutcome = outcomes.find((outcome) => normalizeOutcomeLabel(outcome.label) === "yes");
1762
- return yesOutcome == null ? void 0 : yesOutcome.midpoint;
2249
+ import { useEffect as useEffect9, useMemo as useMemo13, useRef as useRef5, useState as useState9 } from "react";
2250
+ var buildOutcomeMidpointMap = (outcomes) => {
2251
+ const m = /* @__PURE__ */ new Map();
2252
+ if (!outcomes) return m;
2253
+ for (const o of outcomes) {
2254
+ if (o.midpoint != null) m.set(o.venueMarketOutcomeId, o.midpoint);
2255
+ }
2256
+ return m;
1763
2257
  };
1764
2258
  var resolveUncachedVisibleMarketIds = (visibleMarkets, cache, inFlightIds) => {
2259
+ var _a;
2260
+ const seen = /* @__PURE__ */ new Set();
1765
2261
  const idsToFetch = [];
2262
+ const consider = (id) => {
2263
+ if (!id) return;
2264
+ if (seen.has(id)) return;
2265
+ if (inFlightIds.has(id)) return;
2266
+ if (cache.has(id)) return;
2267
+ seen.add(id);
2268
+ idsToFetch.push(id);
2269
+ };
1766
2270
  for (const market of visibleMarkets) {
1767
- if (inFlightIds.has(market.id)) continue;
1768
- if (cache.has(market.id)) continue;
1769
- idsToFetch.push(market.id);
2271
+ consider(market.id);
2272
+ for (const sibling of (_a = market.matchedVenueMarkets) != null ? _a : []) {
2273
+ consider(sibling.id);
2274
+ }
1770
2275
  }
1771
2276
  return idsToFetch;
1772
2277
  };
1773
2278
  var buildCachedMidpointEntries = (requestedVenueMarketIds, rows) => {
1774
- var _a, _b, _c;
2279
+ var _a;
1775
2280
  const rowsByVenueMarketId = new Map(rows.map((item) => [item.venueMarketId, item]));
1776
2281
  const nextCacheEntries = /* @__PURE__ */ new Map();
1777
2282
  for (const venueMarketId of requestedVenueMarketIds) {
1778
2283
  const item = rowsByVenueMarketId.get(venueMarketId);
1779
- const yesMidpoint = resolveYesMidpoint(item == null ? void 0 : item.outcomes);
1780
2284
  nextCacheEntries.set(venueMarketId, __spreadProps(__spreadValues({}, (item == null ? void 0 : item.venue) ? { venue: item.venue } : {}), {
1781
- midpoint: (_a = yesMidpoint != null ? yesMidpoint : item == null ? void 0 : item.midpoint) != null ? _a : null,
1782
- spread: (_b = item == null ? void 0 : item.spread) != null ? _b : null,
1783
- matched: ((_c = item == null ? void 0 : item.matched) != null ? _c : []).map((matched) => {
1784
- var _a2, _b2;
1785
- return __spreadValues({
1786
- venueMarketId: matched.venueMarketId,
1787
- midpoint: (_a2 = matched.midpoint) != null ? _a2 : null,
1788
- spread: (_b2 = matched.spread) != null ? _b2 : null
1789
- }, matched.venue ? { venue: matched.venue } : {});
1790
- })
2285
+ ownOutcomes: buildOutcomeMidpointMap(item == null ? void 0 : item.outcomes),
2286
+ matched: ((_a = item == null ? void 0 : item.matched) != null ? _a : []).map((sib) => __spreadProps(__spreadValues({
2287
+ venueMarketId: sib.venueMarketId
2288
+ }, sib.venue ? { venue: sib.venue } : {}), {
2289
+ outcomes: buildOutcomeMidpointMap(sib.outcomes)
2290
+ }))
1791
2291
  }));
1792
2292
  }
1793
2293
  return nextCacheEntries;
1794
2294
  };
1795
2295
  function useViewportMidpoints(visibleMarkets) {
1796
2296
  const client = useAggClient();
1797
- const [cache, setCache] = useState7(() => /* @__PURE__ */ new Map());
1798
- const inFlightRef = useRef4(/* @__PURE__ */ new Set());
1799
- const visibleRef = useRef4(visibleMarkets);
2297
+ const [cache, setCache] = useState9(() => /* @__PURE__ */ new Map());
2298
+ const inFlightRef = useRef5(/* @__PURE__ */ new Set());
2299
+ const visibleRef = useRef5(visibleMarkets);
1800
2300
  visibleRef.current = visibleMarkets;
1801
- const visibleFp = useMemo10(
2301
+ const visibleFp = useMemo13(
1802
2302
  () => [...new Set(visibleMarkets.map((m) => m.id))].sort().join("|"),
1803
2303
  [visibleMarkets]
1804
2304
  );
1805
- useEffect8(() => {
2305
+ useEffect9(() => {
1806
2306
  const toFetch = resolveUncachedVisibleMarketIds(visibleRef.current, cache, inFlightRef.current);
1807
2307
  if (!toFetch.length) return;
1808
2308
  let cancelled = false;
1809
2309
  for (const id of toFetch) inFlightRef.current.add(id);
1810
- client.getMidpoints(toFetch).then((resp) => {
2310
+ client.getMidpoints(toFetch, { bestPrice: true }).then((resp) => {
1811
2311
  var _a;
1812
2312
  if (cancelled) return;
1813
2313
  const nextCacheEntries = buildCachedMidpointEntries(toFetch, (_a = resp.data) != null ? _a : []);
@@ -1826,29 +2326,31 @@ function useViewportMidpoints(visibleMarkets) {
1826
2326
  cancelled = true;
1827
2327
  };
1828
2328
  }, [visibleFp, cache]);
1829
- const { prices, venueByOutcomeId } = useMemo10(() => {
1830
- var _a, _b, _c, _d, _e, _f;
2329
+ const { prices, venueByOutcomeId } = useMemo13(() => {
2330
+ var _a, _b, _c, _d;
1831
2331
  const map = /* @__PURE__ */ new Map();
1832
2332
  const venueMap = /* @__PURE__ */ new Map();
1833
2333
  for (const market of visibleMarkets) {
1834
2334
  const entry = cache.get(market.id);
1835
2335
  if (!entry) continue;
1836
- let mid = entry.midpoint;
1837
- let midVenue = (_a = entry.venue) != null ? _a : market.venue;
1838
- for (const m of entry.matched) {
1839
- const matchedFromCache = (_b = cache.get(m.venueMarketId)) == null ? void 0 : _b.midpoint;
1840
- const candidateMidpoint = matchedFromCache != null ? matchedFromCache : m.midpoint;
1841
- if (candidateMidpoint == null) continue;
1842
- if (mid == null || candidateMidpoint < mid) {
1843
- mid = candidateMidpoint;
1844
- midVenue = (_e = (_d = (_c = cache.get(m.venueMarketId)) == null ? void 0 : _c.venue) != null ? _d : m.venue) != null ? _e : market.venue;
1845
- }
1846
- }
1847
- if (mid == null) continue;
2336
+ const ownVenue = (_a = entry.venue) != null ? _a : market.venue;
1848
2337
  for (const outcome of market.venueMarketOutcomes) {
1849
- const isYes = ((_f = outcome.label) == null ? void 0 : _f.toLowerCase()) === "yes";
1850
- map.set(outcome.id, isYes ? mid : 1 - mid);
1851
- venueMap.set(outcome.id, midVenue);
2338
+ let best = (_b = entry.ownOutcomes.get(outcome.id)) != null ? _b : null;
2339
+ let bestVenue = best != null ? ownVenue : null;
2340
+ for (const ref of (_c = outcome.matchedVenueMarketOutcomes) != null ? _c : []) {
2341
+ const sib = entry.matched.find((m) => m.venueMarketId === ref.venueMarketId);
2342
+ if (!sib) continue;
2343
+ const sibMidpoint = sib.outcomes.get(ref.venueMarketOutcomeId);
2344
+ if (sibMidpoint == null) continue;
2345
+ if (best == null || sibMidpoint < best) {
2346
+ best = sibMidpoint;
2347
+ bestVenue = (_d = sib.venue) != null ? _d : bestVenue;
2348
+ }
2349
+ }
2350
+ if (best != null) {
2351
+ map.set(outcome.id, best);
2352
+ if (bestVenue) venueMap.set(outcome.id, bestVenue);
2353
+ }
1852
2354
  }
1853
2355
  }
1854
2356
  return { prices: map, venueByOutcomeId: venueMap };
@@ -1857,15 +2359,15 @@ function useViewportMidpoints(visibleMarkets) {
1857
2359
  }
1858
2360
 
1859
2361
  // src/use-visible-ids.ts
1860
- import { useCallback as useCallback5, useEffect as useEffect9, useRef as useRef5, useState as useState8 } from "react";
2362
+ import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef6, useState as useState10 } from "react";
1861
2363
  function useVisibleIds(options = {}) {
1862
2364
  const { rootMargin = "0px", threshold = 0 } = options;
1863
- const [visibleIds, setVisibleIds] = useState8(() => /* @__PURE__ */ new Set());
1864
- const observerRef = useRef5(null);
1865
- const elementsRef = useRef5(/* @__PURE__ */ new Map());
1866
- const elementIdRef = useRef5(/* @__PURE__ */ new WeakMap());
1867
- const callbackRefsRef = useRef5(/* @__PURE__ */ new Map());
1868
- useEffect9(() => {
2365
+ const [visibleIds, setVisibleIds] = useState10(() => /* @__PURE__ */ new Set());
2366
+ const observerRef = useRef6(null);
2367
+ const elementsRef = useRef6(/* @__PURE__ */ new Map());
2368
+ const elementIdRef = useRef6(/* @__PURE__ */ new WeakMap());
2369
+ const callbackRefsRef = useRef6(/* @__PURE__ */ new Map());
2370
+ useEffect10(() => {
1869
2371
  if (typeof IntersectionObserver === "undefined") return;
1870
2372
  const observer = new IntersectionObserver(
1871
2373
  (entries) => {
@@ -1897,7 +2399,7 @@ function useVisibleIds(options = {}) {
1897
2399
  observerRef.current = null;
1898
2400
  };
1899
2401
  }, [rootMargin, threshold]);
1900
- const register = useCallback5((id) => {
2402
+ const register = useCallback6((id) => {
1901
2403
  const existing = callbackRefsRef.current.get(id);
1902
2404
  if (existing) return existing;
1903
2405
  const callback = (el) => {
@@ -1933,7 +2435,7 @@ function useVisibleIds(options = {}) {
1933
2435
  import { useQuery as useQuery9 } from "@tanstack/react-query";
1934
2436
  var FIVE_MINUTES = 5 * 60 * 1e3;
1935
2437
  function useAppConfig() {
1936
- var _a, _b, _c, _d, _e, _f;
2438
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1937
2439
  const client = useAggClient();
1938
2440
  const query = useQuery9({
1939
2441
  queryKey: ["agg", "app-config"],
@@ -1944,6 +2446,7 @@ function useAppConfig() {
1944
2446
  disabledVenues: (_b = (_a = query.data) == null ? void 0 : _a.disabledVenues) != null ? _b : [],
1945
2447
  disabledCategoryPresets: (_d = (_c = query.data) == null ? void 0 : _c.disabledCategoryPresets) != null ? _d : [],
1946
2448
  earlyAccessEnabled: (_f = (_e = query.data) == null ? void 0 : _e.earlyAccessEnabled) != null ? _f : false,
2449
+ authOptions: (_h = (_g = query.data) == null ? void 0 : _g.authOptions) != null ? _h : [],
1947
2450
  isLoading: query.isLoading,
1948
2451
  error: query.error
1949
2452
  };
@@ -1963,6 +2466,8 @@ export {
1963
2466
  MatchType,
1964
2467
  QueryClient4 as QueryClient,
1965
2468
  QueryClientProvider,
2469
+ RedeemRejectedError,
2470
+ TradeSide,
1966
2471
  TurnstileChallengeError,
1967
2472
  Venue,
1968
2473
  computeClosedPositionTotals,
@@ -1977,9 +2482,13 @@ export {
1977
2482
  getWalletAddressFromUserProfile,
1978
2483
  invalidateBalanceQueries,
1979
2484
  invalidatePositionQueries,
2485
+ invalidateUserActivityQueries,
2486
+ invalidateUserMoneyState,
2487
+ mergeBestPricesPreferringLive,
1980
2488
  optimizedImageUrl,
1981
2489
  parseEmail,
1982
2490
  parseEmailStrict,
2491
+ rangeToSeconds,
1983
2492
  requestAggAuthChooserOpen,
1984
2493
  resolveAggUiLabels,
1985
2494
  resolveDefaultMarket as resolveDefaultTradingMarket,
@@ -1987,6 +2496,7 @@ export {
1987
2496
  resolveMarketTradingState,
1988
2497
  resolveMarketWinningOutcome,
1989
2498
  resolveOrderEligibility,
2499
+ resolveRollingWindow,
1990
2500
  resolveTradingStateKind,
1991
2501
  sortVenues,
1992
2502
  timeRangeToInterval,
@@ -2017,6 +2527,7 @@ export {
2017
2527
  useGeoBlock,
2018
2528
  useLabels,
2019
2529
  useLinkAccount,
2530
+ useLiveBestPrices,
2020
2531
  useLiveCandleOverlay,
2021
2532
  useLiveCandles,
2022
2533
  useLiveMarket,
@@ -2026,6 +2537,7 @@ export {
2026
2537
  useManagedBalances,
2027
2538
  useMarketChart,
2028
2539
  useMarketOrderbook,
2540
+ useMarketSearch,
2029
2541
  useMidpoints,
2030
2542
  useOnBalanceUpdate,
2031
2543
  useOnOrderSubmitted,
@@ -2041,11 +2553,15 @@ export {
2041
2553
  useRampSession,
2042
2554
  useRedeem,
2043
2555
  useRedeemEligibleCount,
2556
+ useRedeemLifecycle,
2557
+ useRedeemLifecycles,
2558
+ useRollingChartWindow,
2044
2559
  useSdkLabels,
2045
2560
  useSdkUiConfig,
2046
2561
  useSearch,
2047
2562
  useSmartRoute,
2048
2563
  useSyncBalances,
2564
+ useTradableVenues,
2049
2565
  useUserActivity,
2050
2566
  useUserHoldings,
2051
2567
  useVenueEvent,
@@ -2054,7 +2570,9 @@ export {
2054
2570
  useVenueMarkets,
2055
2571
  useViewportMidpoints,
2056
2572
  useVisibleIds,
2573
+ useWithdrawEstimate,
2057
2574
  useWithdrawFlow,
2058
2575
  useWithdrawManaged,
2059
- useWithdrawalLifecycle
2576
+ useWithdrawalLifecycle,
2577
+ userActivityQueryKeys
2060
2578
  };