@agg-build/hooks 1.0.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 ADDED
@@ -0,0 +1,2010 @@
1
+ import {
2
+ AggAuthContext,
3
+ AggBalanceProvider,
4
+ AggClientContext,
5
+ AggProvider,
6
+ AggUiProvider,
7
+ CHART_TIME_RANGES,
8
+ CONFIRMED_MATCH_STATUSES,
9
+ DEFAULT_AGG_ROOT_CLASS_NAME,
10
+ EventListStateProvider,
11
+ MarketStatus,
12
+ MatchStatus,
13
+ MatchType,
14
+ Venue,
15
+ __async,
16
+ __objRest,
17
+ __spreadProps,
18
+ __spreadValues,
19
+ applyOrderbookDepth,
20
+ computeClosedPositionTotals,
21
+ createMarketChartData,
22
+ createMarketLiveState,
23
+ createMarketOrderbookDataFromState,
24
+ createMarketOrderbookDataFromVenueOrderbooks,
25
+ defaultAggUiConfig,
26
+ executionKeys,
27
+ getBuilder,
28
+ getDepositAddress,
29
+ getOrCreateBuilder,
30
+ getWalletAddressFromUserProfile,
31
+ invalidateBalanceQueries,
32
+ invalidatePositionQueries,
33
+ marketDataKeys,
34
+ marketOrderbookDataToResponse,
35
+ mergeMarketChartData,
36
+ optimizedImageUrl,
37
+ parseEmail,
38
+ parseEmailStrict,
39
+ resolveAggUiLabels,
40
+ resolveDefaultMarket,
41
+ resolveEventTradingState,
42
+ resolveMarketTradingState,
43
+ resolveMarketWinningOutcome,
44
+ resolveOrderEligibility,
45
+ resolveTradingStateKind,
46
+ sortVenues,
47
+ tradingReducer,
48
+ useAggAuthContext,
49
+ useAggAuthState,
50
+ useAggBalance,
51
+ useAggBalanceContext,
52
+ useAggBalanceState,
53
+ useAggClient,
54
+ useAggLabels,
55
+ useAggUiConfig,
56
+ useAggWebSocket,
57
+ useAggWebSocketConnectionState,
58
+ useDepositAddresses,
59
+ useEventListState,
60
+ useEventTradingContext,
61
+ useExecuteManaged,
62
+ useExecutionProgress,
63
+ useLabels,
64
+ useManagedBalances,
65
+ useOnBalanceUpdate,
66
+ useOnOrderSubmitted,
67
+ useOnRedeemEvent,
68
+ usePositions,
69
+ useQuoteManaged,
70
+ useRampQuotes,
71
+ useRampSession,
72
+ useRedeem,
73
+ useRedeemEligibleCount,
74
+ useSdkLabels,
75
+ useSdkUiConfig,
76
+ useSyncBalances,
77
+ useWithdrawManaged
78
+ } from "./chunk-CDPQERUC.mjs";
79
+
80
+ // src/index.ts
81
+ import { QueryClient as QueryClient4, QueryClientProvider, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
82
+ import { TurnstileChallengeError } from "@agg-build/sdk";
83
+
84
+ // src/use-geo-block.ts
85
+ import { useContext } from "react";
86
+ var DEFAULT_STATE = {
87
+ isLocationBlocked: false,
88
+ isTradingBlocked: false,
89
+ isDepositBlocked: false
90
+ };
91
+ function useGeoBlock() {
92
+ var _a, _b;
93
+ const authContext = useContext(AggAuthContext);
94
+ if (process.env.NEXT_PUBLIC_GEO_BLOCK_DISABLE === "true") return DEFAULT_STATE;
95
+ const isBlocked = (_b = (_a = authContext == null ? void 0 : authContext.user) == null ? void 0 : _a.isLocationBlocked) != null ? _b : false;
96
+ if (!isBlocked) return DEFAULT_STATE;
97
+ return {
98
+ isLocationBlocked: true,
99
+ isTradingBlocked: true,
100
+ isDepositBlocked: true
101
+ };
102
+ }
103
+
104
+ // src/use-agg-auth.ts
105
+ import { useCallback } from "react";
106
+ function useAggAuth(options = {}) {
107
+ const {
108
+ isAuthenticated,
109
+ user,
110
+ isLoading,
111
+ error,
112
+ signIn: signInWithProvider,
113
+ signOut
114
+ } = useAggAuthContext();
115
+ const signIn = useCallback(
116
+ (statement) => __async(null, null, function* () {
117
+ if (!options.signMessage) {
118
+ throw new Error(
119
+ "signMessage is required to call signIn. Pass wallet options to useAggAuth()."
120
+ );
121
+ }
122
+ if (!options.address) {
123
+ throw new Error("address is required to call signIn. Pass wallet options to useAggAuth().");
124
+ }
125
+ yield signInWithProvider({
126
+ signMessage: options.signMessage,
127
+ address: options.address,
128
+ chainId: options.chainId,
129
+ chain: options.chain,
130
+ statement
131
+ });
132
+ }),
133
+ [options.address, options.chain, options.chainId, options.signMessage, signInWithProvider]
134
+ );
135
+ return { isAuthenticated, user, signIn, signOut, isLoading, error };
136
+ }
137
+
138
+ // src/use-link-account.ts
139
+ import { useCallback as useCallback2, useState } from "react";
140
+ function useLinkAccount() {
141
+ const client = useAggClient();
142
+ const [isLoading, setIsLoading] = useState(false);
143
+ const [error, setError] = useState(null);
144
+ const run = (fn) => {
145
+ setIsLoading(true);
146
+ setError(null);
147
+ return fn().catch((e) => {
148
+ const err = e instanceof Error ? e : new Error(String(e));
149
+ setError(err);
150
+ throw err;
151
+ }).finally(() => setIsLoading(false));
152
+ };
153
+ const startLink = useCallback2(
154
+ (body) => run(() => client.linkAccount(body)),
155
+ [client]
156
+ );
157
+ const confirmLink = useCallback2(
158
+ (token) => run(() => client.linkAccountConfirm(token)),
159
+ [client]
160
+ );
161
+ return { startLink, confirmLink, isLoading, error };
162
+ }
163
+
164
+ // src/auth-chooser-events.ts
165
+ var AUTH_CHOOSER_OPEN_EVENT = "agg-auth:open-chooser";
166
+ var requestAggAuthChooserOpen = () => {
167
+ if (typeof window === "undefined") return;
168
+ window.dispatchEvent(new Event(AUTH_CHOOSER_OPEN_EVENT));
169
+ };
170
+
171
+ // src/use-categories.ts
172
+ import { useInfiniteQuery } from "@tanstack/react-query";
173
+ function useCategories(options) {
174
+ var _a, _b, _c, _d;
175
+ const client = useAggClient();
176
+ const enabled = (_a = options == null ? void 0 : options.enabled) != null ? _a : true;
177
+ const limit = (_b = options == null ? void 0 : options.limit) != null ? _b : 20;
178
+ const query = useInfiniteQuery({
179
+ queryKey: ["categories", limit],
180
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
181
+ const res = yield client.getCategories({
182
+ limit,
183
+ cursor: pageParam
184
+ });
185
+ return res;
186
+ }),
187
+ initialPageParam: void 0,
188
+ getNextPageParam: (lastPage) => {
189
+ var _a2;
190
+ return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
191
+ },
192
+ enabled
193
+ });
194
+ const categories = (_d = (_c = query.data) == null ? void 0 : _c.pages.flatMap((p) => p.data)) != null ? _d : [];
195
+ const hasNextPage = !!query.hasNextPage;
196
+ return __spreadProps(__spreadValues({}, query), {
197
+ categories,
198
+ hasNextPage
199
+ });
200
+ }
201
+
202
+ // src/use-debounced-value.ts
203
+ import { useEffect, useState as useState2 } from "react";
204
+ function useDebouncedValue(value, delay) {
205
+ const [debouncedValue, setDebouncedValue] = useState2(value);
206
+ useEffect(() => {
207
+ const timeoutId = window.setTimeout(() => {
208
+ setDebouncedValue(value);
209
+ }, delay);
210
+ return () => {
211
+ window.clearTimeout(timeoutId);
212
+ };
213
+ }, [value, delay]);
214
+ return debouncedValue;
215
+ }
216
+
217
+ // src/use-execution-orders.ts
218
+ import { useInfiniteQuery as useInfiniteQuery2 } from "@tanstack/react-query";
219
+ function useExecutionOrders(options = {}) {
220
+ var _a, _b;
221
+ const client = useAggClient();
222
+ const { status, limit = 50, enabled = true, refetchIntervalMs = false } = options;
223
+ const query = useInfiniteQuery2({
224
+ queryKey: ["execution-orders", status != null ? status : "all", limit],
225
+ queryFn: ({ pageParam }) => client.getExecutionOrders({
226
+ status,
227
+ limit,
228
+ cursor: pageParam
229
+ }),
230
+ initialPageParam: void 0,
231
+ getNextPageParam: (lastPage) => {
232
+ var _a2;
233
+ return lastPage.hasMore ? (_a2 = lastPage.nextCursor) != null ? _a2 : void 0 : void 0;
234
+ },
235
+ enabled,
236
+ refetchInterval: refetchIntervalMs
237
+ });
238
+ const orders = (_b = (_a = query.data) == null ? void 0 : _a.pages.flatMap((page) => page.data)) != null ? _b : [];
239
+ const hasNextPage = !!query.hasNextPage;
240
+ return __spreadProps(__spreadValues({}, query), {
241
+ orders,
242
+ hasNextPage
243
+ });
244
+ }
245
+
246
+ // src/use-user-activity.ts
247
+ import { useInfiniteQuery as useInfiniteQuery3 } from "@tanstack/react-query";
248
+ function useUserActivity(options = {}) {
249
+ var _a, _b;
250
+ const client = useAggClient();
251
+ const { type, limit = 50, enabled = true } = options;
252
+ const query = useInfiniteQuery3({
253
+ queryKey: ["user-activity", type != null ? type : "all", limit],
254
+ queryFn: ({ pageParam }) => client.getUserActivity({
255
+ type,
256
+ limit,
257
+ cursor: pageParam
258
+ }),
259
+ initialPageParam: void 0,
260
+ getNextPageParam: (lastPage) => {
261
+ var _a2;
262
+ return lastPage.hasMore ? (_a2 = lastPage.nextCursor) != null ? _a2 : void 0 : void 0;
263
+ },
264
+ enabled
265
+ });
266
+ const activities = (_b = (_a = query.data) == null ? void 0 : _a.pages.flatMap((page) => page.data)) != null ? _b : [];
267
+ const hasNextPage = !!query.hasNextPage;
268
+ return __spreadProps(__spreadValues({}, query), {
269
+ activities,
270
+ hasNextPage
271
+ });
272
+ }
273
+
274
+ // src/use-external-id.ts
275
+ import { useCallback as useCallback3, useState as useState3 } from "react";
276
+ function useExternalId(options = {}) {
277
+ const client = useAggClient();
278
+ const { onSuccess, onError: onErrorCb } = options;
279
+ const [isLoading, setIsLoading] = useState3(false);
280
+ const [error, setError] = useState3(null);
281
+ const linkExternalId = useCallback3(
282
+ (assertion) => __async(null, null, function* () {
283
+ setIsLoading(true);
284
+ setError(null);
285
+ try {
286
+ const profile = yield client.linkExternalId(assertion);
287
+ onSuccess == null ? void 0 : onSuccess(profile);
288
+ return profile;
289
+ } catch (err) {
290
+ const resolvedError = err instanceof Error ? err : new Error(String(err));
291
+ setError(resolvedError);
292
+ onErrorCb == null ? void 0 : onErrorCb(resolvedError);
293
+ throw resolvedError;
294
+ } finally {
295
+ setIsLoading(false);
296
+ }
297
+ }),
298
+ [client, onErrorCb, onSuccess]
299
+ );
300
+ return { linkExternalId, isLoading, error };
301
+ }
302
+
303
+ // src/use-execution-positions.ts
304
+ import { useInfiniteQuery as useInfiniteQuery4 } from "@tanstack/react-query";
305
+ function useExecutionPositions(options = {}) {
306
+ var _a, _b;
307
+ const client = useAggClient();
308
+ const { limit = 50, status, enabled = true } = options;
309
+ const query = useInfiniteQuery4({
310
+ queryKey: executionKeys.positions(null, limit, status != null ? status : null),
311
+ queryFn: ({ pageParam }) => client.getExecutionPositions({
312
+ limit,
313
+ status,
314
+ cursor: pageParam
315
+ }),
316
+ initialPageParam: void 0,
317
+ getNextPageParam: (lastPage) => {
318
+ var _a2;
319
+ return lastPage.hasMore ? (_a2 = lastPage.nextCursor) != null ? _a2 : void 0 : void 0;
320
+ },
321
+ enabled
322
+ });
323
+ const positions = (_b = (_a = query.data) == null ? void 0 : _a.pages.flatMap((page) => page.data)) != null ? _b : [];
324
+ const hasNextPage = !!query.hasNextPage;
325
+ return __spreadProps(__spreadValues({}, query), {
326
+ positions,
327
+ hasNextPage
328
+ });
329
+ }
330
+
331
+ // src/use-live-candle-overlay.ts
332
+ import { useCallback as useCallback4, useMemo as useMemo4 } from "react";
333
+
334
+ // src/use-live-candles.ts
335
+ import { useMemo as useMemo3 } from "react";
336
+ import { mergeCandles, mergeClosedCandles } from "@agg-build/sdk";
337
+
338
+ // src/use-market-chart.ts
339
+ import { keepPreviousData, useQueries } from "@tanstack/react-query";
340
+
341
+ // src/market-data/subscription.ts
342
+ import { useEffect as useEffect2, useMemo } from "react";
343
+ function useMarketDataSubscription({
344
+ marketId,
345
+ additionalMarketIds,
346
+ enabled = true,
347
+ orderbook = true,
348
+ trades = false
349
+ }) {
350
+ const ws = useAggWebSocket();
351
+ const allIds = useMemo(() => {
352
+ const ids = /* @__PURE__ */ new Set();
353
+ if (marketId) ids.add(marketId);
354
+ if (additionalMarketIds) {
355
+ for (const id of additionalMarketIds) {
356
+ if (id) ids.add(id);
357
+ }
358
+ }
359
+ return [...ids];
360
+ }, [marketId, additionalMarketIds]);
361
+ const stableKey = allIds.join("|");
362
+ useEffect2(() => {
363
+ if (!ws || !allIds.length || !enabled || !orderbook && !trades) return;
364
+ const unsubscribers = [];
365
+ for (const id of allIds) {
366
+ if (orderbook) {
367
+ const unsub = ws.subscribe(id, "orderbook");
368
+ unsubscribers.push(unsub);
369
+ }
370
+ if (trades) {
371
+ const unsub = ws.subscribe(id, "trades");
372
+ unsubscribers.push(unsub);
373
+ }
374
+ }
375
+ return () => {
376
+ for (const unsub of unsubscribers) {
377
+ unsub();
378
+ }
379
+ };
380
+ }, [enabled, stableKey, orderbook, trades, ws]);
381
+ }
382
+
383
+ // src/use-market-chart.ts
384
+ function useMarketChart(options) {
385
+ var _a, _b, _c;
386
+ const client = useAggClient();
387
+ const isConnected = useAggWebSocketConnectionState();
388
+ const {
389
+ features: { enableLiveUpdates }
390
+ } = useAggUiConfig();
391
+ const {
392
+ marketId,
393
+ venueMarketIds,
394
+ interval = "5m",
395
+ startTs = null,
396
+ endTs = null,
397
+ countBack = null,
398
+ enabled = true,
399
+ live
400
+ } = options;
401
+ const liveEnabled = live != null ? live : enableLiveUpdates;
402
+ const outcomeIds = (() => {
403
+ const ids = /* @__PURE__ */ new Set();
404
+ if (marketId) {
405
+ ids.add(marketId);
406
+ }
407
+ if (venueMarketIds) {
408
+ for (const venueMarketId of venueMarketIds) {
409
+ if (venueMarketId) {
410
+ ids.add(venueMarketId);
411
+ }
412
+ }
413
+ }
414
+ return [...ids];
415
+ })();
416
+ const primaryOutcomeId = (_a = outcomeIds[0]) != null ? _a : null;
417
+ const isQueryEnabled = enabled && outcomeIds.length > 0 && endTs != null && (startTs != null || countBack != null);
418
+ useMarketDataSubscription({
419
+ marketId: primaryOutcomeId,
420
+ additionalMarketIds: outcomeIds.slice(1),
421
+ enabled: Boolean(isQueryEnabled && liveEnabled),
422
+ orderbook: true,
423
+ trades: true
424
+ });
425
+ const queries = useQueries({
426
+ queries: outcomeIds.map((outcomeId) => ({
427
+ queryKey: marketDataKeys.chart(outcomeId, interval, startTs, endTs, countBack),
428
+ queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
429
+ const response = yield client.getChartBars(
430
+ {
431
+ venueMarketOutcomeId: outcomeId,
432
+ resolution: interval,
433
+ from: startTs != null ? startTs : void 0,
434
+ to: endTs,
435
+ countBack: countBack != null ? countBack : void 0
436
+ },
437
+ { signal }
438
+ );
439
+ return createMarketChartData({
440
+ marketId: outcomeId,
441
+ interval,
442
+ startTs,
443
+ endTs,
444
+ response
445
+ });
446
+ }),
447
+ enabled: isQueryEnabled,
448
+ staleTime: 3e4,
449
+ gcTime: 5 * 6e4,
450
+ refetchOnWindowFocus: false,
451
+ retry: 1,
452
+ placeholderData: keepPreviousData
453
+ }))
454
+ });
455
+ const successfulDatasets = queries.flatMap((query) => {
456
+ return query.data ? [query.data] : [];
457
+ });
458
+ const data = primaryOutcomeId && successfulDatasets.length > 0 ? mergeMarketChartData({
459
+ marketId: primaryOutcomeId,
460
+ interval,
461
+ startTs,
462
+ endTs,
463
+ datasets: successfulDatasets
464
+ }) : null;
465
+ const hasPendingQuery = queries.some((query) => query.isLoading);
466
+ const firstError = (_c = (_b = queries.find((query) => query.error != null)) == null ? void 0 : _b.error) != null ? _c : null;
467
+ const error = data == null && !hasPendingQuery ? firstError instanceof Error ? firstError : firstError ? new Error(String(firstError)) : null : null;
468
+ const isLoading = Boolean(isQueryEnabled && data == null && hasPendingQuery);
469
+ return {
470
+ data,
471
+ isLoading,
472
+ error,
473
+ isLive: Boolean(liveEnabled && primaryOutcomeId && isConnected),
474
+ refetch: () => __async(null, null, function* () {
475
+ return Promise.all(queries.map((query) => query.refetch()));
476
+ })
477
+ };
478
+ }
479
+
480
+ // src/use-live-market-stores.ts
481
+ import { useEffect as useEffect3, useMemo as useMemo2, useReducer, useRef } from "react";
482
+ function useLiveMarketStores(venueMarketIds) {
483
+ const ws = useAggWebSocket();
484
+ const [, forceRender] = useReducer((c) => c + 1, 0);
485
+ const subsRef = useRef(/* @__PURE__ */ new Map());
486
+ const stableKey = useMemo2(() => venueMarketIds.slice().sort().join("|"), [venueMarketIds]);
487
+ useEffect3(() => {
488
+ if (!ws || venueMarketIds.length === 0) return;
489
+ const current = subsRef.current;
490
+ const desired = new Set(venueMarketIds);
491
+ for (const [id, sub] of current) {
492
+ if (!desired.has(id)) {
493
+ sub.unsub();
494
+ sub.unlisten();
495
+ current.delete(id);
496
+ }
497
+ }
498
+ for (const id of desired) {
499
+ if (!current.has(id)) {
500
+ const builder = getOrCreateBuilder(id);
501
+ const unsub = ws.subscribe(id, "orderbook");
502
+ const unlisten = builder.onChange(forceRender);
503
+ current.set(id, { unsub, unlisten });
504
+ }
505
+ }
506
+ return () => {
507
+ for (const [, sub] of current) {
508
+ sub.unsub();
509
+ sub.unlisten();
510
+ }
511
+ current.clear();
512
+ };
513
+ }, [ws, stableKey]);
514
+ return venueMarketIds.map((id) => getOrCreateBuilder(id));
515
+ }
516
+
517
+ // src/use-live-candles.ts
518
+ function candleToLive(c, source) {
519
+ return { time: c.openTime, o: c.o, h: c.h, l: c.l, c: c.c, v: c.v, source };
520
+ }
521
+ function useLiveCandles(options) {
522
+ var _a;
523
+ const { market, interval = "5m", mode = "venue", startTs, endTs } = options;
524
+ const venueMarketIds = useMemo3(() => {
525
+ if (!market) return [];
526
+ if (mode === "venue") return [market.id];
527
+ const ids = [market.id];
528
+ if (market.matchedVenueMarkets) {
529
+ for (const m of market.matchedVenueMarkets) {
530
+ ids.push(m.id);
531
+ }
532
+ }
533
+ return ids;
534
+ }, [market, mode]);
535
+ const builders = useLiveMarketStores(venueMarketIds);
536
+ const restMarketId = (_a = market == null ? void 0 : market.marketId) != null ? _a : null;
537
+ const { data: chartData, isLoading } = useMarketChart({
538
+ marketId: restMarketId,
539
+ interval,
540
+ startTs: startTs != null ? startTs : null,
541
+ endTs: endTs != null ? endTs : null,
542
+ enabled: !!restMarketId && startTs != null && endTs != null
543
+ });
544
+ const liveData = useMemo3(() => {
545
+ if (builders.length === 0) return { closed: [], forming: null };
546
+ if (mode === "venue" || builders.length === 1) {
547
+ return {
548
+ closed: builders[0].getClosed(interval),
549
+ forming: builders[0].getForming(interval)
550
+ };
551
+ }
552
+ return {
553
+ closed: mergeClosedCandles(builders.map((b) => b.getClosed(interval))),
554
+ forming: mergeCandles(builders.map((b) => b.getForming(interval)))
555
+ };
556
+ }, [builders, interval, mode]);
557
+ const candles = useMemo3(() => {
558
+ const byTime = /* @__PURE__ */ new Map();
559
+ if (chartData) {
560
+ const venueEntries = Object.values(chartData.venues);
561
+ for (const venueData of venueEntries) {
562
+ for (const c of venueData.candles) {
563
+ byTime.set(c.time, {
564
+ time: c.time,
565
+ o: c.open,
566
+ h: c.high,
567
+ l: c.low,
568
+ c: c.close,
569
+ v: c.volume,
570
+ source: "rest"
571
+ });
572
+ }
573
+ }
574
+ }
575
+ for (const c of liveData.closed) {
576
+ byTime.set(c.openTime, candleToLive(c, "live"));
577
+ }
578
+ const merged = Array.from(byTime.values());
579
+ merged.sort((a, b) => a.time - b.time);
580
+ return merged;
581
+ }, [chartData, liveData.closed]);
582
+ const liveCandle = useMemo3(() => {
583
+ if (!liveData.forming) return null;
584
+ return candleToLive(liveData.forming, "live");
585
+ }, [liveData.forming]);
586
+ return { candles, liveCandle, isLoading };
587
+ }
588
+
589
+ // src/use-live-candle-overlay.ts
590
+ function timeRangeToInterval(range) {
591
+ switch (range) {
592
+ case "1H":
593
+ return "1m";
594
+ case "6H":
595
+ return "5m";
596
+ case "1D":
597
+ return "5m";
598
+ case "1W":
599
+ return "1h";
600
+ case "1M":
601
+ return "1h";
602
+ case "ALL":
603
+ return "1h";
604
+ default:
605
+ return "5m";
606
+ }
607
+ }
608
+ function useLiveCandleOverlay(options) {
609
+ var _a, _b;
610
+ const {
611
+ market,
612
+ interval = "5m",
613
+ mode = "venue",
614
+ startTs,
615
+ endTs,
616
+ enabled = true,
617
+ scale = 100
618
+ } = options;
619
+ const {
620
+ candles: rawCandles,
621
+ liveCandle: rawLive,
622
+ isLoading
623
+ } = useLiveCandles({
624
+ market: enabled ? market : null,
625
+ interval,
626
+ mode,
627
+ startTs,
628
+ endTs
629
+ });
630
+ const scaleCandle = useCallback4(
631
+ (candle) => ({
632
+ time: candle.time,
633
+ open: candle.o * scale,
634
+ high: candle.h * scale,
635
+ low: candle.l * scale,
636
+ close: candle.c * scale,
637
+ v: candle.v
638
+ }),
639
+ [scale]
640
+ );
641
+ const scaledCandles = useMemo4(() => rawCandles.map(scaleCandle), [rawCandles, scaleCandle]);
642
+ const liveCandle = useMemo4(() => rawLive ? scaleCandle(rawLive) : null, [rawLive, scaleCandle]);
643
+ return {
644
+ liveCandle,
645
+ scaledCandles,
646
+ lineValue: (_b = liveCandle == null ? void 0 : liveCandle.close) != null ? _b : (_a = scaledCandles[scaledCandles.length - 1]) == null ? void 0 : _a.close,
647
+ live: liveCandle != null,
648
+ isLoading
649
+ };
650
+ }
651
+
652
+ // src/use-event-orderbook-data.ts
653
+ import { useEffect as useEffect4, useMemo as useMemo5 } from "react";
654
+ function extractSelectedOutcomeIds(selectedMarket) {
655
+ var _a, _b, _c;
656
+ if (!selectedMarket) return [];
657
+ const ids = /* @__PURE__ */ new Set();
658
+ for (const outcome of (_a = selectedMarket.venueMarketOutcomes) != null ? _a : []) {
659
+ if (outcome.id) ids.add(outcome.id);
660
+ }
661
+ for (const matched of (_b = selectedMarket.matchedVenueMarkets) != null ? _b : []) {
662
+ for (const outcome of (_c = matched.venueMarketOutcomes) != null ? _c : []) {
663
+ if (outcome.id) ids.add(outcome.id);
664
+ }
665
+ }
666
+ return [...ids].sort();
667
+ }
668
+ function useEventOrderbookData(venueMarkets, selectedMarketId) {
669
+ const ws = useAggWebSocket();
670
+ const {
671
+ features: { enableLiveUpdates }
672
+ } = useAggUiConfig();
673
+ const selectedMarket = useMemo5(() => {
674
+ var _a;
675
+ if (!selectedMarketId || !(venueMarkets == null ? void 0 : venueMarkets.length)) return null;
676
+ return (_a = venueMarkets.find((m) => m.id === selectedMarketId)) != null ? _a : null;
677
+ }, [venueMarkets, selectedMarketId]);
678
+ const selectedOutcomeIds = useMemo5(
679
+ () => extractSelectedOutcomeIds(selectedMarket),
680
+ [selectedMarket]
681
+ );
682
+ const selectedKey = selectedOutcomeIds.join("|");
683
+ useEffect4(() => {
684
+ if (!ws || !enableLiveUpdates || !selectedOutcomeIds.length) return;
685
+ const unsubscribers = selectedOutcomeIds.map((id) => ws.subscribe(id, "orderbook"));
686
+ return () => {
687
+ for (const unsub of unsubscribers) unsub();
688
+ };
689
+ }, [ws, selectedKey, enableLiveUpdates]);
690
+ }
691
+
692
+ // src/use-live-market.ts
693
+ import { useQuery } from "@tanstack/react-query";
694
+ function outcomeOrderbookToState(response, marketId) {
695
+ var _a, _b, _c, _d;
696
+ const { venue, orderbook, midpoint, spread, seq, checksum, timestamp, venueMarketOutcomeId } = response;
697
+ const attribute = (l) => ({
698
+ price: l.price,
699
+ size: l.size,
700
+ venues: { [venue]: l.size }
701
+ });
702
+ const venueLevels = (l) => ({
703
+ price: l.price,
704
+ size: l.size
705
+ });
706
+ return {
707
+ marketId,
708
+ outcomeId: venueMarketOutcomeId,
709
+ bids: orderbook.bids.map(attribute),
710
+ asks: orderbook.asks.map(attribute),
711
+ venueOrderbooks: {
712
+ [venue]: {
713
+ bids: orderbook.bids.map(venueLevels),
714
+ asks: orderbook.asks.map(venueLevels)
715
+ }
716
+ },
717
+ venues: {
718
+ [venue]: {
719
+ bestBid: (_b = (_a = orderbook.bids[0]) == null ? void 0 : _a.price) != null ? _b : null,
720
+ bestAsk: (_d = (_c = orderbook.asks[0]) == null ? void 0 : _c.price) != null ? _d : null
721
+ }
722
+ },
723
+ midpoint,
724
+ spread,
725
+ seq,
726
+ checksum,
727
+ timestamp
728
+ };
729
+ }
730
+ function useLiveMarket(canonicalMarketId) {
731
+ var _a, _b;
732
+ const client = useAggClient();
733
+ const isConnected = useAggWebSocketConnectionState();
734
+ const {
735
+ features: { enableLiveUpdates }
736
+ } = useAggUiConfig();
737
+ const isLiveSubscriptionEnabled = Boolean(canonicalMarketId && enableLiveUpdates);
738
+ useMarketDataSubscription({
739
+ marketId: canonicalMarketId,
740
+ enabled: isLiveSubscriptionEnabled,
741
+ orderbook: true
742
+ });
743
+ const query = useQuery({
744
+ queryKey: marketDataKeys.live(canonicalMarketId != null ? canonicalMarketId : "__disabled__"),
745
+ queryFn: () => __async(null, null, function* () {
746
+ return createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__");
747
+ }),
748
+ enabled: false,
749
+ staleTime: Infinity,
750
+ gcTime: 5 * 6e4,
751
+ initialData: () => createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__", {
752
+ isConnected: Boolean(isLiveSubscriptionEnabled && isConnected)
753
+ })
754
+ });
755
+ const seedQuery = useQuery({
756
+ queryKey: ["live-market-seed", canonicalMarketId],
757
+ queryFn: ({ signal }) => canonicalMarketId ? client.getOutcomeOrderbook(canonicalMarketId, { signal }) : Promise.resolve(null),
758
+ enabled: Boolean(canonicalMarketId),
759
+ staleTime: 5e3,
760
+ gcTime: 6e4,
761
+ refetchOnWindowFocus: false,
762
+ retry: 1
763
+ });
764
+ const data = (_a = query.data) != null ? _a : createMarketLiveState(canonicalMarketId != null ? canonicalMarketId : "__disabled__");
765
+ const orderbook = (_b = data.orderbook) != null ? _b : canonicalMarketId && seedQuery.data ? outcomeOrderbookToState(seedQuery.data, canonicalMarketId) : null;
766
+ return {
767
+ orderbook,
768
+ trades: data.trades,
769
+ isConnected: isLiveSubscriptionEnabled ? data.isConnected : false,
770
+ integrity: data.integrity
771
+ };
772
+ }
773
+
774
+ // src/use-live-outcome-prices.ts
775
+ import { useMemo as useMemo6, useRef as useRef2 } from "react";
776
+ import { useQueries as useQueries2 } from "@tanstack/react-query";
777
+ var EMPTY_PRICES = /* @__PURE__ */ new Map();
778
+ var buildMidpointFingerprint = (outcomeIds, queries) => {
779
+ var _a, _b, _c;
780
+ const parts = [];
781
+ for (let i = 0; i < outcomeIds.length; i++) {
782
+ const midpoint = (_c = (_b = (_a = queries[i]) == null ? void 0 : _a.data) == null ? void 0 : _b.orderbook) == null ? void 0 : _c.midpoint;
783
+ parts.push(`${outcomeIds[i]}:${midpoint != null ? midpoint : "_"}`);
784
+ }
785
+ return parts.join("|");
786
+ };
787
+ function useLiveOutcomePrices(venueMarkets) {
788
+ const {
789
+ features: { enableLiveUpdates }
790
+ } = useAggUiConfig();
791
+ const outcomeIds = useMemo6(() => {
792
+ var _a;
793
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return [];
794
+ const ids = /* @__PURE__ */ new Set();
795
+ for (const vm of venueMarkets) {
796
+ for (const outcome of (_a = vm.venueMarketOutcomes) != null ? _a : []) {
797
+ if (outcome.id) ids.add(outcome.id);
798
+ }
799
+ }
800
+ return [...ids].sort();
801
+ }, [venueMarkets]);
802
+ const queries = useQueries2({
803
+ queries: outcomeIds.map((id) => ({
804
+ queryKey: marketDataKeys.live(id),
805
+ queryFn: () => createMarketLiveState(id),
806
+ enabled: false,
807
+ staleTime: Infinity,
808
+ gcTime: 5 * 6e4,
809
+ initialData: () => createMarketLiveState(id)
810
+ }))
811
+ });
812
+ const fingerprint = buildMidpointFingerprint(outcomeIds, queries);
813
+ const prevRef = useRef2({
814
+ fingerprint: "",
815
+ prices: EMPTY_PRICES
816
+ });
817
+ const data = useMemo6(() => {
818
+ var _a, _b, _c, _d;
819
+ if (!(venueMarkets == null ? void 0 : venueMarkets.length)) return EMPTY_PRICES;
820
+ if (fingerprint === prevRef.current.fingerprint) {
821
+ return prevRef.current.prices;
822
+ }
823
+ const prices = /* @__PURE__ */ new Map();
824
+ const liveByOutcomeId = /* @__PURE__ */ new Map();
825
+ for (let i = 0; i < outcomeIds.length; i++) {
826
+ const state = (_a = queries[i]) == null ? void 0 : _a.data;
827
+ liveByOutcomeId.set(outcomeIds[i], (_c = (_b = state == null ? void 0 : state.orderbook) == null ? void 0 : _b.midpoint) != null ? _c : null);
828
+ }
829
+ for (const vm of venueMarkets) {
830
+ for (const outcome of (_d = vm.venueMarketOutcomes) != null ? _d : []) {
831
+ if (!enableLiveUpdates) {
832
+ prices.set(outcome.id, outcome.price);
833
+ continue;
834
+ }
835
+ const liveMidpoint = liveByOutcomeId.get(outcome.id);
836
+ prices.set(outcome.id, liveMidpoint != null ? liveMidpoint : outcome.price);
837
+ }
838
+ }
839
+ prevRef.current = { fingerprint, prices };
840
+ return prices;
841
+ }, [venueMarkets, enableLiveUpdates, fingerprint, outcomeIds, queries]);
842
+ return data;
843
+ }
844
+ function findLivePriceById(livePrices, id) {
845
+ return livePrices.get(id);
846
+ }
847
+
848
+ // src/use-live-trades.ts
849
+ function useLiveTrades(canonicalMarketId) {
850
+ const {
851
+ features: { enableLiveUpdates }
852
+ } = useAggUiConfig();
853
+ const { trades } = useLiveMarket(canonicalMarketId);
854
+ useMarketDataSubscription({
855
+ marketId: canonicalMarketId,
856
+ enabled: Boolean(canonicalMarketId && enableLiveUpdates),
857
+ orderbook: false,
858
+ trades: true
859
+ });
860
+ return trades;
861
+ }
862
+
863
+ // src/use-midpoints.ts
864
+ import { useMemo as useMemo7 } from "react";
865
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
866
+ var normalizeVenueMarketIds = (venueMarkets) => {
867
+ return [...new Set((venueMarkets != null ? venueMarkets : []).map((market) => market.id).filter(Boolean))].sort(
868
+ (left, right) => left.localeCompare(right)
869
+ );
870
+ };
871
+ function useMidpoints(venueMarkets) {
872
+ const client = useAggClient();
873
+ const ids = useMemo7(() => normalizeVenueMarketIds(venueMarkets), [venueMarkets]);
874
+ const { data, isLoading } = useQuery2({
875
+ queryKey: ["midpoints", ids],
876
+ queryFn: () => client.getMidpoints(ids),
877
+ enabled: ids.length > 0,
878
+ staleTime: Infinity,
879
+ gcTime: 30 * 6e4,
880
+ refetchOnMount: false,
881
+ refetchOnWindowFocus: false,
882
+ refetchOnReconnect: false
883
+ });
884
+ const prices = useMemo7(() => {
885
+ var _a, _b, _c, _d;
886
+ const map = /* @__PURE__ */ new Map();
887
+ if (!(data == null ? void 0 : data.data) || !venueMarkets) return map;
888
+ for (const item of data.data) {
889
+ if ((_a = item.outcomes) == null ? void 0 : _a.length) {
890
+ for (const o of item.outcomes) {
891
+ if (o.midpoint != null) {
892
+ map.set(o.venueMarketOutcomeId, o.midpoint);
893
+ }
894
+ }
895
+ if ((_b = item.matched) == null ? void 0 : _b.length) {
896
+ for (const m of item.matched) {
897
+ if (m.midpoint != null) {
898
+ const market = venueMarkets.find((vm) => vm.id === item.venueMarketId);
899
+ if (!market) continue;
900
+ for (const outcome of market.venueMarketOutcomes) {
901
+ const existing = map.get(outcome.id);
902
+ const isYes = ((_c = outcome.label) == null ? void 0 : _c.toLowerCase()) === "yes";
903
+ const matchedPrice = isYes ? m.midpoint : 1 - m.midpoint;
904
+ if (existing == null || isYes && matchedPrice > existing || !isYes && matchedPrice < existing) {
905
+ map.set(outcome.id, matchedPrice);
906
+ }
907
+ }
908
+ }
909
+ }
910
+ }
911
+ continue;
912
+ }
913
+ if (item.midpoint != null) {
914
+ const market = venueMarkets.find((vm) => vm.id === item.venueMarketId);
915
+ if (!market) continue;
916
+ for (const outcome of market.venueMarketOutcomes) {
917
+ const isYes = ((_d = outcome.label) == null ? void 0 : _d.toLowerCase()) === "yes";
918
+ map.set(outcome.id, isYes ? item.midpoint : 1 - item.midpoint);
919
+ }
920
+ }
921
+ }
922
+ return map;
923
+ }, [data, venueMarkets]);
924
+ return { prices, isLoading: isLoading && ids.length > 0 };
925
+ }
926
+
927
+ // src/use-market-orderbook.ts
928
+ import { useQueries as useQueries3, useQueryClient } from "@tanstack/react-query";
929
+ function useMarketOrderbook(options) {
930
+ var _a, _b, _c, _d, _e, _f, _g;
931
+ const queryClient = useQueryClient();
932
+ const ws = useAggWebSocket();
933
+ const isConnected = useAggWebSocketConnectionState();
934
+ const {
935
+ features: { enableLiveUpdates }
936
+ } = useAggUiConfig();
937
+ const { marketId, depth, enabled = true, venueOutcomes, live } = options;
938
+ const liveEnabled = live != null ? live : enableLiveUpdates;
939
+ const outcomeIds = venueOutcomes == null ? void 0 : venueOutcomes.map((v) => v.venueMarketOutcomeId).filter(Boolean);
940
+ const subscriptionIds = (outcomeIds == null ? void 0 : outcomeIds.length) ? [...new Set(outcomeIds)] : marketId ? [marketId] : [];
941
+ const selectedOutcomeId = (_a = subscriptionIds[0]) != null ? _a : null;
942
+ useMarketDataSubscription({
943
+ marketId: selectedOutcomeId,
944
+ additionalMarketIds: subscriptionIds.slice(1),
945
+ enabled: enabled && !!selectedOutcomeId,
946
+ orderbook: true
947
+ });
948
+ const liveQueries = useQueries3({
949
+ queries: subscriptionIds.map((subscriptionId) => ({
950
+ queryKey: marketDataKeys.live(subscriptionId),
951
+ queryFn: () => createMarketLiveState(subscriptionId),
952
+ staleTime: Infinity,
953
+ gcTime: 5 * 6e4,
954
+ refetchOnMount: false,
955
+ refetchOnWindowFocus: false,
956
+ refetchOnReconnect: false
957
+ }))
958
+ });
959
+ const liveStates = subscriptionIds.map((subscriptionId, index) => {
960
+ var _a2, _b2;
961
+ return (_b2 = (_a2 = liveQueries[index]) == null ? void 0 : _a2.data) != null ? _b2 : createMarketLiveState(subscriptionId);
962
+ });
963
+ const primaryOrderbook = (_c = (_b = liveStates[0]) == null ? void 0 : _b.orderbook) != null ? _c : null;
964
+ const primarySnapshotVersion = (_e = (_d = liveStates[0]) == null ? void 0 : _d.orderbookSnapshotVersion) != null ? _e : 0;
965
+ const data = primaryOrderbook ? applyOrderbookDepth(
966
+ createMarketOrderbookDataFromState(primaryOrderbook, {
967
+ snapshotVersion: primarySnapshotVersion
968
+ }),
969
+ depth
970
+ ) : null;
971
+ const dataById = Object.fromEntries(
972
+ liveStates.flatMap((liveState, index) => {
973
+ if (!liveState.orderbook) return [];
974
+ return [
975
+ [
976
+ subscriptionIds[index],
977
+ applyOrderbookDepth(
978
+ createMarketOrderbookDataFromState(liveState.orderbook, {
979
+ snapshotVersion: liveState.orderbookSnapshotVersion
980
+ }),
981
+ depth
982
+ )
983
+ ]
984
+ ];
985
+ })
986
+ );
987
+ const hasAnyOrderbook = liveStates.some((liveState) => liveState.orderbook != null);
988
+ const liveOrderbookErrorMessage = enabled && liveEnabled && !hasAnyOrderbook ? (_g = (_f = liveStates.find(
989
+ (liveState) => typeof liveState.orderbookError === "string" && liveState.orderbookError.length > 0
990
+ )) == null ? void 0 : _f.orderbookError) != null ? _g : null : null;
991
+ return {
992
+ data,
993
+ dataById,
994
+ isLoading: enabled && liveEnabled && !hasAnyOrderbook && isConnected && liveOrderbookErrorMessage == null,
995
+ error: liveOrderbookErrorMessage ? new Error(liveOrderbookErrorMessage) : null,
996
+ isLive: Boolean(liveEnabled && selectedOutcomeId && isConnected),
997
+ refetch: () => __async(null, null, function* () {
998
+ if (!enabled) return;
999
+ if (subscriptionIds.length === 0) return;
1000
+ subscriptionIds.forEach((subscriptionId) => {
1001
+ queryClient.setQueryData(
1002
+ marketDataKeys.live(subscriptionId),
1003
+ (previous) => __spreadProps(__spreadValues({}, previous != null ? previous : createMarketLiveState(subscriptionId)), {
1004
+ orderbookError: null
1005
+ })
1006
+ );
1007
+ });
1008
+ ws == null ? void 0 : ws.resnapshot(subscriptionIds);
1009
+ })
1010
+ };
1011
+ }
1012
+
1013
+ // src/use-order-book.ts
1014
+ import { keepPreviousData as keepPreviousData2, useQuery as useQuery3 } from "@tanstack/react-query";
1015
+ function useOrderBook(options) {
1016
+ const client = useAggClient();
1017
+ const { orderbooks, enabled = true, canonicalMarketId } = options;
1018
+ const requestedVenueMarketIds = [...new Set(orderbooks.map(({ market }) => market.id))];
1019
+ const canonicalResult = useMarketOrderbook({
1020
+ marketId: canonicalMarketId != null ? canonicalMarketId : null,
1021
+ enabled: enabled && !!canonicalMarketId && orderbooks.length > 0,
1022
+ venueOutcomes: canonicalMarketId ? orderbooks.map(({ market, outcome }) => ({
1023
+ venue: market.venue,
1024
+ venueMarketOutcomeId: outcome.id
1025
+ })) : void 0
1026
+ });
1027
+ const batchedResult = useQuery3({
1028
+ queryKey: requestedVenueMarketIds.length ? ["orderbooks", requestedVenueMarketIds, null] : ["orderbooks", "__disabled__", null],
1029
+ queryFn: ({ signal }) => client.getOrderbooks(
1030
+ {
1031
+ venueMarketIds: requestedVenueMarketIds
1032
+ },
1033
+ { signal }
1034
+ ),
1035
+ enabled: enabled && !canonicalMarketId && requestedVenueMarketIds.length > 0,
1036
+ staleTime: 1e4,
1037
+ gcTime: 5 * 6e4,
1038
+ refetchOnWindowFocus: false,
1039
+ retry: 1,
1040
+ placeholderData: keepPreviousData2
1041
+ });
1042
+ const data = (() => {
1043
+ var _a, _b;
1044
+ if (canonicalMarketId) {
1045
+ const canonicalData = canonicalResult.data;
1046
+ if (!canonicalData) return void 0;
1047
+ const merged2 = orderbooks.flatMap(({ market, outcome }) => {
1048
+ const venueBook = canonicalData.venueOrderbooks[market.venue];
1049
+ if (!venueBook) return [];
1050
+ return [
1051
+ {
1052
+ market,
1053
+ outcome,
1054
+ orderbook: {
1055
+ bids: venueBook.bids,
1056
+ asks: venueBook.asks
1057
+ }
1058
+ }
1059
+ ];
1060
+ });
1061
+ return merged2.length === orderbooks.length ? merged2 : void 0;
1062
+ }
1063
+ const liveBooksByMarketId = new Map(
1064
+ ((_b = (_a = batchedResult.data) == null ? void 0 : _a.data) != null ? _b : []).filter((item) => item.status === "ok").map((item) => [item.venueMarketId, item])
1065
+ );
1066
+ const merged = orderbooks.flatMap(({ market, outcome }, index) => {
1067
+ var _a2;
1068
+ void index;
1069
+ const item = liveBooksByMarketId.get(market.id);
1070
+ const orderbook = (_a2 = item == null ? void 0 : item.venueOrderbooks[market.venue]) == null ? void 0 : _a2.orderbook;
1071
+ if (!orderbook) return [];
1072
+ return [
1073
+ {
1074
+ market,
1075
+ outcome,
1076
+ orderbook
1077
+ }
1078
+ ];
1079
+ });
1080
+ return merged.length === orderbooks.length ? merged : void 0;
1081
+ })();
1082
+ const aggregated = canonicalResult.data ? marketOrderbookDataToResponse(canonicalResult.data) : null;
1083
+ const error = canonicalMarketId ? canonicalResult.error : batchedResult.error;
1084
+ return {
1085
+ data,
1086
+ isLoading: canonicalMarketId ? canonicalResult.isLoading : batchedResult.isLoading,
1087
+ error: error instanceof Error ? error : error ? new Error(String(error)) : null,
1088
+ results: [batchedResult],
1089
+ aggregated,
1090
+ isLive: canonicalResult.isLive
1091
+ };
1092
+ }
1093
+
1094
+ // src/use-orderbook-quote.ts
1095
+ import { keepPreviousData as keepPreviousData3, useQuery as useQuery4 } from "@tanstack/react-query";
1096
+ var QUOTE_DEBOUNCE_MS = 300;
1097
+ var createUnavailableOrderbookError = (message, code, retryable) => {
1098
+ const error = new Error(message);
1099
+ error.status = 404;
1100
+ if (code) error.code = code;
1101
+ if (retryable !== void 0) error.retryable = retryable;
1102
+ return error;
1103
+ };
1104
+ var quoteVenueOrderbooks = ({
1105
+ marketId,
1106
+ side,
1107
+ requestedSize,
1108
+ venueOrderbooks
1109
+ }) => {
1110
+ var _a;
1111
+ const marketData = createMarketOrderbookDataFromVenueOrderbooks({
1112
+ marketId,
1113
+ venueOrderbooks
1114
+ });
1115
+ const levels = side === "buy" ? marketData.orderbook.asks : marketData.orderbook.bids;
1116
+ let remaining = requestedSize;
1117
+ const fillsByVenue = /* @__PURE__ */ new Map();
1118
+ for (const level of levels) {
1119
+ if (remaining <= 0) break;
1120
+ for (const [venue, venueSize] of Object.entries(level.venues)) {
1121
+ if (remaining <= 0) break;
1122
+ const fillSize = Math.min(remaining, venueSize);
1123
+ const fillCost = fillSize * level.price;
1124
+ remaining -= fillSize;
1125
+ const existing = (_a = fillsByVenue.get(venue)) != null ? _a : { size: 0, cost: 0 };
1126
+ existing.size += fillSize;
1127
+ existing.cost += fillCost;
1128
+ fillsByVenue.set(venue, existing);
1129
+ }
1130
+ }
1131
+ const filledSize = requestedSize - Math.max(0, remaining);
1132
+ const totalCost = [...fillsByVenue.values()].reduce((sum, fill) => sum + fill.cost, 0);
1133
+ const avgPrice = filledSize > 0 ? totalCost / filledSize : null;
1134
+ const slippage = avgPrice !== null && marketData.midpoint !== null ? side === "buy" ? avgPrice - marketData.midpoint : marketData.midpoint - avgPrice : null;
1135
+ return {
1136
+ marketId,
1137
+ side,
1138
+ requestedSize,
1139
+ filledSize,
1140
+ avgPrice,
1141
+ totalCost,
1142
+ slippage,
1143
+ fills: [...fillsByVenue.entries()].map(([venue, fill]) => ({
1144
+ venue,
1145
+ size: fill.size,
1146
+ avgPrice: fill.size > 0 ? fill.cost / fill.size : 0,
1147
+ cost: fill.cost
1148
+ }))
1149
+ };
1150
+ };
1151
+ function useOrderbookQuote(options) {
1152
+ var _a;
1153
+ const client = useAggClient();
1154
+ const { marketId, side, size, enabled = true } = options;
1155
+ const debouncedSize = useDebouncedValue(size, QUOTE_DEBOUNCE_MS);
1156
+ const shouldFetch = enabled && !!marketId && debouncedSize > 0;
1157
+ const query = useQuery4({
1158
+ queryKey: marketId ? marketDataKeys.orderbookQuote(marketId, side, debouncedSize) : ["market-data", "orderbook-quote", "__disabled__"],
1159
+ queryFn: () => __async(null, null, function* () {
1160
+ var _a2, _b, _c, _d;
1161
+ const response = yield client.getOrderbooks({
1162
+ venueMarketIds: [marketId]
1163
+ });
1164
+ const item = response.data.find((entry) => entry.venueMarketId === marketId);
1165
+ if (!item) {
1166
+ throw createUnavailableOrderbookError(`No orderbook payload returned for ${marketId}.`);
1167
+ }
1168
+ if (item.status !== "ok") {
1169
+ throw createUnavailableOrderbookError(
1170
+ (_b = (_a2 = item.error) == null ? void 0 : _a2.message) != null ? _b : `No live orderbook is available for ${marketId}.`,
1171
+ (_c = item.error) == null ? void 0 : _c.code,
1172
+ (_d = item.error) == null ? void 0 : _d.retryable
1173
+ );
1174
+ }
1175
+ return quoteVenueOrderbooks({
1176
+ marketId,
1177
+ side,
1178
+ requestedSize: debouncedSize,
1179
+ venueOrderbooks: Object.fromEntries(
1180
+ Object.entries(item.venueOrderbooks).map(([venue, entry]) => [venue, entry.orderbook])
1181
+ )
1182
+ });
1183
+ }),
1184
+ enabled: shouldFetch && debouncedSize > 0,
1185
+ staleTime: 1e4,
1186
+ gcTime: 5 * 6e4,
1187
+ retry: 1,
1188
+ placeholderData: keepPreviousData3
1189
+ });
1190
+ return {
1191
+ data: (_a = query.data) != null ? _a : null,
1192
+ isLoading: query.isLoading,
1193
+ isFetching: query.isFetching,
1194
+ error: query.error instanceof Error ? query.error : query.error ? new Error(String(query.error)) : null
1195
+ };
1196
+ }
1197
+
1198
+ // src/use-orders.ts
1199
+ import { useQuery as useQuery5 } from "@tanstack/react-query";
1200
+ function useOrders(options = {}) {
1201
+ var _a, _b, _c, _d;
1202
+ const client = useAggClient();
1203
+ const { userId, status, limit = 50, offset = 0, enabled = true } = options;
1204
+ const query = useQuery5({
1205
+ queryKey: ["orders", userId != null ? userId : "me", status != null ? status : "all", limit, offset],
1206
+ queryFn: () => client.getOrders({
1207
+ userId,
1208
+ status,
1209
+ limit,
1210
+ offset
1211
+ }),
1212
+ enabled
1213
+ });
1214
+ return __spreadProps(__spreadValues({}, query), {
1215
+ orders: (_b = (_a = query.data) == null ? void 0 : _a.orders) != null ? _b : [],
1216
+ total: (_d = (_c = query.data) == null ? void 0 : _c.total) != null ? _d : 0
1217
+ });
1218
+ }
1219
+
1220
+ // src/use-search.ts
1221
+ import {
1222
+ QueryClient,
1223
+ QueryClientContext,
1224
+ keepPreviousData as keepPreviousData4,
1225
+ useInfiniteQuery as useInfiniteQuery5
1226
+ } from "@tanstack/react-query";
1227
+ import { useContext as useContext2, useEffect as useEffect5, useState as useState4 } from "react";
1228
+ function useSearch(options) {
1229
+ var _a, _b, _c;
1230
+ const client = useContext2(AggClientContext);
1231
+ const queryClient = useContext2(QueryClientContext);
1232
+ const [fallbackQueryClient] = useState4(() => new QueryClient());
1233
+ const { q, type, categoryIds, limit = 20, enabled = true } = options;
1234
+ const isEnabled = enabled && q.length > 0;
1235
+ useEffect5(() => {
1236
+ if (queryClient) return void 0;
1237
+ fallbackQueryClient.mount();
1238
+ return () => {
1239
+ fallbackQueryClient.unmount();
1240
+ };
1241
+ }, [fallbackQueryClient, queryClient]);
1242
+ if (isEnabled && !client) {
1243
+ throw new Error("useSearch must be used within an <AggProvider>");
1244
+ }
1245
+ const query = useInfiniteQuery5(
1246
+ {
1247
+ queryKey: ["search", q, type, (_a = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _a : "", limit],
1248
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
1249
+ if (!client) {
1250
+ throw new Error("useSearch must be used within an <AggProvider>");
1251
+ }
1252
+ const res = yield client.search({
1253
+ q,
1254
+ type,
1255
+ categoryIds,
1256
+ limit,
1257
+ cursor: pageParam
1258
+ });
1259
+ return res;
1260
+ }),
1261
+ initialPageParam: void 0,
1262
+ getNextPageParam: (lastPage) => {
1263
+ var _a2;
1264
+ if (!lastPage.hasMore) return void 0;
1265
+ return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1266
+ },
1267
+ placeholderData: keepPreviousData4,
1268
+ enabled: isEnabled && !!client
1269
+ },
1270
+ queryClient != null ? queryClient : fallbackQueryClient
1271
+ );
1272
+ const data = (_c = (_b = query.data) == null ? void 0 : _b.pages.flatMap((page) => page.data)) != null ? _c : [];
1273
+ return {
1274
+ data,
1275
+ isLoading: query.isLoading,
1276
+ isError: query.isError,
1277
+ error: query.error,
1278
+ hasNextPage: !!query.hasNextPage,
1279
+ fetchNextPage: query.fetchNextPage,
1280
+ isFetchingNextPage: query.isFetchingNextPage,
1281
+ isPlaceholderData: query.isPlaceholderData
1282
+ };
1283
+ }
1284
+
1285
+ // src/use-smart-route.ts
1286
+ import { useQuery as useQuery6, keepPreviousData as keepPreviousData5 } from "@tanstack/react-query";
1287
+ function useSmartRoute(options) {
1288
+ var _a, _b;
1289
+ const client = useAggClient();
1290
+ const {
1291
+ venueMarketOutcomeId,
1292
+ venueMarketId,
1293
+ outcomeId,
1294
+ side,
1295
+ tradeSide,
1296
+ maxSpend,
1297
+ sellShares,
1298
+ chainBalances,
1299
+ slipCapBps,
1300
+ compareVenues,
1301
+ enabled = true
1302
+ } = options;
1303
+ const resolvedVenueMarketOutcomeId = (_a = venueMarketOutcomeId != null ? venueMarketOutcomeId : venueMarketId) != null ? _a : outcomeId;
1304
+ const query = useQuery6({
1305
+ queryKey: [
1306
+ "smart-route",
1307
+ resolvedVenueMarketOutcomeId,
1308
+ side != null ? side : null,
1309
+ tradeSide != null ? tradeSide : null,
1310
+ maxSpend != null ? maxSpend : null,
1311
+ sellShares != null ? sellShares : null,
1312
+ chainBalances ? JSON.stringify(chainBalances) : null,
1313
+ slipCapBps != null ? slipCapBps : null,
1314
+ compareVenues != null ? compareVenues : false
1315
+ ],
1316
+ queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
1317
+ return client.getSmartRoute(
1318
+ {
1319
+ venueMarketOutcomeId: resolvedVenueMarketOutcomeId,
1320
+ side: side != null ? side : void 0,
1321
+ tradeSide: tradeSide != null ? tradeSide : void 0,
1322
+ maxSpend,
1323
+ sellShares,
1324
+ chainBalances,
1325
+ slipCapBps,
1326
+ compareVenues
1327
+ },
1328
+ { signal }
1329
+ );
1330
+ }),
1331
+ enabled: enabled && !!resolvedVenueMarketOutcomeId && ((maxSpend != null ? maxSpend : 0) > 0 || (sellShares != null ? sellShares : 0) > 0),
1332
+ staleTime: 1e4,
1333
+ gcTime: 6e4,
1334
+ refetchOnWindowFocus: false,
1335
+ retry: 1,
1336
+ placeholderData: keepPreviousData5
1337
+ });
1338
+ const error = query.error;
1339
+ return {
1340
+ data: (_b = query.data) != null ? _b : null,
1341
+ isLoading: query.isLoading,
1342
+ isFetching: query.isFetching,
1343
+ error: error instanceof Error ? error : error ? new Error(String(error)) : null,
1344
+ refetch: query.refetch
1345
+ };
1346
+ }
1347
+
1348
+ // src/use-user-holdings.ts
1349
+ import { useInfiniteQuery as useInfiniteQuery6 } from "@tanstack/react-query";
1350
+ function useUserHoldings(options) {
1351
+ var _a, _b;
1352
+ const client = useAggClient();
1353
+ const { venue, venueMarketId, venueEventId, enabled = true } = options;
1354
+ const query = useInfiniteQuery6({
1355
+ queryKey: ["user-holdings", venue, venueMarketId, venueEventId],
1356
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
1357
+ return client.getUserHoldings({
1358
+ venue,
1359
+ venueMarketId,
1360
+ venueEventId,
1361
+ cursor: pageParam
1362
+ });
1363
+ }),
1364
+ initialPageParam: void 0,
1365
+ getNextPageParam: (lastPage) => {
1366
+ var _a2;
1367
+ return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1368
+ },
1369
+ enabled
1370
+ });
1371
+ const holdings = (_b = (_a = query.data) == null ? void 0 : _a.pages.flatMap((p) => p.data)) != null ? _b : [];
1372
+ const hasNextPage = !!query.hasNextPage;
1373
+ return __spreadProps(__spreadValues({}, query), {
1374
+ holdings,
1375
+ hasNextPage
1376
+ });
1377
+ }
1378
+
1379
+ // src/use-enriched-venue-event.ts
1380
+ import { useMemo as useMemo8 } from "react";
1381
+
1382
+ // src/use-venue-event.ts
1383
+ import { useQuery as useQuery7 } from "@tanstack/react-query";
1384
+ function useVenueEvent(options) {
1385
+ var _a;
1386
+ const client = useAggClient();
1387
+ const { eventId, enabled = true } = options;
1388
+ const query = useQuery7({
1389
+ queryKey: ["venue-event", eventId],
1390
+ queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
1391
+ return client.getVenueEventById(eventId, { signal });
1392
+ }),
1393
+ enabled: enabled && !!eventId,
1394
+ staleTime: 5 * 6e4,
1395
+ gcTime: 5 * 6e4,
1396
+ refetchOnWindowFocus: true,
1397
+ refetchOnReconnect: true,
1398
+ refetchOnMount: true,
1399
+ retry: 1
1400
+ });
1401
+ return __spreadProps(__spreadValues({}, query), {
1402
+ event: (_a = query.data) != null ? _a : void 0
1403
+ });
1404
+ }
1405
+
1406
+ // src/use-venue-markets.ts
1407
+ import { QueryClient as QueryClient2, QueryClientContext as QueryClientContext2, useInfiniteQuery as useInfiniteQuery7 } from "@tanstack/react-query";
1408
+ import { useContext as useContext3, useEffect as useEffect6, useState as useState5 } from "react";
1409
+ function useVenueMarkets(options) {
1410
+ var _a, _b, _c, _d, _e;
1411
+ const client = useContext3(AggClientContext);
1412
+ const queryClient = useContext3(QueryClientContext2);
1413
+ const [fallbackQueryClient] = useState5(() => new QueryClient2());
1414
+ const venue = options == null ? void 0 : options.venue;
1415
+ const venueEventId = options == null ? void 0 : options.venueEventId;
1416
+ const search = options == null ? void 0 : options.search;
1417
+ const matchStatus = options == null ? void 0 : options.matchStatus;
1418
+ const status = options == null ? void 0 : options.status;
1419
+ const categoryIds = options == null ? void 0 : options.categoryIds;
1420
+ const enabled = (_a = options == null ? void 0 : options.enabled) != null ? _a : true;
1421
+ const limit = (_b = options == null ? void 0 : options.limit) != null ? _b : 20;
1422
+ const sortBy = options == null ? void 0 : options.sortBy;
1423
+ const sortDir = options == null ? void 0 : options.sortDir;
1424
+ useEffect6(() => {
1425
+ if (queryClient) return void 0;
1426
+ fallbackQueryClient.mount();
1427
+ return () => {
1428
+ fallbackQueryClient.unmount();
1429
+ };
1430
+ }, [fallbackQueryClient, queryClient]);
1431
+ if (enabled && !client) {
1432
+ throw new Error("useVenueMarkets must be used within an <AggProvider>");
1433
+ }
1434
+ const query = useInfiniteQuery7(
1435
+ {
1436
+ queryKey: [
1437
+ "venue-markets",
1438
+ venue != null ? venue : "",
1439
+ venueEventId != null ? venueEventId : "",
1440
+ search != null ? search : "",
1441
+ matchStatus != null ? matchStatus : "",
1442
+ status != null ? status : "",
1443
+ (_c = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _c : "",
1444
+ limit,
1445
+ sortBy != null ? sortBy : "",
1446
+ sortDir != null ? sortDir : ""
1447
+ ],
1448
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
1449
+ if (!client) {
1450
+ throw new Error("useVenueMarkets must be used within an <AggProvider>");
1451
+ }
1452
+ const res = yield client.getVenueMarkets({
1453
+ venue,
1454
+ venueEventId,
1455
+ search,
1456
+ matchStatus,
1457
+ status,
1458
+ categoryIds,
1459
+ limit,
1460
+ cursor: pageParam,
1461
+ sortBy,
1462
+ sortDir
1463
+ });
1464
+ return res;
1465
+ }),
1466
+ initialPageParam: void 0,
1467
+ getNextPageParam: (lastPage) => {
1468
+ var _a2;
1469
+ if (!lastPage.hasMore) return void 0;
1470
+ return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1471
+ },
1472
+ enabled: enabled && !!client
1473
+ },
1474
+ queryClient != null ? queryClient : fallbackQueryClient
1475
+ );
1476
+ const markets = (_e = (_d = query.data) == null ? void 0 : _d.pages.flatMap((page) => page.data)) != null ? _e : [];
1477
+ const hasNextPage = !!query.hasNextPage;
1478
+ return __spreadProps(__spreadValues({}, query), {
1479
+ markets,
1480
+ hasNextPage
1481
+ });
1482
+ }
1483
+
1484
+ // src/use-enriched-venue-event.ts
1485
+ function mergeEventWithFullMarkets(event, fullMarkets) {
1486
+ if (fullMarkets.length === 0) return event;
1487
+ const fullById = new Map(fullMarkets.map((m) => [m.id, m]));
1488
+ const mergedMarkets = event.venueMarkets.map((minimal) => {
1489
+ var _a;
1490
+ return (_a = fullById.get(minimal.id)) != null ? _a : minimal;
1491
+ });
1492
+ return __spreadProps(__spreadValues({}, event), { venueMarkets: mergedMarkets });
1493
+ }
1494
+ function useEnrichedVenueEvent(options) {
1495
+ var _b;
1496
+ const _a = useVenueEvent(options), { event, isLoading, error } = _a, rest = __objRest(_a, ["event", "isLoading", "error"]);
1497
+ const { markets, isLoading: isEnriching } = useVenueMarkets({
1498
+ venueEventId: options.eventId,
1499
+ enabled: ((_b = options.enabled) != null ? _b : true) && !!event,
1500
+ status: "open" /* open */,
1501
+ sortBy: "yesPrice",
1502
+ sortDir: "desc"
1503
+ });
1504
+ const enrichedEvent = useMemo8(() => {
1505
+ if (!event) return void 0;
1506
+ if (markets.length === 0) return event;
1507
+ return mergeEventWithFullMarkets(event, markets);
1508
+ }, [event, markets]);
1509
+ return __spreadProps(__spreadValues({}, rest), {
1510
+ event: enrichedEvent,
1511
+ isLoading,
1512
+ isEnriching,
1513
+ error
1514
+ });
1515
+ }
1516
+
1517
+ // src/use-venue-events.ts
1518
+ import {
1519
+ QueryClient as QueryClient3,
1520
+ QueryClientContext as QueryClientContext3,
1521
+ keepPreviousData as keepPreviousData6,
1522
+ useInfiniteQuery as useInfiniteQuery8
1523
+ } from "@tanstack/react-query";
1524
+ import { useContext as useContext4, useEffect as useEffect7, useMemo as useMemo9, useRef as useRef3, useState as useState6 } from "react";
1525
+ function useVenueEvents(options) {
1526
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1527
+ const client = useContext4(AggClientContext);
1528
+ const queryClient = useContext4(QueryClientContext3);
1529
+ const [fallbackQueryClient] = useState6(() => new QueryClient3());
1530
+ const venues = options == null ? void 0 : options.venues;
1531
+ const search = options == null ? void 0 : options.search;
1532
+ const categoryIds = options == null ? void 0 : options.categoryIds;
1533
+ const matchStatus = (_a = options == null ? void 0 : options.matchStatus) != null ? _a : [];
1534
+ const enabled = (_b = options == null ? void 0 : options.enabled) != null ? _b : true;
1535
+ const limit = (_c = options == null ? void 0 : options.limit) != null ? _c : 20;
1536
+ const status = options == null ? void 0 : options.status;
1537
+ const sortBy = options == null ? void 0 : options.sortBy;
1538
+ const sortDir = options == null ? void 0 : options.sortDir;
1539
+ const queryKeyScope = (_d = options == null ? void 0 : options.queryKeyScope) != null ? _d : "events";
1540
+ const minYesPrice = options == null ? void 0 : options.minYesPrice;
1541
+ const maxYesPrice = options == null ? void 0 : options.maxYesPrice;
1542
+ const endDateFrom = options == null ? void 0 : options.endDateFrom;
1543
+ const initialPages = options == null ? void 0 : options.initialPages;
1544
+ useEffect7(() => {
1545
+ if (queryClient) return void 0;
1546
+ fallbackQueryClient.mount();
1547
+ return () => {
1548
+ fallbackQueryClient.unmount();
1549
+ };
1550
+ }, [fallbackQueryClient, queryClient]);
1551
+ if (enabled && !client) {
1552
+ throw new Error("useVenueEvents must be used within an <AggProvider>");
1553
+ }
1554
+ const query = useInfiniteQuery8(
1555
+ {
1556
+ queryKey: [
1557
+ queryKeyScope,
1558
+ venues != null ? venues : [],
1559
+ search != null ? search : "",
1560
+ (_e = categoryIds == null ? void 0 : categoryIds.join(",")) != null ? _e : "",
1561
+ (_f = matchStatus == null ? void 0 : matchStatus.join(",")) != null ? _f : "",
1562
+ (_g = status == null ? void 0 : status.join(",")) != null ? _g : "",
1563
+ sortBy != null ? sortBy : "",
1564
+ sortDir != null ? sortDir : "",
1565
+ minYesPrice != null ? minYesPrice : "",
1566
+ maxYesPrice != null ? maxYesPrice : "",
1567
+ endDateFrom != null ? endDateFrom : "",
1568
+ limit
1569
+ ],
1570
+ queryFn: (_0) => __async(null, [_0], function* ({ pageParam }) {
1571
+ if (!client) {
1572
+ throw new Error("useVenueEvents must be used within an <AggProvider>");
1573
+ }
1574
+ const res = yield client.getVenueEvents({
1575
+ venues,
1576
+ search,
1577
+ categoryIds,
1578
+ matchStatus,
1579
+ status,
1580
+ sortBy,
1581
+ sortDir,
1582
+ limit,
1583
+ minYesPrice,
1584
+ maxYesPrice,
1585
+ endDateFrom,
1586
+ cursor: pageParam
1587
+ });
1588
+ return res;
1589
+ }),
1590
+ initialPageParam: void 0,
1591
+ getNextPageParam: (lastPage) => {
1592
+ var _a2;
1593
+ if (!lastPage.hasMore) return void 0;
1594
+ return (_a2 = lastPage.nextCursor) != null ? _a2 : void 0;
1595
+ },
1596
+ placeholderData: keepPreviousData6,
1597
+ enabled: enabled && !!client
1598
+ },
1599
+ queryClient != null ? queryClient : fallbackQueryClient
1600
+ );
1601
+ const prefetchedRef = useRef3(false);
1602
+ useEffect7(() => {
1603
+ var _a2, _b2;
1604
+ if (prefetchedRef.current) return;
1605
+ if (!initialPages || initialPages <= 1) return;
1606
+ if (query.isLoading) return;
1607
+ const pagesLoaded = (_b2 = (_a2 = query.data) == null ? void 0 : _a2.pages.length) != null ? _b2 : 0;
1608
+ if (pagesLoaded >= initialPages || !query.hasNextPage) {
1609
+ prefetchedRef.current = true;
1610
+ return;
1611
+ }
1612
+ void query.fetchNextPage();
1613
+ }, [
1614
+ initialPages,
1615
+ query.isLoading,
1616
+ (_h = query.data) == null ? void 0 : _h.pages.length,
1617
+ query.hasNextPage,
1618
+ query.fetchNextPage
1619
+ ]);
1620
+ const events = useMemo9(
1621
+ () => {
1622
+ var _a2, _b2;
1623
+ return (_b2 = (_a2 = query.data) == null ? void 0 : _a2.pages.flatMap((page) => page.data)) != null ? _b2 : [];
1624
+ },
1625
+ [(_i = query.data) == null ? void 0 : _i.pages]
1626
+ );
1627
+ const hasNextPage = !!query.hasNextPage;
1628
+ const loadedPageCount = (_k = (_j = query.data) == null ? void 0 : _j.pages.length) != null ? _k : 0;
1629
+ return __spreadProps(__spreadValues({}, query), {
1630
+ events,
1631
+ hasNextPage,
1632
+ loadedPageCount,
1633
+ isPlaceholderData: query.isPlaceholderData
1634
+ });
1635
+ }
1636
+
1637
+ // src/use-venue-market-midpoints.ts
1638
+ import { keepPreviousData as keepPreviousData7, useQuery as useQuery8 } from "@tanstack/react-query";
1639
+ var MAX_VENUE_MARKET_IDS_PER_REQUEST = 200;
1640
+ var normalizeVenueMarketIds2 = (venueMarketIds) => {
1641
+ return [
1642
+ ...new Set(venueMarketIds.map((venueMarketId) => venueMarketId.trim()).filter(Boolean))
1643
+ ].sort((left, right) => left.localeCompare(right));
1644
+ };
1645
+ var chunkVenueMarketIds = (venueMarketIds) => {
1646
+ if (venueMarketIds.length === 0) return [];
1647
+ const chunks = [];
1648
+ for (let index = 0; index < venueMarketIds.length; index += MAX_VENUE_MARKET_IDS_PER_REQUEST) {
1649
+ chunks.push(venueMarketIds.slice(index, index + MAX_VENUE_MARKET_IDS_PER_REQUEST));
1650
+ }
1651
+ return chunks;
1652
+ };
1653
+ var mergeMidpointResponses = (responses) => {
1654
+ return {
1655
+ data: responses.flatMap((response) => response.data)
1656
+ };
1657
+ };
1658
+ var mapMidpointsByVenueMarketId = (rows) => {
1659
+ const mappedMidpoints = /* @__PURE__ */ new Map();
1660
+ rows.forEach((row) => {
1661
+ mappedMidpoints.set(row.venueMarketId, row.midpoint);
1662
+ row.matched.forEach((matchedRow) => {
1663
+ if (mappedMidpoints.has(matchedRow.venueMarketId)) return;
1664
+ mappedMidpoints.set(matchedRow.venueMarketId, matchedRow.midpoint);
1665
+ });
1666
+ });
1667
+ return mappedMidpoints;
1668
+ };
1669
+ function useVenueMarketMidpoints(options) {
1670
+ var _a, _b, _c;
1671
+ const client = useAggClient();
1672
+ const enabled = (_a = options.enabled) != null ? _a : true;
1673
+ const requestedVenueMarketIds = normalizeVenueMarketIds2(options.venueMarketIds);
1674
+ const query = useQuery8({
1675
+ queryKey: requestedVenueMarketIds.length ? ["venue-market-midpoints", requestedVenueMarketIds] : ["venue-market-midpoints", "__disabled__"],
1676
+ queryFn: (_0) => __async(null, [_0], function* ({ signal }) {
1677
+ const venueMarketIdChunks = chunkVenueMarketIds(requestedVenueMarketIds);
1678
+ if (venueMarketIdChunks.length === 0) {
1679
+ return { data: [] };
1680
+ }
1681
+ const chunkResponses = yield Promise.all(
1682
+ venueMarketIdChunks.map((venueMarketIds) => {
1683
+ return client.getMidpoints({ venueMarketIds }, { signal });
1684
+ })
1685
+ );
1686
+ return mergeMidpointResponses(chunkResponses);
1687
+ }),
1688
+ enabled: enabled && requestedVenueMarketIds.length > 0,
1689
+ staleTime: 1e4,
1690
+ gcTime: 5 * 6e4,
1691
+ refetchOnWindowFocus: false,
1692
+ retry: 1,
1693
+ placeholderData: keepPreviousData7
1694
+ });
1695
+ const midpointRows = (_c = (_b = query.data) == null ? void 0 : _b.data) != null ? _c : [];
1696
+ const midpointsByVenueMarketId = mapMidpointsByVenueMarketId(midpointRows);
1697
+ return __spreadProps(__spreadValues({}, query), {
1698
+ midpointRows,
1699
+ midpointsByVenueMarketId,
1700
+ requestedVenueMarketIds
1701
+ });
1702
+ }
1703
+
1704
+ // src/utils/compute-price-gaps.ts
1705
+ var MIN_PRICE_GAP_PCT = 3;
1706
+ function computePriceGaps(input) {
1707
+ var _a;
1708
+ const { markets, midpointsByVenueMarketId } = input;
1709
+ const result = /* @__PURE__ */ new Map();
1710
+ for (const market of markets) {
1711
+ const ownMidpoint = midpointsByVenueMarketId.get(market.id);
1712
+ if (ownMidpoint == null || ownMidpoint <= 0) continue;
1713
+ const siblings = (_a = market.matchedVenueMarkets) != null ? _a : [];
1714
+ if (siblings.length === 0) continue;
1715
+ let maxGap = 0;
1716
+ for (const sibling of siblings) {
1717
+ const siblingMidpoint = midpointsByVenueMarketId.get(sibling.id);
1718
+ if (siblingMidpoint == null || siblingMidpoint <= 0) continue;
1719
+ const gap = Math.abs(ownMidpoint - siblingMidpoint) / ownMidpoint * 100;
1720
+ if (gap > maxGap) maxGap = gap;
1721
+ }
1722
+ if (maxGap >= MIN_PRICE_GAP_PCT) result.set(market.id, maxGap);
1723
+ }
1724
+ return result;
1725
+ }
1726
+
1727
+ // src/use-viewport-midpoints.ts
1728
+ import { useEffect as useEffect8, useMemo as useMemo10, useRef as useRef4, useState as useState7 } from "react";
1729
+ var resolveUncachedVisibleMarketIds = (visibleMarkets, cache, inFlightIds) => {
1730
+ const idsToFetch = [];
1731
+ for (const market of visibleMarkets) {
1732
+ if (inFlightIds.has(market.id)) continue;
1733
+ if (cache.has(market.id)) continue;
1734
+ idsToFetch.push(market.id);
1735
+ }
1736
+ return idsToFetch;
1737
+ };
1738
+ var buildCachedMidpointEntries = (requestedVenueMarketIds, rows) => {
1739
+ var _a, _b;
1740
+ const rowsByVenueMarketId = new Map(rows.map((item) => [item.venueMarketId, item]));
1741
+ const nextCacheEntries = /* @__PURE__ */ new Map();
1742
+ for (const venueMarketId of requestedVenueMarketIds) {
1743
+ const item = rowsByVenueMarketId.get(venueMarketId);
1744
+ nextCacheEntries.set(venueMarketId, {
1745
+ midpoint: (_a = item == null ? void 0 : item.midpoint) != null ? _a : null,
1746
+ matched: ((_b = item == null ? void 0 : item.matched) != null ? _b : []).map((matched) => {
1747
+ var _a2;
1748
+ return {
1749
+ venueMarketId: matched.venueMarketId,
1750
+ midpoint: (_a2 = matched.midpoint) != null ? _a2 : null
1751
+ };
1752
+ })
1753
+ });
1754
+ }
1755
+ return nextCacheEntries;
1756
+ };
1757
+ function useViewportMidpoints(visibleMarkets) {
1758
+ const client = useAggClient();
1759
+ const [cache, setCache] = useState7(() => /* @__PURE__ */ new Map());
1760
+ const inFlightRef = useRef4(/* @__PURE__ */ new Set());
1761
+ const visibleRef = useRef4(visibleMarkets);
1762
+ visibleRef.current = visibleMarkets;
1763
+ const visibleFp = useMemo10(
1764
+ () => [...new Set(visibleMarkets.map((m) => m.id))].sort().join("|"),
1765
+ [visibleMarkets]
1766
+ );
1767
+ useEffect8(() => {
1768
+ const toFetch = resolveUncachedVisibleMarketIds(visibleRef.current, cache, inFlightRef.current);
1769
+ if (!toFetch.length) return;
1770
+ let cancelled = false;
1771
+ for (const id of toFetch) inFlightRef.current.add(id);
1772
+ client.getMidpoints(toFetch).then((resp) => {
1773
+ var _a;
1774
+ if (cancelled) return;
1775
+ const nextCacheEntries = buildCachedMidpointEntries(toFetch, (_a = resp.data) != null ? _a : []);
1776
+ setCache((prev) => {
1777
+ const next = new Map(prev);
1778
+ for (const [venueMarketId, entry] of nextCacheEntries) {
1779
+ next.set(venueMarketId, entry);
1780
+ }
1781
+ return next;
1782
+ });
1783
+ }).catch(() => {
1784
+ }).finally(() => {
1785
+ for (const id of toFetch) inFlightRef.current.delete(id);
1786
+ });
1787
+ return () => {
1788
+ cancelled = true;
1789
+ };
1790
+ }, [visibleFp, cache]);
1791
+ const prices = useMemo10(() => {
1792
+ var _a;
1793
+ const map = /* @__PURE__ */ new Map();
1794
+ for (const market of visibleMarkets) {
1795
+ const entry = cache.get(market.id);
1796
+ if (!entry) continue;
1797
+ const candidates = [];
1798
+ if (entry.midpoint != null) candidates.push(entry.midpoint);
1799
+ for (const m of entry.matched) if (m.midpoint != null) candidates.push(m.midpoint);
1800
+ if (!candidates.length) continue;
1801
+ const mid = Math.max(...candidates);
1802
+ for (const outcome of market.venueMarketOutcomes) {
1803
+ const isYes = ((_a = outcome.label) == null ? void 0 : _a.toLowerCase()) === "yes";
1804
+ map.set(outcome.id, isYes ? mid : 1 - mid);
1805
+ }
1806
+ }
1807
+ return map;
1808
+ }, [cache, visibleMarkets]);
1809
+ return { prices };
1810
+ }
1811
+
1812
+ // src/use-visible-ids.ts
1813
+ import { useCallback as useCallback5, useEffect as useEffect9, useRef as useRef5, useState as useState8 } from "react";
1814
+ function useVisibleIds(options = {}) {
1815
+ const { rootMargin = "0px", threshold = 0 } = options;
1816
+ const [visibleIds, setVisibleIds] = useState8(() => /* @__PURE__ */ new Set());
1817
+ const observerRef = useRef5(null);
1818
+ const elementsRef = useRef5(/* @__PURE__ */ new Map());
1819
+ const elementIdRef = useRef5(/* @__PURE__ */ new WeakMap());
1820
+ const callbackRefsRef = useRef5(/* @__PURE__ */ new Map());
1821
+ useEffect9(() => {
1822
+ if (typeof IntersectionObserver === "undefined") return;
1823
+ const observer = new IntersectionObserver(
1824
+ (entries) => {
1825
+ setVisibleIds((prev) => {
1826
+ let changed = false;
1827
+ const next = new Set(prev);
1828
+ for (const entry of entries) {
1829
+ const id = elementIdRef.current.get(entry.target);
1830
+ if (!id) continue;
1831
+ if (entry.isIntersecting) {
1832
+ if (!next.has(id)) {
1833
+ next.add(id);
1834
+ changed = true;
1835
+ }
1836
+ } else if (next.has(id)) {
1837
+ next.delete(id);
1838
+ changed = true;
1839
+ }
1840
+ }
1841
+ return changed ? next : prev;
1842
+ });
1843
+ },
1844
+ { rootMargin, threshold }
1845
+ );
1846
+ observerRef.current = observer;
1847
+ for (const el of elementsRef.current.values()) observer.observe(el);
1848
+ return () => {
1849
+ observer.disconnect();
1850
+ observerRef.current = null;
1851
+ };
1852
+ }, [rootMargin, threshold]);
1853
+ const register = useCallback5((id) => {
1854
+ const existing = callbackRefsRef.current.get(id);
1855
+ if (existing) return existing;
1856
+ const callback = (el) => {
1857
+ var _a, _b;
1858
+ const prev = elementsRef.current.get(id);
1859
+ if (prev === el) return;
1860
+ if (prev) {
1861
+ (_a = observerRef.current) == null ? void 0 : _a.unobserve(prev);
1862
+ elementIdRef.current.delete(prev);
1863
+ elementsRef.current.delete(id);
1864
+ setVisibleIds((curr) => {
1865
+ if (!curr.has(id)) return curr;
1866
+ const next = new Set(curr);
1867
+ next.delete(id);
1868
+ return next;
1869
+ });
1870
+ }
1871
+ if (el) {
1872
+ elementsRef.current.set(id, el);
1873
+ elementIdRef.current.set(el, id);
1874
+ (_b = observerRef.current) == null ? void 0 : _b.observe(el);
1875
+ } else {
1876
+ callbackRefsRef.current.delete(id);
1877
+ }
1878
+ };
1879
+ callbackRefsRef.current.set(id, callback);
1880
+ return callback;
1881
+ }, []);
1882
+ return { visibleIds, register };
1883
+ }
1884
+
1885
+ // src/use-app-config.ts
1886
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
1887
+ var FIVE_MINUTES = 5 * 60 * 1e3;
1888
+ function useAppConfig() {
1889
+ var _a, _b, _c, _d, _e, _f;
1890
+ const client = useAggClient();
1891
+ const query = useQuery9({
1892
+ queryKey: ["agg", "app-config"],
1893
+ queryFn: () => client.getAppConfig(),
1894
+ staleTime: FIVE_MINUTES
1895
+ });
1896
+ return {
1897
+ disabledVenues: (_b = (_a = query.data) == null ? void 0 : _a.disabledVenues) != null ? _b : [],
1898
+ disabledCategoryPresets: (_d = (_c = query.data) == null ? void 0 : _c.disabledCategoryPresets) != null ? _d : [],
1899
+ earlyAccessEnabled: (_f = (_e = query.data) == null ? void 0 : _e.earlyAccessEnabled) != null ? _f : false,
1900
+ isLoading: query.isLoading,
1901
+ error: query.error
1902
+ };
1903
+ }
1904
+ export {
1905
+ AUTH_CHOOSER_OPEN_EVENT,
1906
+ AggBalanceProvider,
1907
+ AggProvider,
1908
+ AggProvider as AggSdkProvider,
1909
+ AggUiProvider,
1910
+ CHART_TIME_RANGES,
1911
+ CONFIRMED_MATCH_STATUSES,
1912
+ DEFAULT_AGG_ROOT_CLASS_NAME,
1913
+ EventListStateProvider,
1914
+ MarketStatus,
1915
+ MatchStatus,
1916
+ MatchType,
1917
+ QueryClient4 as QueryClient,
1918
+ QueryClientProvider,
1919
+ TurnstileChallengeError,
1920
+ Venue,
1921
+ computeClosedPositionTotals,
1922
+ computePriceGaps,
1923
+ defaultAggUiConfig,
1924
+ defaultAggUiConfig as defaultSdkUiConfig,
1925
+ executionKeys,
1926
+ findLivePriceById,
1927
+ getBuilder,
1928
+ getDepositAddress,
1929
+ getOrCreateBuilder,
1930
+ getWalletAddressFromUserProfile,
1931
+ invalidateBalanceQueries,
1932
+ invalidatePositionQueries,
1933
+ optimizedImageUrl,
1934
+ parseEmail,
1935
+ parseEmailStrict,
1936
+ requestAggAuthChooserOpen,
1937
+ resolveAggUiLabels,
1938
+ resolveDefaultMarket as resolveDefaultTradingMarket,
1939
+ resolveEventTradingState,
1940
+ resolveMarketTradingState,
1941
+ resolveMarketWinningOutcome,
1942
+ resolveOrderEligibility,
1943
+ resolveTradingStateKind,
1944
+ sortVenues,
1945
+ timeRangeToInterval,
1946
+ tradingReducer,
1947
+ useAggAuth,
1948
+ useAggAuthContext,
1949
+ useAggAuthState,
1950
+ useAggBalance,
1951
+ useAggBalanceContext,
1952
+ useAggBalanceState,
1953
+ useAggClient,
1954
+ useAggLabels,
1955
+ useAggUiConfig,
1956
+ useAggWebSocket,
1957
+ useAppConfig,
1958
+ useCategories,
1959
+ useDebouncedValue,
1960
+ useDepositAddresses,
1961
+ useEnrichedVenueEvent,
1962
+ useEventListState,
1963
+ useEventOrderbookData,
1964
+ useEventTradingContext,
1965
+ useExecuteManaged,
1966
+ useExecutionOrders,
1967
+ useExecutionPositions,
1968
+ useExecutionProgress,
1969
+ useExternalId,
1970
+ useGeoBlock,
1971
+ useLabels,
1972
+ useLinkAccount,
1973
+ useLiveCandleOverlay,
1974
+ useLiveCandles,
1975
+ useLiveMarket,
1976
+ useLiveMarketStores,
1977
+ useLiveOutcomePrices,
1978
+ useLiveTrades,
1979
+ useManagedBalances,
1980
+ useMarketChart,
1981
+ useMarketOrderbook,
1982
+ useMidpoints,
1983
+ useOnBalanceUpdate,
1984
+ useOnOrderSubmitted,
1985
+ useOnRedeemEvent,
1986
+ useOrderBook,
1987
+ useOrderbookQuote,
1988
+ useOrders,
1989
+ usePositions,
1990
+ useQueryClient2 as useQueryClient,
1991
+ useQuoteManaged,
1992
+ useRampQuotes,
1993
+ useRampSession,
1994
+ useRedeem,
1995
+ useRedeemEligibleCount,
1996
+ useSdkLabels,
1997
+ useSdkUiConfig,
1998
+ useSearch,
1999
+ useSmartRoute,
2000
+ useSyncBalances,
2001
+ useUserActivity,
2002
+ useUserHoldings,
2003
+ useVenueEvent,
2004
+ useVenueEvents,
2005
+ useVenueMarketMidpoints,
2006
+ useVenueMarkets,
2007
+ useViewportMidpoints,
2008
+ useVisibleIds,
2009
+ useWithdrawManaged
2010
+ };