@agg-build/hooks 4.17.2 → 4.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  useRampQuotes,
3
3
  useRampSession
4
- } from "./chunk-BBAKQDOH.mjs";
4
+ } from "./chunk-SBGLJDPJ.mjs";
5
5
  import {
6
6
  useWithdrawEstimate,
7
7
  useWithdrawFlow,
8
8
  useWithdrawPreview,
9
9
  useWithdrawalLifecycle
10
- } from "./chunk-IVUHIMRY.mjs";
10
+ } from "./chunk-5B2F3GMC.mjs";
11
11
  import {
12
12
  AggAuthContext,
13
13
  AggBalanceProvider,
@@ -26,20 +26,17 @@ import {
26
26
  Venue,
27
27
  __async,
28
28
  __objRest,
29
+ __pow,
29
30
  __spreadProps,
30
31
  __spreadValues,
31
32
  appConfigQueryKey,
32
- applyOrderbookDepth,
33
33
  computeClosedPositionTotals,
34
- createMarketChartData,
35
34
  createMarketLiveState,
36
- createMarketOrderbookDataFromState,
37
- createMarketOrderbookDataFromVenueOrderbooks,
38
35
  defaultAggUiConfig,
39
36
  executionKeys,
40
37
  getBuilder,
41
38
  getDepositAddress,
42
- getIntervalSeconds,
39
+ getMarketLiveStore,
43
40
  getOrCreateBuilder,
44
41
  getWalletAddressFromUserProfile,
45
42
  invalidateBalanceQueries,
@@ -48,8 +45,6 @@ import {
48
45
  invalidateUserClaimState,
49
46
  invalidateUserMoneyState,
50
47
  marketDataKeys,
51
- marketOrderbookDataToResponse,
52
- mergeMarketChartData,
53
48
  optimizedImageUrl,
54
49
  parseEmail,
55
50
  parseEmailStrict,
@@ -60,6 +55,7 @@ import {
60
55
  resolveMarketWinningOutcome,
61
56
  resolveOrderEligibility,
62
57
  resolveTradingStateKind,
58
+ retinaImageUrl,
63
59
  sortVenues,
64
60
  tradingReducer,
65
61
  useAggAuthContext,
@@ -82,6 +78,7 @@ import {
82
78
  useExecuteManaged,
83
79
  useExecutionProgress,
84
80
  useLabels,
81
+ useLiveStates,
85
82
  useManagedBalances,
86
83
  useOnBalanceUpdate,
87
84
  useOnOrderEvent,
@@ -101,10 +98,10 @@ import {
101
98
  useSyncBalances,
102
99
  useWithdrawManaged,
103
100
  userActivityQueryKeys
104
- } from "./chunk-KQ5TOPNY.mjs";
101
+ } from "./chunk-ESDA4NZI.mjs";
105
102
 
106
103
  // src/index.ts
107
- import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
104
+ import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient5 } from "@tanstack/react-query";
108
105
  import { TurnstileChallengeError } from "@agg-build/sdk";
109
106
 
110
107
  // src/use-geo-block.ts
@@ -170,9 +167,113 @@ var useVenueKeyStatus = (venue, enabled = true) => {
170
167
  });
171
168
  };
172
169
 
170
+ // src/use-hosted-venue-account.ts
171
+ import { useEffect, useRef } from "react";
172
+ import { useMutation, useQuery as useQuery2, useQueryClient } from "@tanstack/react-query";
173
+ var hostedVenueAccountQueryKeys = {
174
+ all: ["agg", "hosted-venue-account"],
175
+ account: (venue, userId, mode) => ["agg", "hosted-venue-account", venue, userId, mode]
176
+ };
177
+ function useHostedVenueAccount(venue, enabled = true) {
178
+ var _a;
179
+ const client = useAggClient();
180
+ const { user, isAuthenticated } = useAggAuthContext();
181
+ const { executionMode, isResolving } = useResolvedExecutionMode();
182
+ const queryClient = useQueryClient();
183
+ const userId = (_a = user == null ? void 0 : user.id) != null ? _a : null;
184
+ const permitted = enabled && isAuthenticated && userId !== null && !isResolving && executionMode === "live";
185
+ const queryKey = hostedVenueAccountQueryKeys.account(venue, userId, executionMode);
186
+ const session = useRef({ client, userId, executionMode, permitted });
187
+ session.current = { client, userId, executionMode, permitted };
188
+ const assertSession = () => {
189
+ const current = session.current;
190
+ if (!permitted || !current.permitted || current.client !== client || current.userId !== userId || current.executionMode !== executionMode)
191
+ throw new Error("Hosted custody is unavailable for this session");
192
+ };
193
+ const account = useQuery2({
194
+ queryKey,
195
+ queryFn: () => {
196
+ assertSession();
197
+ return client.getHostedVenueAccount(venue, { mode: executionMode });
198
+ },
199
+ enabled: permitted,
200
+ staleTime: 3e3,
201
+ refetchInterval: permitted ? 5e3 : false,
202
+ refetchIntervalInBackground: false,
203
+ retry: false
204
+ });
205
+ const provision = useMutation({
206
+ mutationFn: (request2) => request2.run(),
207
+ // Retain the dispatch-time user key even if the observer changes users.
208
+ onSuccess: (result, request2) => {
209
+ queryClient.setQueryData(request2.queryKey, result);
210
+ invalidateBalanceQueries(queryClient);
211
+ },
212
+ retry: false
213
+ });
214
+ const { reset } = provision;
215
+ useEffect(() => {
216
+ reset();
217
+ }, [userId, executionMode, reset]);
218
+ const request = () => ({
219
+ queryKey,
220
+ run: () => {
221
+ assertSession();
222
+ return client.provisionHostedVenueAccount(venue, { mode: "live" });
223
+ }
224
+ });
225
+ return {
226
+ account,
227
+ provision: __spreadProps(__spreadValues({}, provision), {
228
+ mutate: () => provision.mutate(request()),
229
+ mutateAsync: () => provision.mutateAsync(request())
230
+ }),
231
+ isAvailable: permitted
232
+ };
233
+ }
234
+
235
+ // src/use-hosted-venue-activity.ts
236
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
237
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
238
+ function useHostedVenueActivity(venue, page = 0, enabled = true) {
239
+ var _a;
240
+ const client = useAggClient();
241
+ const { user, isAuthenticated } = useAggAuthContext();
242
+ const { executionMode, isResolving } = useResolvedExecutionMode();
243
+ const userId = (_a = user == null ? void 0 : user.id) != null ? _a : null;
244
+ const permitted = enabled && isAuthenticated && userId !== null && !isResolving && executionMode === "live" && Number.isInteger(page) && page >= 0 && page <= 9999;
245
+ const session = useRef2({ client, userId, executionMode, permitted });
246
+ session.current = { client, userId, executionMode, permitted };
247
+ const mounted = useRef2(true);
248
+ useEffect2(() => {
249
+ mounted.current = true;
250
+ return () => {
251
+ mounted.current = false;
252
+ };
253
+ }, []);
254
+ const assertSession = () => {
255
+ const current = session.current;
256
+ if (!mounted.current || !permitted || !current.permitted || current.client !== client || current.userId !== userId || current.executionMode !== executionMode)
257
+ throw new Error("Hosted activity is unavailable for this session");
258
+ };
259
+ const activity = useQuery3({
260
+ queryKey: [...hostedVenueAccountQueryKeys.all, "activity", venue, userId, executionMode, page],
261
+ queryFn: () => __async(null, null, function* () {
262
+ assertSession();
263
+ const result = yield client.getHostedVenueActivity(venue, { mode: executionMode, page });
264
+ assertSession();
265
+ return result;
266
+ }),
267
+ enabled: permitted,
268
+ staleTime: 3e3,
269
+ retry: false
270
+ });
271
+ return { activity, isAvailable: permitted };
272
+ }
273
+
173
274
  // src/use-shared-kyc.ts
174
275
  import { useCallback } from "react";
175
- import { useQuery as useQuery2 } from "@tanstack/react-query";
276
+ import { useQuery as useQuery4 } from "@tanstack/react-query";
176
277
  var sharedKycQueryKeys = {
177
278
  status: (userId) => ["agg", "shared-kyc", userId]
178
279
  };
@@ -181,7 +282,7 @@ var useSharedKyc = () => {
181
282
  const client = useAggClient();
182
283
  const { isAuthenticated, user } = useAggAuthContext();
183
284
  const userId = (_a = user == null ? void 0 : user.id) != null ? _a : null;
184
- const query = useQuery2({
285
+ const query = useQuery4({
185
286
  queryKey: sharedKycQueryKeys.status(userId),
186
287
  queryFn: () => client.getSharedKycStatus(),
187
288
  enabled: isAuthenticated && userId !== null,
@@ -340,10 +441,10 @@ function useCategoryChildren(options) {
340
441
  }
341
442
 
342
443
  // src/use-debounced-value.ts
343
- import { useEffect, useState as useState2 } from "react";
444
+ import { useEffect as useEffect3, useState as useState2 } from "react";
344
445
  function useDebouncedValue(value, delay) {
345
446
  const [debouncedValue, setDebouncedValue] = useState2(value);
346
- useEffect(() => {
447
+ useEffect3(() => {
347
448
  const timeoutId = window.setTimeout(() => {
348
449
  setDebouncedValue(value);
349
450
  }, delay);
@@ -364,11 +465,13 @@ function useExecutionOrders(options = {}) {
364
465
  orderType,
365
466
  orderId,
366
467
  quoteId,
468
+ venueMarketIds,
367
469
  mode,
368
470
  limit = 50,
369
471
  enabled = true,
370
472
  refetchIntervalMs = false
371
473
  } = options;
474
+ const venueMarketIdsKey = (venueMarketIds == null ? void 0 : venueMarketIds.length) ? [...new Set(venueMarketIds)].sort() : null;
372
475
  const query = useInfiniteQuery2({
373
476
  // quoteId + orderId are part of the cache key — different filters
374
477
  // produce different result sets, so they have to vary the key.
@@ -377,16 +480,17 @@ function useExecutionOrders(options = {}) {
377
480
  status != null ? status : "all",
378
481
  quoteId != null ? quoteId : null,
379
482
  orderId != null ? orderId : null,
483
+ ...venueMarketIdsKey ? [{ venueMarketIds: venueMarketIdsKey }] : [],
380
484
  ...orderType ? [orderType] : [],
381
485
  ...mode ? [mode] : [],
382
486
  limit
383
487
  ],
384
- queryFn: ({ pageParam }) => client.getExecutionOrders(__spreadProps(__spreadValues({
488
+ queryFn: ({ pageParam }) => client.getExecutionOrders(__spreadProps(__spreadValues(__spreadValues({
385
489
  status,
386
490
  orderType,
387
491
  orderId,
388
492
  quoteId
389
- }, mode ? { mode } : {}), {
493
+ }, venueMarketIdsKey ? { venueMarketIds: venueMarketIdsKey } : {}), mode ? { mode } : {}), {
390
494
  limit,
391
495
  cursor: pageParam
392
496
  })),
@@ -406,6 +510,85 @@ function useExecutionOrders(options = {}) {
406
510
  });
407
511
  }
408
512
 
513
+ // src/use-execution-orders-for-markets.ts
514
+ import { useQueries as useQueries2 } from "@tanstack/react-query";
515
+ import { useMemo } from "react";
516
+ var MAX_ORDER_VENUE_MARKET_IDS_PER_REQUEST = 75;
517
+ var DEFAULT_PAGE_LIMIT = 100;
518
+ var DEFAULT_MAX_PAGES_PER_BATCH = 5;
519
+ var combineBatches = (results) => {
520
+ var _a, _b;
521
+ return {
522
+ orders: results.flatMap((result) => {
523
+ var _a2, _b2;
524
+ return (_b2 = (_a2 = result.data) == null ? void 0 : _a2.orders) != null ? _b2 : [];
525
+ }),
526
+ isLoading: results.some((result) => result.isLoading),
527
+ error: (_b = (_a = results.find((result) => result.error)) == null ? void 0 : _a.error) != null ? _b : null,
528
+ isTruncated: results.some((result) => {
529
+ var _a2;
530
+ return ((_a2 = result.data) == null ? void 0 : _a2.hasMore) === true;
531
+ })
532
+ };
533
+ };
534
+ var chunk = (items, size) => {
535
+ const chunks = [];
536
+ for (let index = 0; index < items.length; index += size) {
537
+ chunks.push(items.slice(index, index + size));
538
+ }
539
+ return chunks;
540
+ };
541
+ function useExecutionOrdersForMarkets({
542
+ venueMarketIds,
543
+ status,
544
+ orderType,
545
+ mode,
546
+ limit = DEFAULT_PAGE_LIMIT,
547
+ maxPagesPerBatch = DEFAULT_MAX_PAGES_PER_BATCH,
548
+ enabled = true
549
+ }) {
550
+ const client = useAggClient();
551
+ const batchKey = [...new Set(venueMarketIds)].sort().join(",");
552
+ const batches = useMemo(
553
+ () => batchKey ? chunk(batchKey.split(","), MAX_ORDER_VENUE_MARKET_IDS_PER_REQUEST) : [],
554
+ [batchKey]
555
+ );
556
+ return useQueries2({
557
+ combine: combineBatches,
558
+ queries: batches.map((batchVenueMarketIds) => ({
559
+ queryKey: [
560
+ "execution-orders",
561
+ "by-markets",
562
+ batchVenueMarketIds,
563
+ status != null ? status : "all",
564
+ orderType != null ? orderType : null,
565
+ mode != null ? mode : null,
566
+ limit,
567
+ maxPagesPerBatch
568
+ ],
569
+ queryFn: () => __async(null, null, function* () {
570
+ var _a;
571
+ const orders = [];
572
+ let cursor;
573
+ for (let page = 0; page < maxPagesPerBatch; page += 1) {
574
+ const response = yield client.getExecutionOrders(__spreadValues(__spreadProps(__spreadValues({
575
+ venueMarketIds: batchVenueMarketIds,
576
+ status,
577
+ orderType
578
+ }, mode ? { mode } : {}), {
579
+ limit
580
+ }), cursor ? { cursor } : {}));
581
+ orders.push(...response.data);
582
+ cursor = response.hasMore ? (_a = response.nextCursor) != null ? _a : void 0 : void 0;
583
+ if (!cursor) return { orders, hasMore: false };
584
+ }
585
+ return { orders, hasMore: true };
586
+ }),
587
+ enabled
588
+ }))
589
+ });
590
+ }
591
+
409
592
  // src/use-user-activity.ts
410
593
  import { keepPreviousData, useInfiniteQuery as useInfiniteQuery3 } from "@tanstack/react-query";
411
594
  var DEFAULT_PENDING_REFETCH_INTERVAL_MS = 15e3;
@@ -532,17 +715,376 @@ function useExecutionPositions(options = {}) {
532
715
  }
533
716
 
534
717
  // src/use-live-candle-overlay.ts
535
- import { useCallback as useCallback5, useMemo as useMemo4 } from "react";
718
+ import { useCallback as useCallback5, useMemo as useMemo5 } from "react";
536
719
 
537
720
  // src/use-live-candles.ts
538
- import { useMemo as useMemo3 } from "react";
721
+ import { useMemo as useMemo4 } from "react";
539
722
  import { mergeCandles, mergeClosedCandles } from "@agg-build/sdk";
540
723
 
541
724
  // src/use-market-chart.ts
542
- import { keepPreviousData as keepPreviousData2, useQueries as useQueries2 } from "@tanstack/react-query";
725
+ import { keepPreviousData as keepPreviousData2, useQueries as useQueries3, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
726
+
727
+ // src/read-retry.ts
728
+ import { isAggApiError } from "@agg-build/sdk";
729
+ import { isServer } from "@tanstack/react-query";
730
+ var MAX_TIMER_DELAY_MS = 2147483647;
731
+ var hint = (error) => {
732
+ if (!isAggApiError(error)) return void 0;
733
+ const value = error.retryAfterMs;
734
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
735
+ };
736
+ function withReadRetry(options) {
737
+ return {
738
+ retry: (failureCount, error) => {
739
+ var _a, _b;
740
+ if (((_a = hint(error)) != null ? _a : 0) > MAX_TIMER_DELAY_MS) return false;
741
+ const retry = (_b = options.retry) != null ? _b : isServer ? 0 : 3;
742
+ return typeof retry === "function" ? retry(failureCount, error) : retry === true || typeof retry === "number" && failureCount < retry;
743
+ },
744
+ retryDelay: (attempt, error) => {
745
+ var _a, _b;
746
+ return (_b = hint(error)) != null ? _b : typeof options.retryDelay === "function" ? options.retryDelay(attempt, error) : (_a = options.retryDelay) != null ? _a : Math.min(1e3 * __pow(2, attempt), 3e4);
747
+ }
748
+ };
749
+ }
750
+
751
+ // src/market-data/chart-cache.ts
752
+ var MAX_CACHE_RETENTION_SECONDS = 7 * 30 * 24 * 60 * 60 + 14 * 24 * 60 * 60;
753
+ var getIntervalSeconds = (interval) => {
754
+ switch (interval) {
755
+ case "1m":
756
+ return 60;
757
+ case "5m":
758
+ return 5 * 60;
759
+ case "1h":
760
+ return 60 * 60;
761
+ case "1d":
762
+ return 24 * 60 * 60;
763
+ }
764
+ };
765
+ var resolveMaxLastUpdateTs = (venues) => {
766
+ let max = null;
767
+ for (const venueData of Object.values(venues)) {
768
+ if (venueData.lastUpdateTs != null && (max == null || venueData.lastUpdateTs > max)) {
769
+ max = venueData.lastUpdateTs;
770
+ }
771
+ }
772
+ return max;
773
+ };
774
+ var sortCandles = (candles) => {
775
+ return [...candles].sort((left, right) => left.time - right.time);
776
+ };
777
+ var createMarketChartData = (params) => {
778
+ var _a;
779
+ const candles = sortCandles(
780
+ params.response.data.map((candle) => __spreadProps(__spreadValues({
781
+ time: Math.floor(candle.t / 1e3),
782
+ open: candle.o,
783
+ high: candle.h,
784
+ low: candle.l,
785
+ close: candle.c
786
+ }, Number.isFinite(candle.mean) ? { mean: candle.mean } : {}), {
787
+ volume: candle.v,
788
+ source: "rest"
789
+ }))
790
+ );
791
+ const lastCandle = candles[candles.length - 1];
792
+ const lastUpdateTs = (_a = lastCandle == null ? void 0 : lastCandle.time) != null ? _a : null;
793
+ const venues = {
794
+ [params.response.venue]: {
795
+ venue: params.response.venue,
796
+ outcomeIds: [params.response.venueMarketOutcomeId],
797
+ candles,
798
+ liveCandle: null,
799
+ lineValue: lastCandle == null ? void 0 : lastCandle.close,
800
+ lastTrade: null,
801
+ lastUpdateTs
802
+ }
803
+ };
804
+ return {
805
+ marketId: params.marketId,
806
+ delivery: params.response.meta,
807
+ outcomeIds: [params.response.venueMarketOutcomeId],
808
+ primaryVenue: params.response.venue,
809
+ interval: params.interval,
810
+ startTs: params.startTs,
811
+ endTs: params.endTs,
812
+ venues,
813
+ lastUpdateTs
814
+ };
815
+ };
816
+ var mergeMarketChartData = (params) => {
817
+ var _a, _b, _c, _d, _e;
818
+ if (params.datasets.length === 0) {
819
+ return null;
820
+ }
821
+ const primaryVenue = (_b = (_a = params.datasets[0]) == null ? void 0 : _a.primaryVenue) != null ? _b : "aggregate";
822
+ const outcomeIds = Array.from(
823
+ new Set(
824
+ params.datasets.flatMap((dataset) => {
825
+ return dataset.outcomeIds.length > 0 ? dataset.outcomeIds : [dataset.marketId];
826
+ })
827
+ )
828
+ );
829
+ const venues = params.datasets.reduce((acc, dataset) => {
830
+ for (const [venue, venueData] of Object.entries(dataset.venues)) {
831
+ const existingVenueData = acc[venue];
832
+ acc[venue] = existingVenueData ? __spreadProps(__spreadValues({}, venueData), {
833
+ outcomeIds: Array.from(
834
+ /* @__PURE__ */ new Set([...existingVenueData.outcomeIds, ...venueData.outcomeIds])
835
+ )
836
+ }) : venueData;
837
+ }
838
+ return acc;
839
+ }, {});
840
+ return {
841
+ marketId: params.marketId,
842
+ delivery: (_e = (_c = params.datasets.find((dataset) => dataset.marketId === params.marketId)) == null ? void 0 : _c.delivery) != null ? _e : (_d = params.datasets[0]) == null ? void 0 : _d.delivery,
843
+ outcomeIds,
844
+ primaryVenue,
845
+ interval: params.interval,
846
+ startTs: params.startTs,
847
+ endTs: params.endTs,
848
+ venues,
849
+ lastUpdateTs: resolveMaxLastUpdateTs(venues)
850
+ };
851
+ };
852
+
853
+ // src/market-data/chart-retry-gate.ts
854
+ import { isAggApiError as isAggApiError3 } from "@agg-build/sdk";
855
+
856
+ // src/market-data/chart-history.ts
857
+ import {
858
+ loadImmutableHistory,
859
+ isAggApiError as isAggApiError2
860
+ } from "@agg-build/sdk";
861
+ var ChartDeliveryError = class extends Error {
862
+ constructor(state, retryAfterMs) {
863
+ super(`Chart delivery ${state}`);
864
+ this.state = state;
865
+ this.retryAfterMs = retryAfterMs;
866
+ this.name = "ChartDeliveryError";
867
+ }
868
+ };
869
+ var usable = (response) => {
870
+ var _a;
871
+ if (response.data.length === 0 && ((_a = response.meta) == null ? void 0 : _a.state) && response.meta.state !== "empty")
872
+ throw new ChartDeliveryError(response.meta.state, response.meta.retryAfterMs);
873
+ return response;
874
+ };
875
+ var withActualFreshness = (response) => {
876
+ var _a, _b;
877
+ const serverTime = Number.isFinite(response.meta.serverTime) ? response.meta.serverTime : Date.now();
878
+ const lastBarOpenTime = (_b = (_a = response.data.at(-1)) == null ? void 0 : _a.t) != null ? _b : null;
879
+ return __spreadProps(__spreadValues({}, response), {
880
+ meta: __spreadProps(__spreadValues({}, response.meta), {
881
+ serverTime,
882
+ lastBarOpenTime,
883
+ staleSeconds: lastBarOpenTime == null ? null : Math.max(0, (serverTime - lastBarOpenTime) / 1e3)
884
+ })
885
+ });
886
+ };
887
+ function fetchChartHistory(client, socket, request, signal, onInitial) {
888
+ return __async(this, null, function* () {
889
+ var _a, _b, _c;
890
+ const readBars = (params) => __async(null, null, function* () {
891
+ const response = yield client.getChartBars(params, __spreadValues({
892
+ signal
893
+ }, socket ? { decode: (text) => socket.decodeHistory(text) } : {}));
894
+ signal == null ? void 0 : signal.throwIfAborted();
895
+ if (response.venueMarketOutcomeId !== request.venueMarketOutcomeId)
896
+ throw new Error("Chart history identity mismatch");
897
+ return response;
898
+ });
899
+ if (!client.preferImmutableHistory) return usable(yield readBars(request));
900
+ let verified;
901
+ try {
902
+ const manifest2 = yield client.getChartHistoryManifest(request, { signal });
903
+ if (manifest2.venueMarketOutcomeId !== request.venueMarketOutcomeId)
904
+ throw new Error("Chart manifest identity mismatch");
905
+ if (manifest2.meta.complete) {
906
+ const history2 = yield socket ? socket.loadHistory(manifest2, { signal }) : loadImmutableHistory({ manifest: manifest2, signal });
907
+ verified = {
908
+ manifest: manifest2,
909
+ history: history2.filter(
910
+ (bar) => (request.from == null || bar.t >= request.from) && bar.t < request.to
911
+ )
912
+ };
913
+ }
914
+ } catch (error) {
915
+ if ((signal == null ? void 0 : signal.aborted) || isAggApiError2(error) && (error.status === 429 || error.status === 503))
916
+ throw error;
917
+ }
918
+ signal == null ? void 0 : signal.throwIfAborted();
919
+ if (!verified) return usable(yield readBars(request));
920
+ const { manifest, history } = verified;
921
+ const fullyCovered = manifest.finalizedThrough >= request.to;
922
+ const initial = withActualFreshness({
923
+ venueMarketOutcomeId: manifest.venueMarketOutcomeId,
924
+ venue: manifest.venue,
925
+ resolution: manifest.resolution,
926
+ data: history,
927
+ meta: __spreadProps(__spreadValues({}, manifest.meta), {
928
+ state: fullyCovered ? history.length ? "ready" : "empty" : "warming",
929
+ complete: fullyCovered
930
+ })
931
+ });
932
+ if (fullyCovered) return usable(initial);
933
+ if (history.length > 0) onInitial == null ? void 0 : onInitial(initial);
934
+ signal == null ? void 0 : signal.throwIfAborted();
935
+ try {
936
+ const tail = yield readBars(__spreadProps(__spreadValues({}, request), {
937
+ resolution: manifest.resolution,
938
+ from: Math.max((_a = request.from) != null ? _a : 0, manifest.finalizedThrough),
939
+ countBack: void 0
940
+ }));
941
+ if (tail.venue !== manifest.venue || tail.resolution !== manifest.resolution)
942
+ throw new Error("Chart tail series mismatch");
943
+ const data = [
944
+ ...history,
945
+ ...tail.data.filter((bar) => bar.t >= manifest.finalizedThrough && bar.t < request.to)
946
+ ];
947
+ const incomplete = tail.meta.complete === false || ["warming", "failed", "unsupported"].includes((_b = tail.meta.state) != null ? _b : "");
948
+ return usable(
949
+ withActualFreshness(__spreadProps(__spreadValues({}, tail), {
950
+ resolution: manifest.resolution,
951
+ data,
952
+ meta: __spreadProps(__spreadValues(__spreadValues({}, initial.meta), tail.meta), {
953
+ complete: !incomplete,
954
+ state: incomplete ? (_c = tail.meta.state) != null ? _c : "warming" : data.length ? "ready" : "empty"
955
+ })
956
+ }))
957
+ );
958
+ } catch (error) {
959
+ if (signal == null ? void 0 : signal.aborted) throw error;
960
+ return usable(
961
+ withActualFreshness(__spreadProps(__spreadValues({}, initial), {
962
+ meta: __spreadValues(__spreadProps(__spreadValues({}, initial.meta), {
963
+ state: error instanceof ChartDeliveryError ? error.state : "failed",
964
+ complete: false
965
+ }), (error instanceof ChartDeliveryError || isAggApiError2(error)) && error.retryAfterMs != null ? { retryAfterMs: error.retryAfterMs } : {})
966
+ }))
967
+ );
968
+ }
969
+ });
970
+ }
971
+
972
+ // src/market-data/chart-retry-gate.ts
973
+ var MAX_TIMER_DELAY_MS2 = 2147483647;
974
+ var notBefore = /* @__PURE__ */ new WeakMap();
975
+ var validDelay = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
976
+ function record(query, delay) {
977
+ if (validDelay(delay) && delay > 0)
978
+ notBefore.set(query, Math.min(Number.MAX_SAFE_INTEGER, Date.now() + delay));
979
+ else notBefore.delete(query);
980
+ }
981
+ function chartRetryRemaining(query) {
982
+ var _a;
983
+ return Math.max(0, ((_a = notBefore.get(query)) != null ? _a : 0) - Date.now());
984
+ }
985
+ function chartRefetchInterval(query, interval) {
986
+ if (interval === false) return false;
987
+ const remaining = chartRetryRemaining(query);
988
+ return remaining > MAX_TIMER_DELAY_MS2 ? false : Math.max(interval, remaining);
989
+ }
990
+ function waitForDeadline(query, signal) {
991
+ return __async(this, null, function* () {
992
+ while (chartRetryRemaining(query) > 0) {
993
+ signal.throwIfAborted();
994
+ yield new Promise((resolve, reject) => {
995
+ const aborted = () => {
996
+ clearTimeout(timer);
997
+ signal.removeEventListener("abort", aborted);
998
+ reject(signal.reason);
999
+ };
1000
+ const timer = setTimeout(
1001
+ () => {
1002
+ signal.removeEventListener("abort", aborted);
1003
+ resolve();
1004
+ },
1005
+ Math.min(chartRetryRemaining(query), MAX_TIMER_DELAY_MS2)
1006
+ );
1007
+ signal.addEventListener("abort", aborted, { once: true });
1008
+ if (signal.aborted) aborted();
1009
+ });
1010
+ }
1011
+ signal.throwIfAborted();
1012
+ });
1013
+ }
1014
+ function runChartQuery(query, signal, load) {
1015
+ return __async(this, null, function* () {
1016
+ var _a;
1017
+ yield waitForDeadline(query, signal);
1018
+ try {
1019
+ const data = yield load();
1020
+ signal.throwIfAborted();
1021
+ const delivery = data.delivery;
1022
+ record(
1023
+ query,
1024
+ delivery && delivery.complete !== true && !["ready", "empty"].includes((_a = delivery.state) != null ? _a : "") ? delivery.retryAfterMs : void 0
1025
+ );
1026
+ return data;
1027
+ } catch (error) {
1028
+ if (!signal.aborted) {
1029
+ const delay = isAggApiError3(error) ? error.retryAfterMs : error instanceof ChartDeliveryError && validDelay(error.retryAfterMs) ? error.retryAfterMs : void 0;
1030
+ record(query, delay);
1031
+ }
1032
+ throw error;
1033
+ }
1034
+ });
1035
+ }
1036
+
1037
+ // src/market-data/chart-tail.ts
1038
+ var closedCaches = /* @__PURE__ */ new WeakMap();
1039
+ var toChart = (candle) => ({
1040
+ time: candle.openTime,
1041
+ open: candle.o,
1042
+ high: candle.h,
1043
+ low: candle.l,
1044
+ close: candle.c,
1045
+ volume: candle.v,
1046
+ source: "ws"
1047
+ });
1048
+ function overlayCandleTail(history, live, rolling) {
1049
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1050
+ const tail = (_a = live == null ? void 0 : live.candles) == null ? void 0 : _a[history.interval];
1051
+ const venue = history.venues[history.primaryVenue];
1052
+ if (!tail || !venue || !rolling && history.endTs != null && history.endTs < Date.now())
1053
+ return history;
1054
+ const last = (_c = (_b = venue.candles.at(-1)) == null ? void 0 : _b.time) != null ? _c : -Infinity;
1055
+ const closed = tail.closed.filter((candle) => candle.openTime > last);
1056
+ const key = closed.map((candle) => `${candle.openTime}:${candle.c}:${candle.v}`).join("|");
1057
+ let cached = closedCaches.get(history);
1058
+ if (!cached || cached.key !== key) {
1059
+ cached = {
1060
+ key,
1061
+ candles: closed.length ? [...venue.candles, ...closed.map(toChart)] : venue.candles
1062
+ };
1063
+ closedCaches.set(history, cached);
1064
+ }
1065
+ const forming = tail.forming && tail.forming.openTime >= last ? toChart(tail.forming) : null;
1066
+ const lastSourceTime = Math.max(
1067
+ (_e = (_d = live.orderbook) == null ? void 0 : _d.timestamp) != null ? _e : -Infinity,
1068
+ (_g = (_f = live.trades[0]) == null ? void 0 : _f.timestamp) != null ? _g : -Infinity,
1069
+ (_h = venue.lastUpdateTs) != null ? _h : -Infinity
1070
+ );
1071
+ const lastUpdateTs = Number.isFinite(lastSourceTime) ? lastSourceTime : null;
1072
+ return __spreadProps(__spreadValues({}, history), {
1073
+ lastUpdateTs,
1074
+ venues: __spreadProps(__spreadValues({}, history.venues), {
1075
+ [history.primaryVenue]: __spreadProps(__spreadValues({}, venue), {
1076
+ candles: cached.candles,
1077
+ liveCandle: forming,
1078
+ lineValue: (_i = forming == null ? void 0 : forming.close) != null ? _i : venue.lineValue,
1079
+ lastTrade: (_j = live.trades[0]) != null ? _j : venue.lastTrade,
1080
+ lastUpdateTs
1081
+ })
1082
+ })
1083
+ });
1084
+ }
543
1085
 
544
1086
  // src/market-data/subscription.ts
545
- import { useEffect as useEffect2, useMemo } from "react";
1087
+ import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
546
1088
  function useMarketDataSubscription({
547
1089
  marketId,
548
1090
  additionalMarketIds,
@@ -551,7 +1093,7 @@ function useMarketDataSubscription({
551
1093
  trades = false
552
1094
  }) {
553
1095
  const ws = useAggWebSocket();
554
- const allIds = useMemo(() => {
1096
+ const allIds = useMemo2(() => {
555
1097
  const ids = /* @__PURE__ */ new Set();
556
1098
  if (marketId) ids.add(marketId);
557
1099
  if (additionalMarketIds) {
@@ -562,7 +1104,7 @@ function useMarketDataSubscription({
562
1104
  return [...ids];
563
1105
  }, [marketId, additionalMarketIds]);
564
1106
  const stableKey = allIds.join("|");
565
- useEffect2(() => {
1107
+ useEffect4(() => {
566
1108
  if (!ws || !allIds.length || !enabled || !orderbook && !trades) return;
567
1109
  const unsubscribers = [];
568
1110
  for (const id of allIds) {
@@ -584,9 +1126,11 @@ function useMarketDataSubscription({
584
1126
  }
585
1127
 
586
1128
  // src/use-market-chart.ts
587
- function useMarketChart(options) {
588
- var _a, _b, _c;
1129
+ function useMarketChartQueries(options) {
1130
+ var _a, _b;
589
1131
  const client = useAggClient();
1132
+ const queryClient = useQueryClient2();
1133
+ const socket = useAggWebSocket();
590
1134
  const isConnected = useAggWebSocketConnectionState();
591
1135
  const {
592
1136
  features: { enableLiveUpdates }
@@ -594,6 +1138,7 @@ function useMarketChart(options) {
594
1138
  const {
595
1139
  marketId,
596
1140
  venueMarketIds,
1141
+ liveOutcomeIds,
597
1142
  interval = "5m",
598
1143
  startTs = null,
599
1144
  endTs = null,
@@ -601,9 +1146,10 @@ function useMarketChart(options) {
601
1146
  enabled = true,
602
1147
  live,
603
1148
  refetchIntervalMs = null,
1149
+ staleTimeMs,
604
1150
  rangeKey
605
1151
  } = options;
606
- const resolvedRangeKey = rangeKey != null ? rangeKey : interval;
1152
+ const resolvedRangeKey = rangeKey != null ? rangeKey : `${interval}:${startTs != null ? startTs : "count"}:${endTs != null ? endTs : "unset"}`;
607
1153
  const liveEnabled = live != null ? live : enableLiveUpdates;
608
1154
  const outcomeIds = (() => {
609
1155
  const ids = /* @__PURE__ */ new Set();
@@ -617,72 +1163,197 @@ function useMarketChart(options) {
617
1163
  })();
618
1164
  const primaryOutcomeId = (_a = marketId != null ? marketId : venueMarketIds == null ? void 0 : venueMarketIds.find(Boolean)) != null ? _a : null;
619
1165
  const isQueryEnabled = enabled && outcomeIds.length > 0 && endTs != null && (startTs != null || countBack != null);
1166
+ const subscribedIds = liveOutcomeIds ? outcomeIds.filter((id) => liveOutcomeIds.includes(id)) : outcomeIds;
1167
+ const subscribedPrimaryId = primaryOutcomeId && subscribedIds.includes(primaryOutcomeId) ? primaryOutcomeId : (_b = subscribedIds[0]) != null ? _b : null;
620
1168
  useMarketDataSubscription({
621
- marketId: primaryOutcomeId,
622
- additionalMarketIds: outcomeIds.slice(1),
623
- enabled: Boolean(isQueryEnabled && liveEnabled),
1169
+ marketId: subscribedPrimaryId,
1170
+ additionalMarketIds: subscribedIds.filter((id) => id !== subscribedPrimaryId),
1171
+ enabled: Boolean(isQueryEnabled && liveEnabled && subscribedIds.length > 0),
624
1172
  orderbook: true,
625
1173
  trades: true
626
1174
  });
627
- const queries = useQueries2({
628
- queries: outcomeIds.map((outcomeId) => ({
1175
+ const queries = useQueries3({
1176
+ queries: outcomeIds.map((outcomeId) => __spreadProps(__spreadValues({
629
1177
  // Cache key is intentionally time-free. The rolling window's
630
1178
  // startTs/endTs advance on every bucket but the user expects the same
631
1179
  // chart on revisit — see comment on `marketDataKeys.chart`. queryFn
632
1180
  // closes over the current window so refetches still fetch fresh data.
633
1181
  queryKey: marketDataKeys.chart(outcomeId, interval, resolvedRangeKey, countBack),
634
1182
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
635
- const response = yield client.getChartBars(
636
- {
637
- venueMarketOutcomeId: outcomeId,
638
- resolution: interval,
639
- from: startTs != null ? startTs : void 0,
640
- to: endTs,
641
- countBack: countBack != null ? countBack : void 0
642
- },
643
- { signal }
644
- );
645
- return createMarketChartData({
646
- marketId: outcomeId,
647
- interval,
648
- startTs,
649
- endTs,
650
- response
1183
+ const owner = queryClient.getQueryCache().find({
1184
+ queryKey: marketDataKeys.chart(outcomeId, interval, resolvedRangeKey, countBack),
1185
+ exact: true
651
1186
  });
1187
+ if (!owner) throw new Error("Chart query was removed before fetching");
1188
+ return runChartQuery(owner, signal, () => __async(null, null, function* () {
1189
+ var _a2;
1190
+ const response = yield fetchChartHistory(
1191
+ client,
1192
+ socket,
1193
+ {
1194
+ venueMarketOutcomeId: outcomeId,
1195
+ resolution: interval,
1196
+ from: startTs != null ? startTs : void 0,
1197
+ to: endTs,
1198
+ countBack: countBack != null ? countBack : void 0
1199
+ },
1200
+ signal,
1201
+ (initial) => {
1202
+ var _a3;
1203
+ if (signal.aborted) return;
1204
+ queryClient.setQueryData(
1205
+ marketDataKeys.chart(outcomeId, interval, resolvedRangeKey, countBack),
1206
+ createMarketChartData({
1207
+ marketId: outcomeId,
1208
+ interval: (_a3 = initial.resolution) != null ? _a3 : interval,
1209
+ startTs,
1210
+ endTs,
1211
+ response: initial
1212
+ })
1213
+ );
1214
+ }
1215
+ );
1216
+ return createMarketChartData({
1217
+ marketId: outcomeId,
1218
+ interval: (_a2 = response.resolution) != null ? _a2 : interval,
1219
+ startTs,
1220
+ endTs,
1221
+ response
1222
+ });
1223
+ }));
652
1224
  }),
653
1225
  enabled: isQueryEnabled,
1226
+ meta: { chartWindow: rangeKey ? "rolling" : "fixed", chartEndTs: endTs },
654
1227
  // Treat data as fresh for one bucket — within that window the
655
1228
  // existing entry serves remounts without a refetch, and the
656
1229
  // `refetchInterval` below schedules the next bucket's refresh.
657
- staleTime: refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : 3e4,
1230
+ staleTime: (query) => {
1231
+ var _a2;
1232
+ if (rangeKey && endTs != null && ((_a2 = query.state.data) == null ? void 0 : _a2.endTs) != null && query.state.data.endTs < endTs)
1233
+ return 0;
1234
+ return staleTimeMs != null ? staleTimeMs : refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : 3e4;
1235
+ },
658
1236
  // 60 min — survives typical tab/page revisits without re-fetching.
659
1237
  gcTime: 60 * 6e4,
660
- refetchOnWindowFocus: false,
661
- retry: 1,
1238
+ refetchOnWindowFocus: false
1239
+ }, withReadRetry({
1240
+ retry: (failureCount, error) => {
1241
+ if (error instanceof ChartDeliveryError) {
1242
+ if (error.state === "unsupported") return false;
1243
+ if (error.state === "warming") return failureCount < 8;
1244
+ }
1245
+ return failureCount < 1;
1246
+ },
1247
+ retryDelay: (_attempt, error) => error instanceof ChartDeliveryError && error.retryAfterMs != null ? Math.min(error.state === "warming" ? 1e3 : 5e3, Math.max(0, error.retryAfterMs)) : 1e3
1248
+ })), {
662
1249
  placeholderData: keepPreviousData2,
663
- refetchInterval: refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : false,
1250
+ refetchInterval: (query) => chartRefetchInterval(
1251
+ query,
1252
+ refetchIntervalMs != null && refetchIntervalMs > 0 ? refetchIntervalMs : false
1253
+ ),
664
1254
  refetchIntervalInBackground: false
665
1255
  }))
666
1256
  });
1257
+ const liveStates = useLiveStates(isQueryEnabled ? outcomeIds : []);
1258
+ const overlaid = queries.map((query, index) => {
1259
+ var _a2, _b2;
1260
+ return __spreadProps(__spreadValues({}, query), {
1261
+ data: ((_a2 = query.data) == null ? void 0 : _a2.marketId) === outcomeIds[index] ? overlayCandleTail(query.data, (_b2 = liveStates[index]) == null ? void 0 : _b2.data, !!rangeKey) : void 0
1262
+ });
1263
+ });
1264
+ const availability = {};
1265
+ if (isQueryEnabled)
1266
+ queries.forEach((query, index) => {
1267
+ var _a2, _b2, _c, _d;
1268
+ const sameOutcome = ((_a2 = query.data) == null ? void 0 : _a2.marketId) === outcomeIds[index];
1269
+ const metadata = sameOutcome ? (_b2 = query.data) == null ? void 0 : _b2.delivery : void 0;
1270
+ const error = query.error;
1271
+ const pending = query.isLoading || query.isPlaceholderData || query.isFetching;
1272
+ const state = error instanceof ChartDeliveryError ? error.state : error ? "failed" : pending || !sameOutcome ? "warming" : (_c = metadata == null ? void 0 : metadata.state) != null ? _c : Object.values(query.data.venues).some(
1273
+ (venue) => venue.candles.length > 0 || venue.liveCandle
1274
+ ) ? "ready" : "empty";
1275
+ availability[outcomeIds[index]] = __spreadValues(__spreadProps(__spreadValues({}, metadata), {
1276
+ state,
1277
+ complete: (state === "ready" || state === "empty") && ((_d = metadata == null ? void 0 : metadata.complete) != null ? _d : true)
1278
+ }), error instanceof ChartDeliveryError && error.retryAfterMs != null ? { retryAfterMs: error.retryAfterMs } : {});
1279
+ });
1280
+ return {
1281
+ queries: overlaid,
1282
+ availability,
1283
+ outcomeIds,
1284
+ primaryOutcomeId,
1285
+ interval,
1286
+ startTs,
1287
+ endTs,
1288
+ isQueryEnabled,
1289
+ liveEnabled: liveEnabled && subscribedIds.length > 0,
1290
+ isConnected
1291
+ };
1292
+ }
1293
+ function useMarketCharts(options) {
1294
+ const { queries, availability, outcomeIds, isQueryEnabled, liveEnabled, isConnected } = useMarketChartQueries(options);
1295
+ const charts = {};
1296
+ const errors = {};
1297
+ queries.forEach((query, index) => {
1298
+ var _a;
1299
+ const outcomeId = outcomeIds[index];
1300
+ if (((_a = query.data) == null ? void 0 : _a.marketId) === outcomeId && !query.isPlaceholderData)
1301
+ charts[outcomeId] = query.data;
1302
+ if (query.error)
1303
+ errors[outcomeId] = query.error instanceof Error ? query.error : new Error(String(query.error));
1304
+ });
1305
+ return {
1306
+ availability,
1307
+ charts,
1308
+ errors,
1309
+ isLoading: Boolean(
1310
+ isQueryEnabled && queries.some((query) => query.isLoading || query.isPlaceholderData)
1311
+ ),
1312
+ isLive: Boolean(isQueryEnabled && liveEnabled && isConnected),
1313
+ refetch: () => __async(null, null, function* () {
1314
+ return Promise.all(queries.map((query) => query.refetch()));
1315
+ })
1316
+ };
1317
+ }
1318
+ function useMarketChart(options) {
1319
+ var _a, _b, _c, _d;
1320
+ const {
1321
+ queries,
1322
+ availability,
1323
+ primaryOutcomeId,
1324
+ interval,
1325
+ startTs,
1326
+ endTs,
1327
+ isQueryEnabled,
1328
+ liveEnabled,
1329
+ isConnected
1330
+ } = useMarketChartQueries(options);
667
1331
  const successfulDatasets = queries.flatMap((query) => {
668
1332
  return query.data ? [query.data] : [];
669
1333
  });
670
1334
  const data = primaryOutcomeId && successfulDatasets.length > 0 ? mergeMarketChartData({
671
1335
  marketId: primaryOutcomeId,
672
- interval,
1336
+ interval: (_b = (_a = successfulDatasets[0]) == null ? void 0 : _a.interval) != null ? _b : interval,
673
1337
  startTs,
674
1338
  endTs,
675
1339
  datasets: successfulDatasets
676
1340
  }) : null;
677
- const hasPendingQuery = queries.some((query) => query.isLoading);
678
- const firstError = (_c = (_b = queries.find((query) => query.error != null)) == null ? void 0 : _b.error) != null ? _c : null;
1341
+ const hasPendingQuery = queries.some((query) => query.isLoading || query.isPlaceholderData);
1342
+ const firstError = (_d = (_c = queries.find((query) => query.error != null)) == null ? void 0 : _c.error) != null ? _d : null;
679
1343
  const error = data == null && !hasPendingQuery ? firstError instanceof Error ? firstError : firstError ? new Error(String(firstError)) : null : null;
680
- const isLoading = Boolean(isQueryEnabled && data == null && hasPendingQuery);
1344
+ const isInRange = (candle) => (startTs == null || candle.time >= startTs / 1e3) && (endTs == null || candle.time <= endTs / 1e3);
1345
+ const hasVisibleHistory = queries.some(
1346
+ (query) => !query.isPlaceholderData && query.data && Object.entries(query.data.venues).some(
1347
+ ([venueName, venue]) => (!options.visibleVenue || venueName === options.visibleVenue) && (venue.candles.some(isInRange) || venue.liveCandle != null && isInRange(venue.liveCandle))
1348
+ )
1349
+ );
1350
+ const isLoading = Boolean(isQueryEnabled && hasPendingQuery && !hasVisibleHistory);
681
1351
  return {
682
1352
  data,
1353
+ availability,
683
1354
  isLoading,
684
1355
  error,
685
- isLive: Boolean(liveEnabled && primaryOutcomeId && isConnected),
1356
+ isLive: Boolean(isQueryEnabled && liveEnabled && primaryOutcomeId && isConnected),
686
1357
  refetch: () => __async(null, null, function* () {
687
1358
  return Promise.all(queries.map((query) => query.refetch()));
688
1359
  })
@@ -690,13 +1361,13 @@ function useMarketChart(options) {
690
1361
  }
691
1362
 
692
1363
  // src/use-live-market-stores.ts
693
- import { useEffect as useEffect3, useMemo as useMemo2, useReducer, useRef } from "react";
1364
+ import { useEffect as useEffect5, useMemo as useMemo3, useReducer, useRef as useRef3 } from "react";
694
1365
  function useLiveMarketStores(venueMarketIds) {
695
1366
  const ws = useAggWebSocket();
696
1367
  const [, forceRender] = useReducer((c) => c + 1, 0);
697
- const subsRef = useRef(/* @__PURE__ */ new Map());
698
- const stableKey = useMemo2(() => venueMarketIds.slice().sort().join("|"), [venueMarketIds]);
699
- useEffect3(() => {
1368
+ const subsRef = useRef3(/* @__PURE__ */ new Map());
1369
+ const stableKey = useMemo3(() => venueMarketIds.slice().sort().join("|"), [venueMarketIds]);
1370
+ useEffect5(() => {
700
1371
  if (!ws || venueMarketIds.length === 0) return;
701
1372
  const current = subsRef.current;
702
1373
  const desired = new Set(venueMarketIds);
@@ -733,7 +1404,7 @@ function candleToLive(c, source) {
733
1404
  function useLiveCandles(options) {
734
1405
  var _a;
735
1406
  const { market, interval = "5m", mode = "venue", startTs, endTs } = options;
736
- const venueMarketIds = useMemo3(() => {
1407
+ const venueMarketIds = useMemo4(() => {
737
1408
  if (!market) return [];
738
1409
  if (mode === "venue") return [market.id];
739
1410
  const ids = [market.id];
@@ -753,7 +1424,7 @@ function useLiveCandles(options) {
753
1424
  endTs: endTs != null ? endTs : null,
754
1425
  enabled: !!restMarketId && startTs != null && endTs != null
755
1426
  });
756
- const liveData = useMemo3(() => {
1427
+ const liveData = useMemo4(() => {
757
1428
  if (builders.length === 0) return { closed: [], forming: null };
758
1429
  if (mode === "venue" || builders.length === 1) {
759
1430
  return {
@@ -766,7 +1437,7 @@ function useLiveCandles(options) {
766
1437
  forming: mergeCandles(builders.map((b) => b.getForming(interval)))
767
1438
  };
768
1439
  }, [builders, interval, mode]);
769
- const candles = useMemo3(() => {
1440
+ const candles = useMemo4(() => {
770
1441
  const byTime = /* @__PURE__ */ new Map();
771
1442
  if (chartData) {
772
1443
  const venueEntries = Object.values(chartData.venues);
@@ -791,7 +1462,7 @@ function useLiveCandles(options) {
791
1462
  merged.sort((a, b) => a.time - b.time);
792
1463
  return merged;
793
1464
  }, [chartData, liveData.closed]);
794
- const liveCandle = useMemo3(() => {
1465
+ const liveCandle = useMemo4(() => {
795
1466
  if (!liveData.forming) return null;
796
1467
  return candleToLive(liveData.forming, "live");
797
1468
  }, [liveData.forming]);
@@ -850,8 +1521,8 @@ function useLiveCandleOverlay(options) {
850
1521
  }),
851
1522
  [scale]
852
1523
  );
853
- const scaledCandles = useMemo4(() => rawCandles.map(scaleCandle), [rawCandles, scaleCandle]);
854
- const liveCandle = useMemo4(() => rawLive ? scaleCandle(rawLive) : null, [rawLive, scaleCandle]);
1524
+ const scaledCandles = useMemo5(() => rawCandles.map(scaleCandle), [rawCandles, scaleCandle]);
1525
+ const liveCandle = useMemo5(() => rawLive ? scaleCandle(rawLive) : null, [rawLive, scaleCandle]);
855
1526
  return {
856
1527
  liveCandle,
857
1528
  scaledCandles,
@@ -862,7 +1533,7 @@ function useLiveCandleOverlay(options) {
862
1533
  }
863
1534
 
864
1535
  // src/use-event-orderbook-data.ts
865
- import { useEffect as useEffect4, useMemo as useMemo5 } from "react";
1536
+ import { useEffect as useEffect6, useMemo as useMemo6 } from "react";
866
1537
  function extractSelectedOutcomeIds(selectedMarket) {
867
1538
  var _a, _b, _c;
868
1539
  if (!selectedMarket) return [];
@@ -882,17 +1553,17 @@ function useEventOrderbookData(venueMarkets, selectedMarketId) {
882
1553
  const {
883
1554
  features: { enableLiveUpdates }
884
1555
  } = useAggUiConfig();
885
- const selectedMarket = useMemo5(() => {
1556
+ const selectedMarket = useMemo6(() => {
886
1557
  var _a;
887
1558
  if (!selectedMarketId || !(venueMarkets == null ? void 0 : venueMarkets.length)) return null;
888
1559
  return (_a = venueMarkets.find((m) => m.id === selectedMarketId)) != null ? _a : null;
889
1560
  }, [venueMarkets, selectedMarketId]);
890
- const selectedOutcomeIds = useMemo5(
1561
+ const selectedOutcomeIds = useMemo6(
891
1562
  () => extractSelectedOutcomeIds(selectedMarket),
892
1563
  [selectedMarket]
893
1564
  );
894
1565
  const selectedKey = selectedOutcomeIds.join("|");
895
- useEffect4(() => {
1566
+ useEffect6(() => {
896
1567
  if (!ws || !enableLiveUpdates || !selectedOutcomeIds.length) return;
897
1568
  const unsubscribers = selectedOutcomeIds.map((id) => ws.subscribe(id, "orderbook"));
898
1569
  return () => {
@@ -901,8 +1572,11 @@ function useEventOrderbookData(venueMarkets, selectedMarketId) {
901
1572
  }, [ws, selectedKey, enableLiveUpdates]);
902
1573
  }
903
1574
 
904
- // src/use-live-market.ts
905
- import { useQuery as useQuery3 } from "@tanstack/react-query";
1575
+ // src/use-market-orderbook.ts
1576
+ import { useQuery as useQuery5, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
1577
+
1578
+ // src/market-data/orderbook-snapshot.ts
1579
+ var orderbookTimestampSeconds = (timestamp) => timestamp >= 1e12 ? timestamp / 1e3 : timestamp;
906
1580
  function outcomeOrderbookToState(response, marketId) {
907
1581
  var _a, _b, _c, _d;
908
1582
  const { venue, orderbook, midpoint, spread, seq, checksum, timestamp, venueMarketOutcomeId } = response;
@@ -936,56 +1610,351 @@ function outcomeOrderbookToState(response, marketId) {
936
1610
  spread,
937
1611
  seq,
938
1612
  checksum,
939
- timestamp
1613
+ timestamp: orderbookTimestampSeconds(timestamp)
1614
+ };
1615
+ }
1616
+
1617
+ // src/market-data/orderbook-cache.ts
1618
+ var truncateLevels = (levels, depth) => {
1619
+ if (depth == null) return levels;
1620
+ return levels.slice(0, Math.max(0, depth));
1621
+ };
1622
+ var truncateVenueOrderbooks = (venueOrderbooks, depth) => {
1623
+ if (depth == null) return venueOrderbooks;
1624
+ return Object.fromEntries(
1625
+ Object.entries(venueOrderbooks).map(([venue, book]) => [
1626
+ venue,
1627
+ {
1628
+ bids: truncateLevels(book.bids, depth),
1629
+ asks: truncateLevels(book.asks, depth)
1630
+ }
1631
+ ])
1632
+ );
1633
+ };
1634
+ var aggregateVenueLevels = (venueOrderbooks, side) => {
1635
+ var _a;
1636
+ const levelsByPrice = /* @__PURE__ */ new Map();
1637
+ for (const [venue, orderbook] of Object.entries(venueOrderbooks)) {
1638
+ for (const level of orderbook[side]) {
1639
+ const currentLevel = levelsByPrice.get(level.price);
1640
+ if (currentLevel) {
1641
+ currentLevel.size += level.size;
1642
+ currentLevel.venues[venue] = ((_a = currentLevel.venues[venue]) != null ? _a : 0) + level.size;
1643
+ continue;
1644
+ }
1645
+ levelsByPrice.set(level.price, {
1646
+ price: level.price,
1647
+ size: level.size,
1648
+ venues: {
1649
+ [venue]: level.size
1650
+ }
1651
+ });
1652
+ }
1653
+ }
1654
+ return [...levelsByPrice.values()].sort(
1655
+ (left, right) => side === "bids" ? right.price - left.price : left.price - right.price
1656
+ );
1657
+ };
1658
+ var createMarketOrderbookDataFromVenueOrderbooks = ({
1659
+ marketId,
1660
+ venueOrderbooks,
1661
+ timestamp = Math.floor(Date.now() / 1e3)
1662
+ }) => {
1663
+ var _a, _b, _c, _d;
1664
+ const bids = aggregateVenueLevels(venueOrderbooks, "bids");
1665
+ const asks = aggregateVenueLevels(venueOrderbooks, "asks");
1666
+ const bestBid = (_b = (_a = bids[0]) == null ? void 0 : _a.price) != null ? _b : null;
1667
+ const bestAsk = (_d = (_c = asks[0]) == null ? void 0 : _c.price) != null ? _d : null;
1668
+ return {
1669
+ marketId,
1670
+ orderbook: {
1671
+ bids,
1672
+ asks
1673
+ },
1674
+ venueOrderbooks,
1675
+ venues: Object.fromEntries(
1676
+ Object.entries(venueOrderbooks).map(([venue, orderbook]) => {
1677
+ var _a2, _b2, _c2, _d2;
1678
+ return [
1679
+ venue,
1680
+ {
1681
+ bestBid: (_b2 = (_a2 = orderbook.bids[0]) == null ? void 0 : _a2.price) != null ? _b2 : null,
1682
+ bestAsk: (_d2 = (_c2 = orderbook.asks[0]) == null ? void 0 : _c2.price) != null ? _d2 : null
1683
+ }
1684
+ ];
1685
+ })
1686
+ ),
1687
+ midpoint: bestBid != null && bestAsk != null ? (bestBid + bestAsk) / 2 : null,
1688
+ spread: bestBid != null && bestAsk != null ? bestAsk - bestBid : null,
1689
+ timestamp,
1690
+ snapshotVersion: 0,
1691
+ integrity: "ok"
1692
+ };
1693
+ };
1694
+ var createMarketOrderbookDataFromState = (state, options) => {
1695
+ var _a;
1696
+ return {
1697
+ marketId: state.marketId,
1698
+ orderbook: {
1699
+ bids: state.bids,
1700
+ asks: state.asks
1701
+ },
1702
+ venueOrderbooks: state.venueOrderbooks,
1703
+ venues: state.venues,
1704
+ midpoint: state.midpoint,
1705
+ spread: state.spread,
1706
+ timestamp: state.timestamp,
1707
+ snapshotVersion: (_a = options == null ? void 0 : options.snapshotVersion) != null ? _a : 0,
1708
+ seq: state.seq,
1709
+ checksum: state.checksum,
1710
+ integrity: "ok"
1711
+ };
1712
+ };
1713
+ var marketOrderbookDataToResponse = (data) => {
1714
+ return {
1715
+ venueMarketId: data.marketId,
1716
+ orderbook: data.orderbook,
1717
+ venueOrderbooks: data.venueOrderbooks,
1718
+ venues: data.venues,
1719
+ midpoint: data.midpoint,
1720
+ spread: data.spread,
1721
+ timestamp: data.timestamp,
1722
+ seq: data.seq,
1723
+ checksum: data.checksum,
1724
+ matchedMarkets: data.matchedMarkets
1725
+ };
1726
+ };
1727
+ var applyOrderbookDepth = (data, depth) => {
1728
+ if (depth == null) return data;
1729
+ return __spreadProps(__spreadValues({}, data), {
1730
+ orderbook: {
1731
+ bids: truncateLevels(data.orderbook.bids, depth),
1732
+ asks: truncateLevels(data.orderbook.asks, depth)
1733
+ },
1734
+ venueOrderbooks: truncateVenueOrderbooks(data.venueOrderbooks, depth)
1735
+ });
1736
+ };
1737
+
1738
+ // src/market-data/snapshot-selection.ts
1739
+ import { computeChecksum } from "@agg-build/sdk";
1740
+ var SOCKET_GRACE_MS = 200;
1741
+ var REST_BUDGET_MS = 1500;
1742
+ var MAX_SEED_AGE_MS = 5e3;
1743
+ function hasFreshSnapshot(store, id, now = Date.now()) {
1744
+ const state = store.get(id);
1745
+ return !!state.orderbook && state.integrity === "ok" && now - state.orderbook.timestamp * 1e3 <= MAX_SEED_AGE_MS && state.orderbook.timestamp * 1e3 <= now + 1e3;
1746
+ }
1747
+ function createOrderbookSnapshotQuery(client, store, ids, socketHealthy) {
1748
+ return fetchSnapshotQuery.bind(null, client, store, ids, socketHealthy);
1749
+ }
1750
+ function fetchSnapshotQuery(client, store, ids, socketHealthy, { signal }) {
1751
+ return selectOrderbookSnapshots(client, store, ids, socketHealthy, signal);
1752
+ }
1753
+ function selectOrderbookSnapshots(client, store, ids, socketHealthy, signal) {
1754
+ return __async(this, null, function* () {
1755
+ if (ids.length > 100) throw new Error("Orderbook snapshot batch exceeds 100 outcomes");
1756
+ const missing = () => ids.filter((id) => !hasFreshSnapshot(store, id));
1757
+ if (!missing().length || signal.aborted) return {};
1758
+ if (socketHealthy) {
1759
+ yield new Promise((resolve) => {
1760
+ let unsubscribe2 = () => {
1761
+ };
1762
+ const finish = () => {
1763
+ clearTimeout(timer2);
1764
+ unsubscribe2();
1765
+ signal.removeEventListener("abort", finish);
1766
+ resolve();
1767
+ };
1768
+ const timer2 = setTimeout(finish, SOCKET_GRACE_MS);
1769
+ unsubscribe2 = store.subscribe(ids, () => {
1770
+ if (!missing().length) finish();
1771
+ });
1772
+ signal.addEventListener("abort", finish, { once: true });
1773
+ });
1774
+ }
1775
+ const requested = missing();
1776
+ if (!requested.length || signal.aborted) return {};
1777
+ const initialStates = new Map(requested.map((id) => [id, store.get(id)]));
1778
+ const controller = new AbortController();
1779
+ const abort = () => controller.abort();
1780
+ signal.addEventListener("abort", abort, { once: true });
1781
+ const timer = setTimeout(abort, REST_BUDGET_MS);
1782
+ const unsubscribe = store.subscribe(requested, () => {
1783
+ if (!missing().length) controller.abort();
1784
+ });
1785
+ try {
1786
+ const response = yield client.getOutcomeOrderbooks(
1787
+ { venueMarketOutcomeIds: requested },
1788
+ { signal: controller.signal }
1789
+ );
1790
+ if (signal.aborted) return {};
1791
+ return Object.fromEntries(
1792
+ response.data.flatMap((book, index) => {
1793
+ const id = requested[index];
1794
+ if (!book || !id || hasFreshSnapshot(store, id)) return [];
1795
+ if (book.venueMarketOutcomeId !== id)
1796
+ throw new Error("Orderbook snapshot identity mismatch");
1797
+ if (!Number.isFinite(book.timestamp) || !Number.isSafeInteger(book.seq) || book.seq < 0 || !Number.isInteger(book.checksum))
1798
+ throw new Error("Invalid orderbook snapshot metadata");
1799
+ const snapshot = outcomeOrderbookToState(book, id);
1800
+ if (![...snapshot.bids, ...snapshot.asks].every(
1801
+ (level) => Number.isFinite(level.price) && Number.isFinite(level.size) && level.size >= 0
1802
+ ))
1803
+ throw new Error("Invalid orderbook snapshot levels");
1804
+ const projectedChecksum = book.snapshotChecksum;
1805
+ if (projectedChecksum != null && computeChecksum(snapshot) !== projectedChecksum)
1806
+ throw new Error("Orderbook snapshot checksum mismatch");
1807
+ const current = store.get(id);
1808
+ const live = current.orderbook;
1809
+ const initial = initialStates.get(id);
1810
+ const initialBook = initial.orderbook;
1811
+ if (current.orderbookSnapshotVersion !== initial.orderbookSnapshotVersion || !!live !== !!initialBook || live && initialBook && (live.seq !== initialBook.seq || live.checksum !== initialBook.checksum || live.timestamp !== initialBook.timestamp))
1812
+ return [];
1813
+ if (live) {
1814
+ const sameGeneration = current.isConnected && current.integrity === "ok" && current.orderbookGeneration === current.connectionGeneration;
1815
+ if (snapshot.timestamp < live.timestamp || sameGeneration && snapshot.seq <= live.seq)
1816
+ return [];
1817
+ if (!sameGeneration && snapshot.timestamp <= live.timestamp) return [];
1818
+ }
1819
+ store.update(id, (previous) => __spreadProps(__spreadValues({}, previous), {
1820
+ orderbook: snapshot,
1821
+ integrity: "ok",
1822
+ orderbookError: null
1823
+ }));
1824
+ return [[id, book]];
1825
+ })
1826
+ );
1827
+ } catch (error) {
1828
+ if (signal.aborted || !missing().length) return {};
1829
+ throw error;
1830
+ } finally {
1831
+ clearTimeout(timer);
1832
+ unsubscribe();
1833
+ signal.removeEventListener("abort", abort);
1834
+ }
1835
+ });
1836
+ }
1837
+
1838
+ // src/use-market-orderbook.ts
1839
+ function useMarketOrderbook(options) {
1840
+ var _a, _b, _c, _d, _e, _f, _g;
1841
+ const queryClient = useQueryClient3();
1842
+ const client = useAggClient();
1843
+ const ws = useAggWebSocket();
1844
+ const isConnected = useAggWebSocketConnectionState();
1845
+ const {
1846
+ features: { enableLiveUpdates }
1847
+ } = useAggUiConfig();
1848
+ const { venueMarketOutcomeId, marketId, depth, enabled = true, venueOutcomes, live } = options;
1849
+ const selectedId = (_a = venueMarketOutcomeId != null ? venueMarketOutcomeId : marketId) != null ? _a : null;
1850
+ const liveEnabled = live != null ? live : enableLiveUpdates;
1851
+ const outcomeIds = venueOutcomes == null ? void 0 : venueOutcomes.map((v) => v.venueMarketOutcomeId).filter(Boolean);
1852
+ const subscriptionIds = (outcomeIds == null ? void 0 : outcomeIds.length) ? [...new Set(outcomeIds)] : selectedId ? [selectedId] : [];
1853
+ const selectedOutcomeId = (_b = subscriptionIds[0]) != null ? _b : null;
1854
+ useMarketDataSubscription({
1855
+ marketId: selectedOutcomeId,
1856
+ additionalMarketIds: subscriptionIds.slice(1),
1857
+ enabled: enabled && !!selectedOutcomeId,
1858
+ orderbook: true
1859
+ });
1860
+ const store = getMarketLiveStore(queryClient);
1861
+ const liveQueries = useLiveStates(enabled ? subscriptionIds : []);
1862
+ const sortedIds = [...subscriptionIds].sort();
1863
+ const preferSocket = enabled && Boolean(ws) && (isConnected || subscriptionIds.every((id) => {
1864
+ var _a2;
1865
+ return ((_a2 = store.get(id).connectionGeneration) != null ? _a2 : 0) === 0;
1866
+ }));
1867
+ const seedQuery = useQuery5({
1868
+ queryKey: ["market-orderbook-seed", sortedIds],
1869
+ queryFn: createOrderbookSnapshotQuery(client, store, sortedIds, preferSocket),
1870
+ enabled: enabled && subscriptionIds.length > 0,
1871
+ staleTime: 5e3,
1872
+ gcTime: 6e4,
1873
+ refetchOnWindowFocus: false,
1874
+ retry: false
1875
+ });
1876
+ const liveStates = subscriptionIds.map((subscriptionId, index) => {
1877
+ var _a2, _b2, _c2;
1878
+ return (_c2 = (_b2 = (_a2 = liveQueries[index]) == null ? void 0 : _a2.data) != null ? _b2 : store.peek(subscriptionId)) != null ? _c2 : createMarketLiveState(subscriptionId);
1879
+ });
1880
+ const seededOrderbooks = subscriptionIds.map((subscriptionId, index) => {
1881
+ var _a2, _b2, _c2, _d2;
1882
+ const liveBook = (_b2 = (_a2 = liveStates[index]) == null ? void 0 : _a2.orderbook) != null ? _b2 : null;
1883
+ if (liveBook) return liveBook;
1884
+ const seed = (_c2 = seedQuery.data) == null ? void 0 : _c2[subscriptionId];
1885
+ return ((_d2 = seed == null ? void 0 : seed.orderbook) == null ? void 0 : _d2.bids) && seed.orderbook.asks ? outcomeOrderbookToState(seed, subscriptionId) : null;
1886
+ });
1887
+ const primaryOrderbook = (_c = seededOrderbooks[0]) != null ? _c : null;
1888
+ const primarySnapshotVersion = (_e = (_d = liveStates[0]) == null ? void 0 : _d.orderbookSnapshotVersion) != null ? _e : 0;
1889
+ const data = primaryOrderbook ? applyOrderbookDepth(
1890
+ createMarketOrderbookDataFromState(primaryOrderbook, {
1891
+ snapshotVersion: primarySnapshotVersion
1892
+ }),
1893
+ depth
1894
+ ) : null;
1895
+ const dataById = Object.fromEntries(
1896
+ seededOrderbooks.flatMap((orderbook, index) => {
1897
+ var _a2;
1898
+ if (!orderbook) return [];
1899
+ return [
1900
+ [
1901
+ subscriptionIds[index],
1902
+ applyOrderbookDepth(
1903
+ createMarketOrderbookDataFromState(orderbook, {
1904
+ snapshotVersion: (_a2 = liveStates[index]) == null ? void 0 : _a2.orderbookSnapshotVersion
1905
+ }),
1906
+ depth
1907
+ )
1908
+ ]
1909
+ ];
1910
+ })
1911
+ );
1912
+ const hasAnyOrderbook = seededOrderbooks.some((orderbook) => orderbook != null);
1913
+ const seedLoading = seedQuery.isLoading;
1914
+ const liveOrderbookErrorMessage = enabled && liveEnabled && !hasAnyOrderbook ? (_g = (_f = liveStates.find(
1915
+ (liveState) => typeof liveState.orderbookError === "string" && liveState.orderbookError.length > 0
1916
+ )) == null ? void 0 : _f.orderbookError) != null ? _g : null : null;
1917
+ return {
1918
+ data,
1919
+ dataById,
1920
+ isLoading: enabled && !hasAnyOrderbook && liveOrderbookErrorMessage == null && seedLoading,
1921
+ error: liveOrderbookErrorMessage ? new Error(liveOrderbookErrorMessage) : !hasAnyOrderbook && seedQuery.error instanceof Error ? seedQuery.error : null,
1922
+ isLive: Boolean(enabled && liveEnabled && selectedOutcomeId && isConnected),
1923
+ refetch: () => __async(null, null, function* () {
1924
+ if (!enabled) return;
1925
+ if (subscriptionIds.length === 0) return;
1926
+ subscriptionIds.forEach(
1927
+ (subscriptionId) => store.update(subscriptionId, (previous) => __spreadProps(__spreadValues({}, previous), { orderbookError: null }))
1928
+ );
1929
+ ws == null ? void 0 : ws.resnapshot(subscriptionIds);
1930
+ return seedQuery.refetch();
1931
+ })
940
1932
  };
941
1933
  }
1934
+
1935
+ // src/use-live-market.ts
942
1936
  function useLiveMarket(canonicalMarketId) {
943
- var _a, _b;
944
- const client = useAggClient();
945
- const isConnected = useAggWebSocketConnectionState();
946
1937
  const {
947
1938
  features: { enableLiveUpdates }
948
1939
  } = useAggUiConfig();
949
- const isLiveSubscriptionEnabled = Boolean(canonicalMarketId && enableLiveUpdates);
950
- useMarketDataSubscription({
951
- marketId: canonicalMarketId,
952
- enabled: isLiveSubscriptionEnabled,
953
- orderbook: true
1940
+ const connected = useAggWebSocketConnectionState();
1941
+ const [snapshot] = useLiveStates([canonicalMarketId != null ? canonicalMarketId : "__disabled__"]);
1942
+ useMarketOrderbook({
1943
+ venueMarketOutcomeId: canonicalMarketId,
1944
+ enabled: !!canonicalMarketId,
1945
+ live: enableLiveUpdates
954
1946
  });
955
- const query = useQuery3({
956
- queryKey: marketDataKeys.live(canonicalMarketId != null ? canonicalMarketId : "__disabled__"),
957
- queryFn: () => __async(null, null, function* () {
958
- return createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__");
959
- }),
960
- enabled: false,
961
- staleTime: Infinity,
962
- gcTime: 5 * 6e4,
963
- initialData: () => createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__", {
964
- isConnected: Boolean(isLiveSubscriptionEnabled && isConnected)
965
- })
966
- });
967
- const seedQuery = useQuery3({
968
- queryKey: ["live-market-seed", canonicalMarketId],
969
- queryFn: ({ signal }) => canonicalMarketId ? client.getOutcomeOrderbook(canonicalMarketId, { signal }) : Promise.resolve(null),
970
- enabled: Boolean(canonicalMarketId),
971
- staleTime: 5e3,
972
- gcTime: 6e4,
973
- refetchOnWindowFocus: false,
974
- retry: 1
975
- });
976
- const data = (_a = query.data) != null ? _a : createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__");
977
- const orderbook = (_b = data.orderbook) != null ? _b : canonicalMarketId && seedQuery.data ? outcomeOrderbookToState(seedQuery.data, canonicalMarketId) : null;
1947
+ const data = snapshot.data;
978
1948
  return {
979
- orderbook,
1949
+ orderbook: data.orderbook,
980
1950
  trades: data.trades,
981
- isConnected: isLiveSubscriptionEnabled ? data.isConnected : false,
1951
+ isConnected: !!canonicalMarketId && enableLiveUpdates && connected,
982
1952
  integrity: data.integrity
983
1953
  };
984
1954
  }
985
1955
 
986
1956
  // src/use-live-outcome-prices.ts
987
- import { useMemo as useMemo6, useRef as useRef2 } from "react";
988
- import { useQueries as useQueries3 } from "@tanstack/react-query";
1957
+ import { useMemo as useMemo7, useRef as useRef4 } from "react";
989
1958
  var EMPTY_PRICES = /* @__PURE__ */ new Map();
990
1959
  var buildMidpointFingerprint = (outcomeIds, queries) => {
991
1960
  var _a, _b, _c;
@@ -1000,7 +1969,7 @@ function useLiveOutcomePrices(venueMarkets) {
1000
1969
  const {
1001
1970
  features: { enableLiveUpdates }
1002
1971
  } = useAggUiConfig();
1003
- const outcomeIds = useMemo6(() => {
1972
+ const outcomeIds = useMemo7(() => {
1004
1973
  var _a, _b;
1005
1974
  if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
1006
1975
  const ids = /* @__PURE__ */ new Set();
@@ -1014,22 +1983,13 @@ function useLiveOutcomePrices(venueMarkets) {
1014
1983
  }
1015
1984
  return [...ids].sort();
1016
1985
  }, [venueMarkets]);
1017
- const queries = useQueries3({
1018
- queries: outcomeIds.map((id) => ({
1019
- queryKey: marketDataKeys.live(id),
1020
- queryFn: () => createMarketLiveState(id),
1021
- enabled: false,
1022
- staleTime: Infinity,
1023
- gcTime: 5 * 6e4,
1024
- initialData: () => createMarketLiveState(id)
1025
- }))
1026
- });
1986
+ const queries = useLiveStates(outcomeIds);
1027
1987
  const fingerprint = buildMidpointFingerprint(outcomeIds, queries);
1028
- const prevRef = useRef2({
1988
+ const prevRef = useRef4({
1029
1989
  fingerprint: "",
1030
1990
  prices: EMPTY_PRICES
1031
1991
  });
1032
- const data = useMemo6(() => {
1992
+ const data = useMemo7(() => {
1033
1993
  var _a, _b, _c;
1034
1994
  if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return EMPTY_PRICES;
1035
1995
  if (fingerprint === prevRef.current.fingerprint) {
@@ -1056,8 +2016,7 @@ function findLivePriceById(livePrices, id) {
1056
2016
  }
1057
2017
 
1058
2018
  // src/use-live-best-prices.ts
1059
- import { useMemo as useMemo7, useRef as useRef3 } from "react";
1060
- import { useQueries as useQueries4 } from "@tanstack/react-query";
2019
+ import { useMemo as useMemo8, useRef as useRef5 } from "react";
1061
2020
  var EMPTY = /* @__PURE__ */ new Map();
1062
2021
  var EMPTY_CANDIDATES = /* @__PURE__ */ new Map();
1063
2022
  var extractOutcomeBestPrices = (state) => {
@@ -1086,7 +2045,7 @@ function useLiveBestPrices(venueMarkets) {
1086
2045
  const {
1087
2046
  features: { enableLiveUpdates }
1088
2047
  } = useAggUiConfig();
1089
- const outcomeIds = useMemo7(() => {
2048
+ const outcomeIds = useMemo8(() => {
1090
2049
  var _a, _b;
1091
2050
  if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
1092
2051
  const ids = /* @__PURE__ */ new Set();
@@ -1100,22 +2059,13 @@ function useLiveBestPrices(venueMarkets) {
1100
2059
  }
1101
2060
  return [...ids].sort();
1102
2061
  }, [venueMarkets]);
1103
- const queries = useQueries4({
1104
- queries: outcomeIds.map((id) => ({
1105
- queryKey: marketDataKeys.live(id),
1106
- queryFn: () => createMarketLiveState(id),
1107
- enabled: false,
1108
- staleTime: Infinity,
1109
- gcTime: 5 * 6e4,
1110
- initialData: () => createMarketLiveState(id)
1111
- }))
1112
- });
2062
+ const queries = useLiveStates(outcomeIds);
1113
2063
  const fingerprint = buildFingerprint(outcomeIds, queries);
1114
- const prevRef = useRef3({
2064
+ const prevRef = useRef5({
1115
2065
  fingerprint: "",
1116
2066
  result: EMPTY
1117
2067
  });
1118
- return useMemo7(() => {
2068
+ return useMemo8(() => {
1119
2069
  var _a, _b, _c, _d;
1120
2070
  if (!(venueMarkets == null ? void 0 : venueMarkets.length) || !enableLiveUpdates) return EMPTY;
1121
2071
  if (fingerprint === prevRef.current.fingerprint) return prevRef.current.result;
@@ -1305,7 +2255,7 @@ function useLiveBestPriceCandidates(venueMarkets) {
1305
2255
  const {
1306
2256
  features: { enableLiveUpdates }
1307
2257
  } = useAggUiConfig();
1308
- const outcomeIds = useMemo7(() => {
2258
+ const outcomeIds = useMemo8(() => {
1309
2259
  var _a, _b;
1310
2260
  if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
1311
2261
  const ids = /* @__PURE__ */ new Set();
@@ -1319,22 +2269,13 @@ function useLiveBestPriceCandidates(venueMarkets) {
1319
2269
  }
1320
2270
  return [...ids].sort();
1321
2271
  }, [venueMarkets]);
1322
- const queries = useQueries4({
1323
- queries: outcomeIds.map((id) => ({
1324
- queryKey: marketDataKeys.live(id),
1325
- queryFn: () => createMarketLiveState(id),
1326
- enabled: false,
1327
- staleTime: Infinity,
1328
- gcTime: 5 * 6e4,
1329
- initialData: () => createMarketLiveState(id)
1330
- }))
1331
- });
2272
+ const queries = useLiveStates(outcomeIds);
1332
2273
  const fingerprint = buildCandidateFingerprint(outcomeIds, queries);
1333
- const prevRef = useRef3({
2274
+ const prevRef = useRef5({
1334
2275
  fingerprint: "",
1335
2276
  result: EMPTY_CANDIDATES
1336
2277
  });
1337
- return useMemo7(() => {
2278
+ return useMemo8(() => {
1338
2279
  if (!(venueMarkets == null ? void 0 : venueMarkets.length) || !enableLiveUpdates) return EMPTY_CANDIDATES;
1339
2280
  if (fingerprint === prevRef.current.fingerprint) return prevRef.current.result;
1340
2281
  const states = outcomeIds.map((_, i) => {
@@ -1363,8 +2304,8 @@ function useLiveTrades(canonicalMarketId) {
1363
2304
  }
1364
2305
 
1365
2306
  // src/use-midpoints.ts
1366
- import { useQuery as useQuery4 } from "@tanstack/react-query";
1367
- import { useMemo as useMemo8 } from "react";
2307
+ import { useQuery as useQuery6 } from "@tanstack/react-query";
2308
+ import { useMemo as useMemo9 } from "react";
1368
2309
  var normalizeVenueMarketIds = (venueMarkets) => {
1369
2310
  var _a;
1370
2311
  const ids = /* @__PURE__ */ new Set();
@@ -1537,12 +2478,12 @@ function useMidpoints(venueMarkets, options) {
1537
2478
  market: { maxMidpointIdsPerRequest: configuredMaxMidpointIdsPerRequest }
1538
2479
  } = useAggUiConfig();
1539
2480
  const maxMidpointIdsPerRequest = (_a = options == null ? void 0 : options.maxMidpointIdsPerRequest) != null ? _a : configuredMaxMidpointIdsPerRequest;
1540
- const ids = useMemo8(() => normalizeVenueMarketIds(venueMarkets), [venueMarkets]);
1541
- const bestMidpointCandidateOutcomeIds = useMemo8(
2481
+ const ids = useMemo9(() => normalizeVenueMarketIds(venueMarkets), [venueMarkets]);
2482
+ const bestMidpointCandidateOutcomeIds = useMemo9(
1542
2483
  () => resolveBestMidpointCandidateOutcomeIds(venueMarkets),
1543
2484
  [venueMarkets]
1544
2485
  );
1545
- const { data, isLoading } = useQuery4({
2486
+ const { data, isLoading } = useQuery6({
1546
2487
  queryKey: ["midpoints", ids, maxMidpointIdsPerRequest],
1547
2488
  queryFn: () => client.getMidpoints(ids, { bestPrice: true, maxMidpointIdsPerRequest }),
1548
2489
  enabled: ids.length > 0,
@@ -1552,7 +2493,7 @@ function useMidpoints(venueMarkets, options) {
1552
2493
  refetchOnWindowFocus: false,
1553
2494
  refetchOnReconnect: false
1554
2495
  });
1555
- const result = useMemo8(() => {
2496
+ const result = useMemo9(() => {
1556
2497
  var _a2, _b, _c, _d, _e, _f;
1557
2498
  const map = /* @__PURE__ */ new Map();
1558
2499
  const currentMap = /* @__PURE__ */ new Map();
@@ -1605,7 +2546,7 @@ function useMidpoints(venueMarkets, options) {
1605
2546
  }
1606
2547
  return { map, currentMap, venueMap };
1607
2548
  }, [data, venueMarkets]);
1608
- const { bestMidpoint, bestMidpointVenue } = useMemo8(() => {
2549
+ const { bestMidpoint, bestMidpointVenue } = useMemo9(() => {
1609
2550
  let value;
1610
2551
  let venue;
1611
2552
  for (const outcomeId of bestMidpointCandidateOutcomeIds) {
@@ -1626,7 +2567,7 @@ function useMidpoints(venueMarkets, options) {
1626
2567
  }
1627
2568
  return { bestMidpoint: value, bestMidpointVenue: venue };
1628
2569
  }, [bestMidpointCandidateOutcomeIds, result.map, result.venueMap]);
1629
- const { bestPrices, bestPriceVenuesByOutcomeId } = useMemo8(
2570
+ const { bestPrices, bestPriceVenuesByOutcomeId } = useMemo9(
1630
2571
  () => extractBestPrices(data == null ? void 0 : data.data, venueMarkets),
1631
2572
  [data == null ? void 0 : data.data, venueMarkets]
1632
2573
  );
@@ -1644,7 +2585,7 @@ function useMidpoints(venueMarkets, options) {
1644
2585
  }
1645
2586
 
1646
2587
  // src/use-rolling-chart-window.ts
1647
- import { useEffect as useEffect5, useMemo as useMemo9, useState as useState4 } from "react";
2588
+ import { useEffect as useEffect7, useMemo as useMemo10, useState as useState4 } from "react";
1648
2589
  var RANGE_SECONDS_BY_RANGE = {
1649
2590
  "1H": 60 * 60,
1650
2591
  "6H": 6 * 60 * 60,
@@ -1675,135 +2616,27 @@ var useRollingChartWindow = (options) => {
1675
2616
  var _a;
1676
2617
  const tickMs = (_a = options.tickMs) != null ? _a : 1e3;
1677
2618
  const optionsNowMs = options.nowMs;
1678
- const nowMs = useMemo9(() => optionsNowMs != null ? optionsNowMs : (() => Date.now()), [optionsNowMs]);
2619
+ const nowMs = useMemo10(() => optionsNowMs != null ? optionsNowMs : (() => Date.now()), [optionsNowMs]);
1679
2620
  const [nowSec, setNowSec] = useState4(() => Math.floor(nowMs() / 1e3));
1680
- useEffect5(() => {
2621
+ useEffect7(() => {
1681
2622
  setNowSec(Math.floor(nowMs() / 1e3));
1682
2623
  const handle = setInterval(() => {
1683
2624
  setNowSec(Math.floor(nowMs() / 1e3));
1684
2625
  }, tickMs);
1685
2626
  return () => clearInterval(handle);
1686
2627
  }, [tickMs, nowMs]);
1687
- return useMemo9(
2628
+ return useMemo10(
1688
2629
  () => resolveRollingWindow({ range: options.range, nowSec, interval: options.interval }),
1689
2630
  [options.range, options.interval, nowSec]
1690
2631
  );
1691
2632
  };
1692
2633
 
1693
- // src/use-market-orderbook.ts
1694
- import { useQueries as useQueries5, useQueryClient } from "@tanstack/react-query";
1695
- function useMarketOrderbook(options) {
1696
- var _a, _b, _c, _d, _e, _f, _g;
1697
- const queryClient = useQueryClient();
1698
- const client = useAggClient();
1699
- const ws = useAggWebSocket();
1700
- const isConnected = useAggWebSocketConnectionState();
1701
- const {
1702
- features: { enableLiveUpdates }
1703
- } = useAggUiConfig();
1704
- const { venueMarketOutcomeId, marketId, depth, enabled = true, venueOutcomes, live } = options;
1705
- const selectedId = (_a = venueMarketOutcomeId != null ? venueMarketOutcomeId : marketId) != null ? _a : null;
1706
- const liveEnabled = live != null ? live : enableLiveUpdates;
1707
- const outcomeIds = venueOutcomes == null ? void 0 : venueOutcomes.map((v) => v.venueMarketOutcomeId).filter(Boolean);
1708
- const subscriptionIds = (outcomeIds == null ? void 0 : outcomeIds.length) ? [...new Set(outcomeIds)] : selectedId ? [selectedId] : [];
1709
- const selectedOutcomeId = (_b = subscriptionIds[0]) != null ? _b : null;
1710
- useMarketDataSubscription({
1711
- marketId: selectedOutcomeId,
1712
- additionalMarketIds: subscriptionIds.slice(1),
1713
- enabled: enabled && !!selectedOutcomeId,
1714
- orderbook: true
1715
- });
1716
- const liveQueries = useQueries5({
1717
- queries: subscriptionIds.map((subscriptionId) => ({
1718
- queryKey: marketDataKeys.live(subscriptionId),
1719
- queryFn: () => createMarketLiveState(subscriptionId),
1720
- staleTime: Infinity,
1721
- gcTime: 5 * 6e4,
1722
- refetchOnMount: false,
1723
- refetchOnWindowFocus: false,
1724
- refetchOnReconnect: false
1725
- }))
1726
- });
1727
- const seedQueries = useQueries5({
1728
- queries: subscriptionIds.map((subscriptionId) => ({
1729
- queryKey: ["market-orderbook-seed", subscriptionId],
1730
- queryFn: ({ signal }) => client.getOutcomeOrderbook(subscriptionId, { signal }),
1731
- enabled: enabled && !!subscriptionId,
1732
- staleTime: 5e3,
1733
- gcTime: 6e4,
1734
- refetchOnWindowFocus: false,
1735
- retry: 1
1736
- }))
1737
- });
1738
- const liveStates = subscriptionIds.map((subscriptionId, index) => {
1739
- var _a2, _b2;
1740
- return (_b2 = (_a2 = liveQueries[index]) == null ? void 0 : _a2.data) != null ? _b2 : createMarketLiveState(subscriptionId);
1741
- });
1742
- const seededOrderbooks = subscriptionIds.map((subscriptionId, index) => {
1743
- var _a2, _b2, _c2, _d2;
1744
- const liveBook = (_b2 = (_a2 = liveStates[index]) == null ? void 0 : _a2.orderbook) != null ? _b2 : null;
1745
- if (liveBook) return liveBook;
1746
- const seed = (_c2 = seedQueries[index]) == null ? void 0 : _c2.data;
1747
- return ((_d2 = seed == null ? void 0 : seed.orderbook) == null ? void 0 : _d2.bids) && seed.orderbook.asks ? outcomeOrderbookToState(seed, subscriptionId) : null;
1748
- });
1749
- const primaryOrderbook = (_c = seededOrderbooks[0]) != null ? _c : null;
1750
- const primarySnapshotVersion = (_e = (_d = liveStates[0]) == null ? void 0 : _d.orderbookSnapshotVersion) != null ? _e : 0;
1751
- const data = primaryOrderbook ? applyOrderbookDepth(
1752
- createMarketOrderbookDataFromState(primaryOrderbook, {
1753
- snapshotVersion: primarySnapshotVersion
1754
- }),
1755
- depth
1756
- ) : null;
1757
- const dataById = Object.fromEntries(
1758
- seededOrderbooks.flatMap((orderbook, index) => {
1759
- var _a2;
1760
- if (!orderbook) return [];
1761
- return [
1762
- [
1763
- subscriptionIds[index],
1764
- applyOrderbookDepth(
1765
- createMarketOrderbookDataFromState(orderbook, {
1766
- snapshotVersion: (_a2 = liveStates[index]) == null ? void 0 : _a2.orderbookSnapshotVersion
1767
- }),
1768
- depth
1769
- )
1770
- ]
1771
- ];
1772
- })
1773
- );
1774
- const hasAnyOrderbook = seededOrderbooks.some((orderbook) => orderbook != null);
1775
- const seedLoading = seedQueries.some((query) => query.isLoading);
1776
- const liveOrderbookErrorMessage = enabled && liveEnabled && !hasAnyOrderbook ? (_g = (_f = liveStates.find(
1777
- (liveState) => typeof liveState.orderbookError === "string" && liveState.orderbookError.length > 0
1778
- )) == null ? void 0 : _f.orderbookError) != null ? _g : null : null;
1779
- return {
1780
- data,
1781
- dataById,
1782
- isLoading: enabled && !hasAnyOrderbook && liveOrderbookErrorMessage == null && (isConnected || seedLoading),
1783
- error: liveOrderbookErrorMessage ? new Error(liveOrderbookErrorMessage) : null,
1784
- isLive: Boolean(liveEnabled && selectedOutcomeId && isConnected),
1785
- refetch: () => __async(null, null, function* () {
1786
- if (!enabled) return;
1787
- if (subscriptionIds.length === 0) return;
1788
- subscriptionIds.forEach((subscriptionId) => {
1789
- queryClient.setQueryData(
1790
- marketDataKeys.live(subscriptionId),
1791
- (previous) => __spreadProps(__spreadValues({}, previous != null ? previous : createMarketLiveState(subscriptionId)), {
1792
- orderbookError: null
1793
- })
1794
- );
1795
- });
1796
- ws == null ? void 0 : ws.resnapshot(subscriptionIds);
1797
- })
1798
- };
1799
- }
1800
-
1801
2634
  // src/use-arb.ts
1802
- import { useEffect as useEffect6, useRef as useRef4, useState as useState5 } from "react";
2635
+ import { useEffect as useEffect8, useRef as useRef6, useState as useState5 } from "react";
1803
2636
  function useMarketArb(marketId) {
1804
2637
  const ws = useAggWebSocket();
1805
2638
  const [state, setState] = useState5({ arbReturn: null, isLive: false });
1806
- useEffect6(() => {
2639
+ useEffect8(() => {
1807
2640
  if (!ws || !marketId) return;
1808
2641
  const cached = ws.getArb(marketId);
1809
2642
  if (cached != null) {
@@ -1823,9 +2656,9 @@ var EMPTY_ARB_FEED = {
1823
2656
  function useArbFeed() {
1824
2657
  const ws = useAggWebSocket();
1825
2658
  const [state, setState] = useState5(EMPTY_ARB_FEED);
1826
- const stateRef = useRef4(state);
2659
+ const stateRef = useRef6(state);
1827
2660
  stateRef.current = state;
1828
- useEffect6(() => {
2661
+ useEffect8(() => {
1829
2662
  if (!ws) return;
1830
2663
  const off = ws.subscribeArbFeed((batch) => {
1831
2664
  setState((prev) => {
@@ -1857,7 +2690,9 @@ function useArbFeed() {
1857
2690
  }
1858
2691
 
1859
2692
  // src/use-order-book.ts
1860
- import { keepPreviousData as keepPreviousData3, useQuery as useQuery5 } from "@tanstack/react-query";
2693
+ import { keepPreviousData as keepPreviousData3, useQuery as useQuery7 } from "@tanstack/react-query";
2694
+ var fetchBatchBookQuery = (client, venueMarketIds, { signal }) => client.getOrderbooks({ venueMarketIds }, { signal });
2695
+ var createBatchBookQuery = (client, venueMarketIds) => fetchBatchBookQuery.bind(null, client, venueMarketIds);
1861
2696
  function useOrderBook(options) {
1862
2697
  const client = useAggClient();
1863
2698
  const { orderbooks, enabled = true, canonicalMarketId } = options;
@@ -1870,14 +2705,9 @@ function useOrderBook(options) {
1870
2705
  venueMarketOutcomeId: outcome.id
1871
2706
  })) : void 0
1872
2707
  });
1873
- const batchedResult = useQuery5({
2708
+ const batchedResult = useQuery7({
1874
2709
  queryKey: requestedVenueMarketIds.length ? ["orderbooks", requestedVenueMarketIds, null] : ["orderbooks", "__disabled__", null],
1875
- queryFn: ({ signal }) => client.getOrderbooks(
1876
- {
1877
- venueMarketIds: requestedVenueMarketIds
1878
- },
1879
- { signal }
1880
- ),
2710
+ queryFn: createBatchBookQuery(client, requestedVenueMarketIds),
1881
2711
  enabled: enabled && !canonicalMarketId && requestedVenueMarketIds.length > 0,
1882
2712
  staleTime: 1e4,
1883
2713
  gcTime: 5 * 6e4,
@@ -1938,7 +2768,7 @@ function useOrderBook(options) {
1938
2768
  }
1939
2769
 
1940
2770
  // src/use-orderbook-quote.ts
1941
- import { keepPreviousData as keepPreviousData4, useQuery as useQuery6 } from "@tanstack/react-query";
2771
+ import { keepPreviousData as keepPreviousData4, useQuery as useQuery8 } from "@tanstack/react-query";
1942
2772
  var QUOTE_DEBOUNCE_MS = 300;
1943
2773
  var createUnavailableOrderbookError = (message, code, retryable) => {
1944
2774
  const error = new Error(message);
@@ -2000,7 +2830,7 @@ function useOrderbookQuote(options) {
2000
2830
  const { marketId, side, size, enabled = true } = options;
2001
2831
  const debouncedSize = useDebouncedValue(size, QUOTE_DEBOUNCE_MS);
2002
2832
  const shouldFetch = enabled && !!marketId && debouncedSize > 0;
2003
- const query = useQuery6({
2833
+ const query = useQuery8({
2004
2834
  queryKey: marketId ? marketDataKeys.orderbookQuote(marketId, side, debouncedSize) : ["market-data", "orderbook-quote", "__disabled__"],
2005
2835
  queryFn: () => __async(null, null, function* () {
2006
2836
  var _a2, _b, _c, _d;
@@ -2042,12 +2872,12 @@ function useOrderbookQuote(options) {
2042
2872
  }
2043
2873
 
2044
2874
  // src/use-orders.ts
2045
- import { useQuery as useQuery7 } from "@tanstack/react-query";
2875
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
2046
2876
  function useOrders(options = {}) {
2047
2877
  var _a, _b, _c, _d;
2048
2878
  const client = useAggClient();
2049
2879
  const { userId, status, limit = 50, offset = 0, enabled = true } = options;
2050
- const query = useQuery7({
2880
+ const query = useQuery9({
2051
2881
  queryKey: ["orders", userId != null ? userId : "me", status != null ? status : "all", limit, offset],
2052
2882
  queryFn: () => client.getOrders({
2053
2883
  userId,
@@ -2070,15 +2900,24 @@ import {
2070
2900
  keepPreviousData as keepPreviousData5,
2071
2901
  useInfiniteQuery as useInfiniteQuery5
2072
2902
  } from "@tanstack/react-query";
2073
- import { useContext as useContext2, useEffect as useEffect7, useState as useState6 } from "react";
2903
+ import { useContext as useContext2, useEffect as useEffect9, useState as useState6 } from "react";
2074
2904
  function useSearch(options) {
2075
2905
  var _a, _b, _c, _d;
2076
2906
  const client = useContext2(AggClientContext);
2077
2907
  const queryClient = useContext2(QueryClientContext);
2078
2908
  const [fallbackQueryClient] = useState6(() => new QueryClient());
2079
- const { q, type, categoryIds, status, limit = 20, enabled = true, deep = false } = options;
2909
+ const {
2910
+ q,
2911
+ type,
2912
+ categoryIds,
2913
+ status,
2914
+ limit = 20,
2915
+ enabled = true,
2916
+ deep = false,
2917
+ mode = "full"
2918
+ } = options;
2080
2919
  const isEnabled = enabled && q.length > 0;
2081
- useEffect7(() => {
2920
+ useEffect9(() => {
2082
2921
  if (queryClient) return void 0;
2083
2922
  fallbackQueryClient.mount();
2084
2923
  return () => {
@@ -2088,32 +2927,40 @@ function useSearch(options) {
2088
2927
  if (isEnabled && !client) {
2089
2928
  throw new Error("useSearch must be used within an <AggProvider>");
2090
2929
  }
2930
+ const queryKey = [
2931
+ "search",
2932
+ q,
2933
+ type,
2934
+ (_a = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _a : "",
2935
+ (_b = status == null ? void 0 : status.join(",")) != null ? _b : "",
2936
+ limit,
2937
+ deep,
2938
+ mode
2939
+ ];
2940
+ const effectiveQueryClient = queryClient != null ? queryClient : fallbackQueryClient;
2941
+ const retryOptions = withReadRetry(effectiveQueryClient.defaultQueryOptions({ queryKey }));
2091
2942
  const query = useInfiniteQuery5(
2092
- {
2943
+ __spreadProps(__spreadValues({
2093
2944
  // deep is part of the key — TanStack treats deep vs light as
2094
2945
  // independent queries so users can have both modes cached side-by-side.
2095
- queryKey: [
2096
- "search",
2097
- q,
2098
- type,
2099
- (_a = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _a : "",
2100
- (_b = status == null ? void 0 : status.join(",")) != null ? _b : "",
2101
- limit,
2102
- deep
2103
- ],
2104
- queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
2946
+ queryKey,
2947
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam, signal }) {
2105
2948
  if (!client) {
2106
2949
  throw new Error("useSearch must be used within an <AggProvider>");
2107
2950
  }
2108
- const res = yield client.search({
2109
- q,
2110
- type,
2111
- categoryIds,
2112
- status,
2113
- limit,
2114
- cursor: pageParam,
2115
- deep
2116
- });
2951
+ const res = yield client.search(
2952
+ {
2953
+ q,
2954
+ type,
2955
+ categoryIds,
2956
+ status,
2957
+ limit,
2958
+ cursor: pageParam,
2959
+ deep,
2960
+ mode
2961
+ },
2962
+ { signal }
2963
+ );
2117
2964
  return res;
2118
2965
  }),
2119
2966
  initialPageParam: void 0,
@@ -2122,10 +2969,11 @@ function useSearch(options) {
2122
2969
  if (!lastPage.hasMore) return void 0;
2123
2970
  return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
2124
2971
  },
2125
- placeholderData: keepPreviousData5,
2972
+ placeholderData: keepPreviousData5
2973
+ }, retryOptions), {
2126
2974
  enabled: isEnabled && !!client
2127
- },
2128
- queryClient != null ? queryClient : fallbackQueryClient
2975
+ }),
2976
+ effectiveQueryClient
2129
2977
  );
2130
2978
  const data = (_d = (_c = query.data) == null ? void 0 : _c.pages.flatMap((page) => page.data)) != null ? _d : [];
2131
2979
  return {
@@ -2165,7 +3013,8 @@ function useMarketSearch(options) {
2165
3013
  status,
2166
3014
  limit,
2167
3015
  enabled: suggestionsEnabled,
2168
- deep: false
3016
+ deep: false,
3017
+ mode: "instant"
2169
3018
  });
2170
3019
  const submittedQ = (_a = submittedQuery == null ? void 0 : submittedQuery.trim()) != null ? _a : "";
2171
3020
  const resultsQuery = useSearch({
@@ -2230,7 +3079,7 @@ function useMarketSearch(options) {
2230
3079
  }
2231
3080
 
2232
3081
  // src/use-smart-route.ts
2233
- import { keepPreviousData as keepPreviousData6, useQuery as useQuery8 } from "@tanstack/react-query";
3082
+ import { keepPreviousData as keepPreviousData6, useQuery as useQuery10 } from "@tanstack/react-query";
2234
3083
 
2235
3084
  // src/smart-route-refresh-policy.ts
2236
3085
  var THIN_SMART_ROUTE_REFETCH_INTERVAL_MS = 5e3;
@@ -2370,7 +3219,7 @@ var getIsDocumentVisible = () => {
2370
3219
  return document.visibilityState !== "hidden";
2371
3220
  };
2372
3221
  function useSmartRoute(options) {
2373
- var _a, _b, _c, _d, _e, _f;
3222
+ var _a, _b, _c, _d, _e, _f, _g;
2374
3223
  const client = useAggClient();
2375
3224
  const {
2376
3225
  venueMarketOutcomeId,
@@ -2394,7 +3243,7 @@ function useSmartRoute(options) {
2394
3243
  const resolvedVenueMarketOutcomeId = (_a = venueMarketOutcomeId != null ? venueMarketOutcomeId : venueMarketId) != null ? _a : outcomeId;
2395
3244
  const hasValidInput = (maxSpend != null ? maxSpend : 0) > 0 || (sellShares != null ? sellShares : 0) > 0;
2396
3245
  const queryEnabled = enabled && !!resolvedVenueMarketOutcomeId && hasValidInput;
2397
- const query = useQuery8({
3246
+ const query = useQuery10({
2398
3247
  queryKey: [
2399
3248
  "smart-route",
2400
3249
  resolvedVenueMarketOutcomeId,
@@ -2407,8 +3256,11 @@ function useSmartRoute(options) {
2407
3256
  slipCapBps != null ? slipCapBps : null,
2408
3257
  compareVenues != null ? compareVenues : false,
2409
3258
  deepEstimate != null ? deepEstimate : false,
2410
- ...balanceCacheScope ? [(_b = balanceCacheScope.accountId) != null ? _b : null, (_c = balanceCacheScope.balanceVersion) != null ? _c : null] : [],
2411
- ...tradeSide === "sell" ? [(_d = sellCacheScope == null ? void 0 : sellCacheScope.accountId) != null ? _d : null, (_e = sellCacheScope == null ? void 0 : sellCacheScope.positionVersion) != null ? _e : null] : []
3259
+ ...balanceCacheScope ? [
3260
+ (_b = balanceCacheScope.accountId) != null ? _b : null,
3261
+ (_d = (_c = balanceCacheScope.balanceKey) != null ? _c : balanceCacheScope.balanceVersion) != null ? _d : null
3262
+ ] : [],
3263
+ ...tradeSide === "sell" ? [(_e = sellCacheScope == null ? void 0 : sellCacheScope.accountId) != null ? _e : null, (_f = sellCacheScope == null ? void 0 : sellCacheScope.positionVersion) != null ? _f : null] : []
2412
3264
  ],
2413
3265
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
2414
3266
  return client.getSmartRoute(
@@ -2466,7 +3318,7 @@ function useSmartRoute(options) {
2466
3318
  }
2467
3319
  }
2468
3320
  return {
2469
- data: (_f = query.data) != null ? _f : null,
3321
+ data: (_g = query.data) != null ? _g : null,
2470
3322
  isLoading: query.isLoading,
2471
3323
  isFetching: query.isFetching,
2472
3324
  error: error instanceof Error ? error : error ? new Error(String(error)) : null,
@@ -2476,7 +3328,7 @@ function useSmartRoute(options) {
2476
3328
  }
2477
3329
 
2478
3330
  // src/use-limit-order-venue-quotes.ts
2479
- import { keepPreviousData as keepPreviousData7, useQueries as useQueries6, useQuery as useQuery9 } from "@tanstack/react-query";
3331
+ import { keepPreviousData as keepPreviousData7, useQueries as useQueries4, useQuery as useQuery11 } from "@tanstack/react-query";
2480
3332
  var getIsDocumentVisible2 = () => {
2481
3333
  if (typeof document === "undefined") return true;
2482
3334
  return document.visibilityState !== "hidden";
@@ -2531,7 +3383,7 @@ var useLimitOrderVenueQuotes = (options) => {
2531
3383
  const hasRequiredAccount = tradeSide === "buy" || Boolean(accountId);
2532
3384
  const queryEnabled = enabled && hasValidInput && hasRequiredAccount;
2533
3385
  const serializedChainBalances = chainBalances ? JSON.stringify(chainBalances) : null;
2534
- const tickMetadataQuery = useQuery9({
3386
+ const tickMetadataQuery = useQuery11({
2535
3387
  queryKey: ["orderbooks", marketId != null ? marketId : "__disabled__", "limit-order-ticks"],
2536
3388
  queryFn: ({ signal }) => client.getOrderbooks({ venueMarketIds: [marketId] }, { signal }),
2537
3389
  enabled: enabled && Boolean(marketId),
@@ -2540,7 +3392,7 @@ var useLimitOrderVenueQuotes = (options) => {
2540
3392
  refetchOnWindowFocus: false,
2541
3393
  retry: 1
2542
3394
  });
2543
- const queries = useQueries6({
3395
+ const queries = useQueries4({
2544
3396
  queries: uniqueRequests.map((request) => ({
2545
3397
  queryKey: [
2546
3398
  "smart-route",
@@ -2622,7 +3474,7 @@ var useLimitOrderVenueQuotes = (options) => {
2622
3474
  };
2623
3475
 
2624
3476
  // src/use-venue-sell-quotes.ts
2625
- import { useQueries as useQueries7 } from "@tanstack/react-query";
3477
+ import { useQueries as useQueries5 } from "@tanstack/react-query";
2626
3478
  var getIsDocumentVisible3 = () => {
2627
3479
  if (typeof document === "undefined") return true;
2628
3480
  return document.visibilityState !== "hidden";
@@ -2653,7 +3505,7 @@ var useVenueSellQuotes = (options) => {
2653
3505
  refreshContext
2654
3506
  } = options;
2655
3507
  const uniqueRequests = getUniqueVenueRequests2(requests);
2656
- const queries = useQueries7({
3508
+ const queries = useQueries5({
2657
3509
  queries: uniqueRequests.map((request) => {
2658
3510
  const hasValidInput = request.requestedSellShares > 0 && request.sellShares > 0 && request.availableShares > 0;
2659
3511
  const queryEnabled = enabled && !!venueMarketOutcomeId && !!accountId && hasValidInput;
@@ -2768,13 +3620,13 @@ function useUserHoldings(options) {
2768
3620
  }
2769
3621
 
2770
3622
  // src/use-enriched-venue-event.ts
2771
- import { useMemo as useMemo10 } from "react";
3623
+ import { useMemo as useMemo11 } from "react";
2772
3624
 
2773
3625
  // src/use-venue-event.ts
2774
- import { useQuery as useQuery11 } from "@tanstack/react-query";
3626
+ import { useQuery as useQuery13 } from "@tanstack/react-query";
2775
3627
 
2776
3628
  // src/use-recurring-crypto-markets.ts
2777
- import { useQuery as useQuery10 } from "@tanstack/react-query";
3629
+ import { useQuery as useQuery12 } from "@tanstack/react-query";
2778
3630
  var RESOLVING_POLL_INTERVAL_MS = 15e3;
2779
3631
  var FALLBACK_VENUE_EVENT_PAGE_LIMIT = 100;
2780
3632
  var FALLBACK_VENUE_EVENT_MAX_PAGES = 5;
@@ -3274,7 +4126,7 @@ var useRecurringCryptoMarkets = ({
3274
4126
  const client = useAggClient();
3275
4127
  const identity = event ? resolveRecurringCryptoIdentity(event) : null;
3276
4128
  const isEnabled = enabled && event != null && identity != null;
3277
- const query = useQuery10({
4129
+ const query = useQuery12({
3278
4130
  queryKey: [
3279
4131
  "recurring-crypto-markets",
3280
4132
  event == null ? void 0 : event.id,
@@ -3336,7 +4188,7 @@ function useVenueEvent(options) {
3336
4188
  var _a;
3337
4189
  const client = useAggClient();
3338
4190
  const { eventId, enabled = true, cluster } = options;
3339
- const query = useQuery11({
4191
+ const query = useQuery13({
3340
4192
  queryKey: ["venue-event", eventId, cluster === false ? "no-cluster" : ""],
3341
4193
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
3342
4194
  return client.getVenueEventById(eventId, { signal, cluster });
@@ -3357,7 +4209,7 @@ function useVenueEvent(options) {
3357
4209
 
3358
4210
  // src/use-venue-markets.ts
3359
4211
  import { QueryClient as QueryClient2, QueryClientContext as QueryClientContext2, useInfiniteQuery as useInfiniteQuery7 } from "@tanstack/react-query";
3360
- import { useContext as useContext3, useEffect as useEffect8, useState as useState8 } from "react";
4212
+ import { useContext as useContext3, useEffect as useEffect10, useState as useState8 } from "react";
3361
4213
  function useVenueMarkets(options) {
3362
4214
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3363
4215
  const client = useContext3(AggClientContext);
@@ -3379,7 +4231,7 @@ function useVenueMarkets(options) {
3379
4231
  const sortBy = options == null ? void 0 : options.sortBy;
3380
4232
  const sortDir = options == null ? void 0 : options.sortDir;
3381
4233
  const context = options == null ? void 0 : options.context;
3382
- useEffect8(() => {
4234
+ useEffect10(() => {
3383
4235
  if (queryClient) return void 0;
3384
4236
  fallbackQueryClient.mount();
3385
4237
  return () => {
@@ -3409,28 +4261,31 @@ function useVenueMarkets(options) {
3409
4261
  sortDir != null ? sortDir : "",
3410
4262
  context != null ? context : ""
3411
4263
  ],
3412
- queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
4264
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam, signal }) {
3413
4265
  if (!client) {
3414
4266
  throw new Error("useVenueMarkets must be used within an <AggProvider>");
3415
4267
  }
3416
- const res = yield client.getVenueMarkets({
3417
- venue,
3418
- venueEventId,
3419
- cluster,
3420
- search,
3421
- matchStatus,
3422
- status,
3423
- aggKey,
3424
- sportsMarketType,
3425
- period,
3426
- marketCategory,
3427
- marketGroup,
3428
- limit,
3429
- cursor: pageParam,
3430
- sortBy,
3431
- sortDir,
3432
- context
3433
- });
4268
+ const res = yield client.getVenueMarkets(
4269
+ {
4270
+ venue,
4271
+ venueEventId,
4272
+ cluster,
4273
+ search,
4274
+ matchStatus,
4275
+ status,
4276
+ aggKey,
4277
+ sportsMarketType,
4278
+ period,
4279
+ marketCategory,
4280
+ marketGroup,
4281
+ limit,
4282
+ cursor: pageParam,
4283
+ sortBy,
4284
+ sortDir,
4285
+ context
4286
+ },
4287
+ { signal }
4288
+ );
3434
4289
  return res;
3435
4290
  }),
3436
4291
  initialPageParam: void 0,
@@ -3447,10 +4302,10 @@ function useVenueMarkets(options) {
3447
4302
  const hasNextPage = !!query.hasNextPage;
3448
4303
  const { fetchNextPage, isFetchingNextPage } = query;
3449
4304
  const fetchAll = (_j = options == null ? void 0 : options.fetchAll) != null ? _j : false;
3450
- useEffect8(() => {
3451
- if (!fetchAll || !hasNextPage || isFetchingNextPage) return;
4305
+ useEffect10(() => {
4306
+ if (!enabled || !client || !fetchAll || !hasNextPage || isFetchingNextPage) return;
3452
4307
  void fetchNextPage();
3453
- }, [fetchAll, hasNextPage, isFetchingNextPage, fetchNextPage]);
4308
+ }, [enabled, client, fetchAll, hasNextPage, isFetchingNextPage, fetchNextPage]);
3454
4309
  return __spreadProps(__spreadValues({}, query), {
3455
4310
  markets,
3456
4311
  hasNextPage
@@ -3473,7 +4328,7 @@ function useEnrichedVenueEvent(options) {
3473
4328
  const _a = useVenueEvent(options), { event, isLoading, error } = _a, rest = __objRest(_a, ["event", "isLoading", "error"]);
3474
4329
  const eventEndedAt = (event == null ? void 0 : event.endDate) && Number.isFinite(Date.parse(event.endDate)) ? Date.parse(event.endDate) : null;
3475
4330
  const shouldFetchOnlyOpenMarkets = eventEndedAt == null || eventEndedAt >= Date.now();
3476
- const { markets: openMarkets, isLoading: isEnrichingOpenMarkets } = useVenueMarkets({
4331
+ const openQuery = useVenueMarkets({
3477
4332
  venueEventId: options.eventId,
3478
4333
  cluster: options.cluster,
3479
4334
  enabled: ((_b = options.enabled) != null ? _b : true) && !!event,
@@ -3483,10 +4338,11 @@ function useEnrichedVenueEvent(options) {
3483
4338
  // MarketDetailsList (including limit, part of the query key) preserves the
3484
4339
  // shared React Query cache key and the event-type ordering.
3485
4340
  limit: 100,
3486
- fetchAll: true
4341
+ fetchAll: !options.progressive
3487
4342
  });
4343
+ const { markets: openMarkets, isLoading: isEnrichingOpenMarkets } = openQuery;
3488
4344
  const shouldFetchAllMarketsFallback = ((_c = options.enabled) != null ? _c : true) && !!event && shouldFetchOnlyOpenMarkets && !isEnrichingOpenMarkets && openMarkets.length === 0;
3489
- const { markets: fallbackMarkets, isLoading: isEnrichingFallbackMarkets } = useVenueMarkets({
4345
+ const fallbackQuery = useVenueMarkets({
3490
4346
  venueEventId: options.eventId,
3491
4347
  cluster: options.cluster,
3492
4348
  enabled: shouldFetchAllMarketsFallback,
@@ -3494,11 +4350,13 @@ function useEnrichedVenueEvent(options) {
3494
4350
  // closed/resolved markets, still render the event page instead of the
3495
4351
  // unavailable state.
3496
4352
  limit: 100,
3497
- fetchAll: true
4353
+ fetchAll: !options.progressive
3498
4354
  });
4355
+ const { markets: fallbackMarkets, isLoading: isEnrichingFallbackMarkets } = fallbackQuery;
4356
+ const activeQuery = shouldFetchAllMarketsFallback ? fallbackQuery : openQuery;
3499
4357
  const markets = fallbackMarkets.length > 0 ? fallbackMarkets : openMarkets;
3500
4358
  const isEnriching = isEnrichingOpenMarkets || isEnrichingFallbackMarkets;
3501
- const enrichedEvent = useMemo10(() => {
4359
+ const enrichedEvent = useMemo11(() => {
3502
4360
  if (!event) return void 0;
3503
4361
  if (markets.length === 0) return event;
3504
4362
  return mergeEventWithFullMarkets(event, markets);
@@ -3507,6 +4365,9 @@ function useEnrichedVenueEvent(options) {
3507
4365
  event: enrichedEvent,
3508
4366
  isLoading,
3509
4367
  isEnriching,
4368
+ hasMoreMarkets: !!activeQuery.hasNextPage,
4369
+ loadMoreMarkets: activeQuery.fetchNextPage,
4370
+ isLoadingMoreMarkets: !!activeQuery.isFetchingNextPage,
3510
4371
  error
3511
4372
  });
3512
4373
  }
@@ -3518,7 +4379,7 @@ import {
3518
4379
  keepPreviousData as keepPreviousData8,
3519
4380
  useInfiniteQuery as useInfiniteQuery8
3520
4381
  } from "@tanstack/react-query";
3521
- import { useContext as useContext4, useEffect as useEffect9, useMemo as useMemo11, useRef as useRef5, useState as useState9 } from "react";
4382
+ import { useContext as useContext4, useEffect as useEffect11, useMemo as useMemo12, useRef as useRef7, useState as useState9 } from "react";
3522
4383
  function useVenueEvents(options) {
3523
4384
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3524
4385
  const client = useContext4(AggClientContext);
@@ -3540,7 +4401,7 @@ function useVenueEvents(options) {
3540
4401
  const endDateFrom = options == null ? void 0 : options.endDateFrom;
3541
4402
  const grouped = options == null ? void 0 : options.grouped;
3542
4403
  const initialPages = options == null ? void 0 : options.initialPages;
3543
- useEffect9(() => {
4404
+ useEffect11(() => {
3544
4405
  if (queryClient) return void 0;
3545
4406
  fallbackQueryClient.mount();
3546
4407
  return () => {
@@ -3568,7 +4429,7 @@ function useVenueEvents(options) {
3568
4429
  grouped != null ? grouped : false,
3569
4430
  limit
3570
4431
  ],
3571
- queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
4432
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam, signal }) {
3572
4433
  if (!client) {
3573
4434
  throw new Error("useVenueEvents must be used within an <AggProvider>");
3574
4435
  }
@@ -3586,7 +4447,8 @@ function useVenueEvents(options) {
3586
4447
  maxYesPrice,
3587
4448
  endDateFrom,
3588
4449
  grouped,
3589
- cursor: pageParam
4450
+ cursor: pageParam,
4451
+ signal
3590
4452
  });
3591
4453
  return res;
3592
4454
  }),
@@ -3602,12 +4464,13 @@ function useVenueEvents(options) {
3602
4464
  },
3603
4465
  queryClient != null ? queryClient : fallbackQueryClient
3604
4466
  );
3605
- const prefetchedRef = useRef5(false);
3606
- useEffect9(() => {
4467
+ const prefetchedRef = useRef7(false);
4468
+ useEffect11(() => {
3607
4469
  var _a2, _b2;
4470
+ if (!enabled || !client) return;
3608
4471
  if (prefetchedRef.current) return;
3609
4472
  if (!initialPages || initialPages <= 1) return;
3610
- if (query.isLoading) return;
4473
+ if (query.isLoading || query.isFetching || query.isError || query.isPlaceholderData) return;
3611
4474
  const pagesLoaded = (_b2 = (_a2 = query.data) == null ? void 0 : _a2.pages.length) != null ? _b2 : 0;
3612
4475
  if (pagesLoaded >= initialPages || !query.hasNextPage) {
3613
4476
  prefetchedRef.current = true;
@@ -3615,13 +4478,18 @@ function useVenueEvents(options) {
3615
4478
  }
3616
4479
  void query.fetchNextPage();
3617
4480
  }, [
4481
+ enabled,
4482
+ client,
3618
4483
  initialPages,
3619
4484
  query.isLoading,
4485
+ query.isFetching,
4486
+ query.isError,
4487
+ query.isPlaceholderData,
3620
4488
  (_h = query.data) == null ? void 0 : _h.pages.length,
3621
4489
  query.hasNextPage,
3622
4490
  query.fetchNextPage
3623
4491
  ]);
3624
- const events = useMemo11(
4492
+ const events = useMemo12(
3625
4493
  () => {
3626
4494
  var _a2, _b2;
3627
4495
  return (_b2 = (_a2 = query.data) == null ? void 0 : _a2.pages.flatMap((page) => page.data)) != null ? _b2 : [];
@@ -3639,7 +4507,7 @@ function useVenueEvents(options) {
3639
4507
  }
3640
4508
 
3641
4509
  // src/use-sports-live.ts
3642
- import { useQuery as useQuery12 } from "@tanstack/react-query";
4510
+ import { useQuery as useQuery14 } from "@tanstack/react-query";
3643
4511
  var SPORTS_LIVE_POLL_INTERVAL_MS = 5e3;
3644
4512
  var SPORTS_SCHEDULED_POLL_INTERVAL_MS = 3e4;
3645
4513
  var sportsLiveQueryKey = (sortedEventIds) => ["sports-live", ...sortedEventIds];
@@ -3659,7 +4527,7 @@ var useSportsLive = (eventIds, enabled = true) => {
3659
4527
  const sortedEventIds = [
3660
4528
  ...new Set(eventIds.map((eventId) => eventId.trim()).filter(Boolean))
3661
4529
  ].sort();
3662
- const query = useQuery12({
4530
+ const query = useQuery14({
3663
4531
  queryKey: sportsLiveQueryKey(sortedEventIds),
3664
4532
  queryFn: ({ signal }) => client.getSportsLive(sortedEventIds, { signal }),
3665
4533
  enabled: enabled && sortedEventIds.length > 0,
@@ -3679,7 +4547,7 @@ var useSportsLive = (eventIds, enabled = true) => {
3679
4547
  };
3680
4548
 
3681
4549
  // src/use-venue-market-midpoints.ts
3682
- import { keepPreviousData as keepPreviousData9, useQuery as useQuery13 } from "@tanstack/react-query";
4550
+ import { keepPreviousData as keepPreviousData9, useQuery as useQuery15 } from "@tanstack/react-query";
3683
4551
  var normalizeVenueMarketIds2 = (venueMarketIds) => {
3684
4552
  return [
3685
4553
  ...new Set(venueMarketIds.map((venueMarketId) => venueMarketId.trim()).filter(Boolean))
@@ -3718,7 +4586,7 @@ function useVenueMarketMidpoints(options) {
3718
4586
  const enabled = (_a = options.enabled) != null ? _a : true;
3719
4587
  const requestedVenueMarketIds = normalizeVenueMarketIds2(options.venueMarketIds);
3720
4588
  const maxMidpointIdsPerRequest = (_b = options.maxMidpointIdsPerRequest) != null ? _b : configuredMaxMidpointIdsPerRequest;
3721
- const query = useQuery13({
4589
+ const query = useQuery15({
3722
4590
  queryKey: requestedVenueMarketIds.length ? ["venue-market-midpoints", requestedVenueMarketIds, maxMidpointIdsPerRequest] : ["venue-market-midpoints", "__disabled__"],
3723
4591
  queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
3724
4592
  if (requestedVenueMarketIds.length === 0) {
@@ -3794,7 +4662,7 @@ var computePriceGaps = ({
3794
4662
  };
3795
4663
 
3796
4664
  // src/use-viewport-midpoints.ts
3797
- import { useEffect as useEffect10, useMemo as useMemo12, useRef as useRef6, useState as useState10 } from "react";
4665
+ import { useEffect as useEffect12, useMemo as useMemo13, useRef as useRef8, useState as useState10 } from "react";
3798
4666
  var buildOutcomeMidpointMap = (outcomes) => {
3799
4667
  const m = /* @__PURE__ */ new Map();
3800
4668
  if (!outcomes) return m;
@@ -3848,14 +4716,14 @@ function useViewportMidpoints(visibleMarkets, options) {
3848
4716
  } = useAggUiConfig();
3849
4717
  const maxMidpointIdsPerRequest = (_a = options == null ? void 0 : options.maxMidpointIdsPerRequest) != null ? _a : configuredMaxMidpointIdsPerRequest;
3850
4718
  const [cache, setCache] = useState10(() => /* @__PURE__ */ new Map());
3851
- const inFlightRef = useRef6(/* @__PURE__ */ new Set());
3852
- const visibleRef = useRef6(visibleMarkets);
4719
+ const inFlightRef = useRef8(/* @__PURE__ */ new Set());
4720
+ const visibleRef = useRef8(visibleMarkets);
3853
4721
  visibleRef.current = visibleMarkets;
3854
- const visibleFp = useMemo12(
4722
+ const visibleFp = useMemo13(
3855
4723
  () => [...new Set(visibleMarkets.map((m) => m.id))].sort().join("|"),
3856
4724
  [visibleMarkets]
3857
4725
  );
3858
- useEffect10(() => {
4726
+ useEffect12(() => {
3859
4727
  const toFetch = resolveUncachedVisibleMarketIds(visibleRef.current, cache, inFlightRef.current);
3860
4728
  if (!toFetch.length) return;
3861
4729
  let cancelled = false;
@@ -3879,7 +4747,7 @@ function useViewportMidpoints(visibleMarkets, options) {
3879
4747
  cancelled = true;
3880
4748
  };
3881
4749
  }, [visibleFp, cache, maxMidpointIdsPerRequest]);
3882
- const { prices, venueByOutcomeId } = useMemo12(() => {
4750
+ const { prices, venueByOutcomeId } = useMemo13(() => {
3883
4751
  var _a2, _b, _c, _d;
3884
4752
  const map = /* @__PURE__ */ new Map();
3885
4753
  const venueMap = /* @__PURE__ */ new Map();
@@ -3912,15 +4780,15 @@ function useViewportMidpoints(visibleMarkets, options) {
3912
4780
  }
3913
4781
 
3914
4782
  // src/use-visible-ids.ts
3915
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef7, useState as useState11 } from "react";
4783
+ import { useCallback as useCallback7, useEffect as useEffect13, useRef as useRef9, useState as useState11 } from "react";
3916
4784
  function useVisibleIds(options = {}) {
3917
4785
  const { rootMargin = "0px", threshold = 0 } = options;
3918
4786
  const [visibleIds, setVisibleIds] = useState11(() => /* @__PURE__ */ new Set());
3919
- const observerRef = useRef7(null);
3920
- const elementsRef = useRef7(/* @__PURE__ */ new Map());
3921
- const elementIdRef = useRef7(/* @__PURE__ */ new WeakMap());
3922
- const callbackRefsRef = useRef7(/* @__PURE__ */ new Map());
3923
- useEffect11(() => {
4787
+ const observerRef = useRef9(null);
4788
+ const elementsRef = useRef9(/* @__PURE__ */ new Map());
4789
+ const elementIdRef = useRef9(/* @__PURE__ */ new WeakMap());
4790
+ const callbackRefsRef = useRef9(/* @__PURE__ */ new Map());
4791
+ useEffect13(() => {
3924
4792
  if (typeof IntersectionObserver === "undefined") return;
3925
4793
  const observer = new IntersectionObserver(
3926
4794
  (entries) => {
@@ -3985,7 +4853,7 @@ function useVisibleIds(options = {}) {
3985
4853
  }
3986
4854
 
3987
4855
  // src/use-paper-onboarding.ts
3988
- import { useCallback as useCallback8, useEffect as useEffect12, useState as useState12 } from "react";
4856
+ import { useCallback as useCallback8, useEffect as useEffect14, useState as useState12 } from "react";
3989
4857
  var STORAGE_KEY = "agg_paper_onboarding_seen";
3990
4858
  var isBrowser = () => typeof window !== "undefined" && "localStorage" in window;
3991
4859
  var seenKey = (userId) => `${STORAGE_KEY}:${userId}`;
@@ -4010,14 +4878,14 @@ function usePaperOnboarding() {
4010
4878
  const userId = user == null ? void 0 : user.id;
4011
4879
  const [dismissed, setDismissed] = useState12(false);
4012
4880
  const [seen, setSeen] = useState12(null);
4013
- useEffect12(() => {
4881
+ useEffect14(() => {
4014
4882
  if (!userId) {
4015
4883
  setSeen(null);
4016
4884
  return;
4017
4885
  }
4018
4886
  setSeen(hasSeen(userId));
4019
4887
  }, [userId]);
4020
- useEffect12(() => {
4888
+ useEffect14(() => {
4021
4889
  setDismissed(false);
4022
4890
  }, [userId]);
4023
4891
  const dismiss = useCallback8(() => {
@@ -4027,6 +4895,206 @@ function usePaperOnboarding() {
4027
4895
  const isOpen = isPaperMode && !isResolving && isAuthenticated && Boolean(userId) && seen === false && !dismissed;
4028
4896
  return { isOpen, dismiss };
4029
4897
  }
4898
+
4899
+ // src/use-settlement-details-data.ts
4900
+ import { useQuery as useQuery16 } from "@tanstack/react-query";
4901
+ function useSettlementDetailsData(options) {
4902
+ const client = useAggClient();
4903
+ const { eventId, market, enabled, needsEvent, needsMarket } = options;
4904
+ const eventQuery = useQuery16({
4905
+ queryKey: ["settlement-details", "event", client.appId, eventId],
4906
+ queryFn: ({ signal }) => client.getVenueEventById(eventId, { signal }),
4907
+ enabled: enabled && needsEvent,
4908
+ staleTime: 5 * 6e4,
4909
+ gcTime: 10 * 6e4,
4910
+ retry: false
4911
+ });
4912
+ const marketQuery = useQuery16({
4913
+ queryKey: ["settlement-details", "market", client.appId, market.id],
4914
+ queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
4915
+ const response = yield client.getVenueMarkets(
4916
+ { venue: market.venue, externalIdentifier: [market.externalIdentifier], limit: 1 },
4917
+ { signal }
4918
+ );
4919
+ const selected = response.data.find((candidate) => candidate.id === market.id);
4920
+ if (!selected) throw new Error("Selected market details unavailable");
4921
+ return { selected, markets: response.data };
4922
+ }),
4923
+ enabled: enabled && needsMarket,
4924
+ staleTime: 5 * 6e4,
4925
+ gcTime: 10 * 6e4,
4926
+ retry: false
4927
+ });
4928
+ return { eventQuery, marketQuery };
4929
+ }
4930
+
4931
+ // src/use-hosted-venue-transfers.ts
4932
+ import { useEffect as useEffect15, useRef as useRef10, useState as useState13 } from "react";
4933
+ import { useMutation as useMutation2, useQuery as useQuery17, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
4934
+ var validRequest = (value) => {
4935
+ var _a;
4936
+ const row = value;
4937
+ return !!row && ((_a = row.request) == null ? void 0 : _a.mode) === "live" && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
4938
+ row.request.requestId
4939
+ ) && /^[1-9][0-9]{0,31}$/.test(row.request.amountRaw) && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(row.request.destinationAddress) && (row.withdrawalId === void 0 || /^[a-zA-Z0-9_-]{1,256}$/.test(row.withdrawalId));
4940
+ };
4941
+ function useHostedVenueTransfers(accountId, environment) {
4942
+ var _a, _b, _c, _d, _e;
4943
+ const client = useAggClient();
4944
+ const { user, isAuthenticated } = useAggAuthContext();
4945
+ const { executionMode, isResolving } = useResolvedExecutionMode();
4946
+ const queryClient = useQueryClient4();
4947
+ const userId = (_a = user == null ? void 0 : user.id) != null ? _a : null;
4948
+ const permitted = isAuthenticated && !!userId && !isResolving && executionMode === "live";
4949
+ const scope = JSON.stringify([userId, accountId, environment]);
4950
+ const storageKey = "agg:betdex-withdrawal:" + scope;
4951
+ const [entry, setEntry] = useState13({
4952
+ scope: "",
4953
+ ready: false,
4954
+ journal: null,
4955
+ invalid: false
4956
+ });
4957
+ const session = useRef10({ client, scope, permitted });
4958
+ session.current = { client, scope, permitted };
4959
+ const mounted = useRef10(true);
4960
+ const dispatching = useRef10(false);
4961
+ const intent = useRef10(null);
4962
+ const current = entry.scope === scope ? entry : null;
4963
+ const journal = (_b = current == null ? void 0 : current.journal) != null ? _b : null;
4964
+ const assertSession = () => {
4965
+ if (!mounted.current || !permitted || !session.current.permitted || session.current.client !== client || session.current.scope !== scope)
4966
+ throw new Error("Hosted transfers are unavailable for this session");
4967
+ };
4968
+ const save = (next) => {
4969
+ localStorage.setItem(storageKey, JSON.stringify(next));
4970
+ if (mounted.current && session.current.scope === scope) {
4971
+ intent.current = { scope, journal: next };
4972
+ setEntry({ scope, ready: true, journal: next, invalid: false });
4973
+ }
4974
+ };
4975
+ const assertResult = (result2) => {
4976
+ if (result2.accountId !== accountId || result2.environment !== environment)
4977
+ throw new Error("Hosted transfer identity mismatch");
4978
+ };
4979
+ const invalidate = () => {
4980
+ void queryClient.invalidateQueries({
4981
+ queryKey: hostedVenueAccountQueryKeys.account("betdex", userId, "live")
4982
+ });
4983
+ invalidateBalanceQueries(queryClient);
4984
+ };
4985
+ const deposit = useMutation2({
4986
+ mutationFn: () => __async(null, null, function* () {
4987
+ assertSession();
4988
+ const result2 = yield client.getHostedVenueDepositAddress("betdex", { mode: "live" });
4989
+ assertResult(result2);
4990
+ assertSession();
4991
+ return { scope, result: result2 };
4992
+ }),
4993
+ retry: false
4994
+ });
4995
+ const withdrawal = useMutation2({
4996
+ mutationFn: (request) => __async(null, null, function* () {
4997
+ assertSession();
4998
+ if (dispatching.current) throw new Error("Withdrawal request is already pending");
4999
+ dispatching.current = true;
5000
+ try {
5001
+ save(request);
5002
+ const result2 = request.withdrawalId ? yield client.getHostedVenueWithdrawal("betdex", request.withdrawalId, { mode: "live" }) : yield client.withdrawHostedVenue("betdex", request.request);
5003
+ assertResult(result2);
5004
+ save(__spreadProps(__spreadValues({}, request), { withdrawalId: result2.id }));
5005
+ assertSession();
5006
+ invalidate();
5007
+ return { scope, result: result2 };
5008
+ } finally {
5009
+ dispatching.current = false;
5010
+ }
5011
+ }),
5012
+ retry: false
5013
+ });
5014
+ const status = useQuery17({
5015
+ queryKey: ["agg", "hosted-venue-withdrawal", scope, journal == null ? void 0 : journal.withdrawalId],
5016
+ queryFn: () => __async(null, null, function* () {
5017
+ assertSession();
5018
+ if (!(journal == null ? void 0 : journal.withdrawalId)) throw new Error("Withdrawal identity is unavailable");
5019
+ const result2 = yield client.getHostedVenueWithdrawal("betdex", journal.withdrawalId, {
5020
+ mode: "live"
5021
+ });
5022
+ assertResult(result2);
5023
+ assertSession();
5024
+ if (result2.status === "confirmed" || result2.status === "failed") invalidate();
5025
+ return result2;
5026
+ }),
5027
+ enabled: permitted && !!(journal == null ? void 0 : journal.withdrawalId),
5028
+ retry: false,
5029
+ refetchInterval: (query) => {
5030
+ var _a2;
5031
+ return ((_a2 = query.state.data) == null ? void 0 : _a2.status) === "processing" ? 2e3 : false;
5032
+ },
5033
+ refetchIntervalInBackground: false
5034
+ });
5035
+ useEffect15(() => {
5036
+ mounted.current = true;
5037
+ return () => {
5038
+ mounted.current = false;
5039
+ };
5040
+ }, []);
5041
+ const resetDeposit = deposit.reset;
5042
+ const resetWithdrawal = withdrawal.reset;
5043
+ useEffect15(() => {
5044
+ resetDeposit();
5045
+ resetWithdrawal();
5046
+ if (!permitted) return;
5047
+ try {
5048
+ const text = localStorage.getItem(storageKey);
5049
+ const value = text ? JSON.parse(text) : null;
5050
+ if (value !== null && !validRequest(value)) throw new Error("Invalid saved withdrawal");
5051
+ intent.current = value ? { scope, journal: value } : null;
5052
+ setEntry({ scope, ready: true, journal: value, invalid: false });
5053
+ } catch (e) {
5054
+ setEntry({ scope, ready: false, journal: null, invalid: true });
5055
+ }
5056
+ }, [storageKey, scope, permitted, resetDeposit, resetWithdrawal]);
5057
+ const result = (_d = status.data) != null ? _d : ((_c = withdrawal.data) == null ? void 0 : _c.scope) === scope ? withdrawal.data.result : void 0;
5058
+ const terminal = (result == null ? void 0 : result.status) === "confirmed" || (result == null ? void 0 : result.status) === "failed";
5059
+ return {
5060
+ isAvailable: permitted,
5061
+ ready: !!(current == null ? void 0 : current.ready),
5062
+ storageError: !!(current == null ? void 0 : current.invalid),
5063
+ deposit: __spreadProps(__spreadValues({}, deposit), { data: ((_e = deposit.data) == null ? void 0 : _e.scope) === scope ? deposit.data.result : void 0 }),
5064
+ withdrawal: __spreadProps(__spreadValues({}, withdrawal), { data: result, isError: withdrawal.isError || status.isError }),
5065
+ request: journal == null ? void 0 : journal.request,
5066
+ submit: (amountRaw, destinationAddress) => __async(null, null, function* () {
5067
+ var _a2;
5068
+ assertSession();
5069
+ if (!(current == null ? void 0 : current.ready) || current.invalid || journal || ((_a2 = intent.current) == null ? void 0 : _a2.scope) === scope)
5070
+ throw new Error("Resolve the existing withdrawal first");
5071
+ const request = {
5072
+ mode: "live",
5073
+ requestId: crypto.randomUUID(),
5074
+ amountRaw,
5075
+ destinationAddress
5076
+ };
5077
+ if (!validRequest({ request })) throw new Error("Invalid withdrawal request");
5078
+ save({ request });
5079
+ return withdrawal.mutateAsync({ request });
5080
+ }),
5081
+ check: () => __async(null, null, function* () {
5082
+ assertSession();
5083
+ if (!journal || !(current == null ? void 0 : current.ready)) throw new Error("No saved withdrawal");
5084
+ return withdrawal.mutateAsync(journal);
5085
+ }),
5086
+ clear: () => {
5087
+ var _a2;
5088
+ assertSession();
5089
+ if (!terminal || dispatching.current || ((_a2 = intent.current) == null ? void 0 : _a2.journal.withdrawalId) !== (result == null ? void 0 : result.id))
5090
+ throw new Error("Withdrawal is not terminal");
5091
+ localStorage.removeItem(storageKey);
5092
+ intent.current = null;
5093
+ setEntry({ scope, ready: true, journal: null, invalid: false });
5094
+ withdrawal.reset();
5095
+ }
5096
+ };
5097
+ }
4030
5098
  export {
4031
5099
  AUTH_CHOOSER_OPEN_EVENT,
4032
5100
  AggBalanceProvider,
@@ -4037,6 +5105,7 @@ export {
4037
5105
  CONFIRMED_MATCH_STATUSES,
4038
5106
  DEFAULT_AGG_ROOT_CLASS_NAME,
4039
5107
  EventListStateProvider,
5108
+ MAX_ORDER_VENUE_MARKET_IDS_PER_REQUEST,
4040
5109
  MAX_PRICE_GAP_PCT,
4041
5110
  MIN_PRICE_GAP_PCT,
4042
5111
  MarketStatus,
@@ -4067,6 +5136,7 @@ export {
4067
5136
  getVisibleVenueIdsByConfig,
4068
5137
  getVisibleVenuesByConfig,
4069
5138
  getWalletAddressFromUserProfile,
5139
+ hostedVenueAccountQueryKeys,
4070
5140
  invalidateBalanceQueries,
4071
5141
  invalidatePositionQueries,
4072
5142
  invalidateUserActivityQueries,
@@ -4092,6 +5162,7 @@ export {
4092
5162
  resolveRecurringCryptoTimeline,
4093
5163
  resolveRollingWindow,
4094
5164
  resolveTradingStateKind,
5165
+ retinaImageUrl,
4095
5166
  sharedKycQueryKeys,
4096
5167
  sortVenues,
4097
5168
  sportsLiveQueryKey,
@@ -4123,10 +5194,14 @@ export {
4123
5194
  useEventTradingContext,
4124
5195
  useExecuteManaged,
4125
5196
  useExecutionOrders,
5197
+ useExecutionOrdersForMarkets,
4126
5198
  useExecutionPositions,
4127
5199
  useExecutionProgress,
4128
5200
  useExternalId,
4129
5201
  useGeoBlock,
5202
+ useHostedVenueAccount,
5203
+ useHostedVenueActivity,
5204
+ useHostedVenueTransfers,
4130
5205
  useLabels,
4131
5206
  useLimitOrderVenueQuotes,
4132
5207
  useLinkAccount,
@@ -4141,6 +5216,7 @@ export {
4141
5216
  useManagedBalances,
4142
5217
  useMarketArb,
4143
5218
  useMarketChart,
5219
+ useMarketCharts,
4144
5220
  useMarketOrderbook,
4145
5221
  useMarketSearch,
4146
5222
  useMidpoints,
@@ -4156,7 +5232,7 @@ export {
4156
5232
  usePaperOnboarding,
4157
5233
  usePlaceLimitOrder,
4158
5234
  usePositions,
4159
- useQueryClient2 as useQueryClient,
5235
+ useQueryClient5 as useQueryClient,
4160
5236
  useRampQuotes,
4161
5237
  useRampSession,
4162
5238
  useRecurringCryptoMarkets,
@@ -4169,6 +5245,7 @@ export {
4169
5245
  useSdkLabels,
4170
5246
  useSdkUiConfig,
4171
5247
  useSearch,
5248
+ useSettlementDetailsData,
4172
5249
  useSharedKyc,
4173
5250
  useSmartRoute,
4174
5251
  useSportsLive,