@liberfi.io/react-predict 0.3.66 → 0.3.68

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,7 +1,7 @@
1
1
  import { httpGet, httpPost, httpDelete } from '@liberfi.io/utils';
2
2
  import { createContext, useMemo, useState, useRef, useCallback, useContext, useEffect } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
- import { useQuery, useInfiniteQuery, useQueries, useMutation, useQueryClient } from '@tanstack/react-query';
4
+ import { useQuery, useInfiniteQuery, useQueryClient, useQueries, useMutation } from '@tanstack/react-query';
5
5
  import { OrderBuilder, SignatureTypeV2, Side, OrderType, orderToJsonV2, ClobClient } from '@polymarket/clob-client-v2';
6
6
 
7
7
  // src/client/client.ts
@@ -82,6 +82,67 @@ var PredictClient = class {
82
82
  const url = `${this.endpoint}/api/v1/events/${encodeURIComponent(slug)}/similar${query}`;
83
83
  return await httpGet(url);
84
84
  }
85
+ // -------------------------------------------------------------------------
86
+ // Sports / esports
87
+ // -------------------------------------------------------------------------
88
+ /** Maps to `GET /api/v1/sports/taxonomy`. */
89
+ async getSportsTaxonomy(params) {
90
+ const query = buildQuery(params ?? {});
91
+ const url = `${this.endpoint}/api/v1/sports/taxonomy${query}`;
92
+ return await httpGet(url, this.requestOptions());
93
+ }
94
+ /** Maps to `GET /api/v1/sports/matches`. */
95
+ async getSportsMatches(params) {
96
+ const query = buildQuery(params ?? {});
97
+ const url = `${this.endpoint}/api/v1/sports/matches${query}`;
98
+ return await httpGet(url, this.requestOptions());
99
+ }
100
+ /** Maps to `GET /api/v1/sports/props`. */
101
+ async getSportsProps(params) {
102
+ const query = buildQuery(params ?? {});
103
+ const url = `${this.endpoint}/api/v1/sports/props${query}`;
104
+ return await httpGet(url, this.requestOptions());
105
+ }
106
+ /** Maps to `GET /api/v1/esports/taxonomy`. */
107
+ async getEsportsTaxonomy(params) {
108
+ const query = buildQuery(params ?? {});
109
+ const url = `${this.endpoint}/api/v1/esports/taxonomy${query}`;
110
+ return await httpGet(url, this.requestOptions());
111
+ }
112
+ /** Maps to `GET /api/v1/esports/matches`. */
113
+ async getEsportsMatches(params) {
114
+ const query = buildQuery(params ?? {});
115
+ const url = `${this.endpoint}/api/v1/esports/matches${query}`;
116
+ return await httpGet(url, this.requestOptions());
117
+ }
118
+ /** Maps to `GET /api/v1/esports/props`. */
119
+ async getEsportsProps(params) {
120
+ const query = buildQuery(params ?? {});
121
+ const url = `${this.endpoint}/api/v1/esports/props${query}`;
122
+ return await httpGet(url, this.requestOptions());
123
+ }
124
+ /** Maps to `GET /api/v1/sports/routing/:slug`. */
125
+ async getSportsRouting(slug, params) {
126
+ const query = buildQuery(params ?? {});
127
+ const url = `${this.endpoint}/api/v1/sports/routing/${encodeURIComponent(slug)}${query}`;
128
+ return await httpGet(url, this.requestOptions());
129
+ }
130
+ /** Maps to `GET /api/v1/sports/matches/:match_group_slug`. */
131
+ async getSportsMatchDetail(section, matchGroupSlug, params) {
132
+ const query = buildQuery(params ?? {});
133
+ const url = `${this.endpoint}/api/v1/${encodeURIComponent(section)}/matches/${encodeURIComponent(matchGroupSlug)}${query}`;
134
+ return await httpGet(url, this.requestOptions());
135
+ }
136
+ /** Convenience wrapper for `GET /api/v1/esports/matches/:match_group_slug`. */
137
+ async getEsportsMatchDetail(matchGroupSlug, params) {
138
+ return this.getSportsMatchDetail("esports", matchGroupSlug, params);
139
+ }
140
+ /** Maps to `GET /api/v1/search`. */
141
+ async search(params) {
142
+ const query = buildQuery(params ?? {});
143
+ const url = `${this.endpoint}/api/v1/search${query}`;
144
+ return await httpGet(url, this.requestOptions());
145
+ }
85
146
  /**
86
147
  * List comments for a prediction event.
87
148
  *
@@ -143,8 +204,9 @@ var PredictClient = class {
143
204
  return await httpGet(url);
144
205
  }
145
206
  /** Maps to `GET /api/v1/markets/:slug/price-history?source=...&range=...`. */
146
- async getPriceHistory(slug, source, range) {
147
- const query = buildQuery({ source, range });
207
+ async getPriceHistory(slug, sourceOrParams, range) {
208
+ const params = typeof sourceOrParams === "string" ? { source: sourceOrParams, range } : sourceOrParams;
209
+ const query = buildQuery(params);
148
210
  const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/price-history${query}`;
149
211
  return await httpGet(url);
150
212
  }
@@ -1219,6 +1281,355 @@ function useEvent(params, queryOptions = {}) {
1219
1281
  ...queryOptions
1220
1282
  });
1221
1283
  }
1284
+
1285
+ // src/hooks/predict/search.params.ts
1286
+ function predictSearchQueryKey(params) {
1287
+ return ["predict", "search-documents", params];
1288
+ }
1289
+ function resolvePredictSearchParams(params = {}) {
1290
+ const q = params.q ?? "";
1291
+ return {
1292
+ ...params,
1293
+ q,
1294
+ sort_by: params.sort_by ?? (q ? "relevance" : "volume"),
1295
+ sort_asc: params.sort_asc ?? (q ? void 0 : false)
1296
+ };
1297
+ }
1298
+ async function fetchPredictSearch(client, params) {
1299
+ return client.search(resolvePredictSearchParams(params));
1300
+ }
1301
+
1302
+ // src/hooks/predict/usePredictSearch.ts
1303
+ function usePredictSearch(params = {}, queryOptions) {
1304
+ const client = usePredictClient();
1305
+ const resolved = resolvePredictSearchParams(params);
1306
+ return useQuery({
1307
+ queryKey: predictSearchQueryKey(resolved),
1308
+ queryFn: () => fetchPredictSearch(client, resolved),
1309
+ enabled: queryOptions?.enabled ?? true
1310
+ });
1311
+ }
1312
+ function useInfinitePredictSearch(params = {}, queryOptions) {
1313
+ const client = usePredictClient();
1314
+ const resolved = resolvePredictSearchParams(params);
1315
+ return useInfiniteQuery({
1316
+ queryKey: predictSearchQueryKey(resolved),
1317
+ queryFn: ({ pageParam }) => fetchPredictSearch(client, {
1318
+ ...resolved,
1319
+ ...pageParam !== void 0 ? { cursor: pageParam } : {}
1320
+ }),
1321
+ initialPageParam: void 0,
1322
+ getNextPageParam: (lastPage) => lastPage.has_more && lastPage.next_cursor ? lastPage.next_cursor : void 0,
1323
+ enabled: queryOptions?.enabled ?? true
1324
+ });
1325
+ }
1326
+
1327
+ // src/hooks/predict/sports.params.ts
1328
+ function sportsTaxonomyQueryKey(params) {
1329
+ return ["predict", "sports", "taxonomy", params];
1330
+ }
1331
+ function sportsMatchesQueryKey(params) {
1332
+ return ["predict", "sports", "matches", params];
1333
+ }
1334
+ function sportsPropsQueryKey(params) {
1335
+ return ["predict", "sports", "props", params];
1336
+ }
1337
+ function resolveSportsTaxonomyParams(params = {}) {
1338
+ return { ...params, section: "sports" };
1339
+ }
1340
+ function resolveSportsMatchesParams(params = {}) {
1341
+ return params;
1342
+ }
1343
+ function resolveSportsPropsParams(params = {}) {
1344
+ return params;
1345
+ }
1346
+ async function fetchSportsTaxonomy(client, params) {
1347
+ return client.getSportsTaxonomy(resolveSportsTaxonomyParams(params));
1348
+ }
1349
+ async function fetchSportsMatches(client, params) {
1350
+ return client.getSportsMatches(resolveSportsMatchesParams(params));
1351
+ }
1352
+ async function fetchSportsProps(client, params) {
1353
+ return client.getSportsProps(resolveSportsPropsParams(params));
1354
+ }
1355
+
1356
+ // src/hooks/predict/useSportsTaxonomy.ts
1357
+ function useSportsTaxonomy(params = {}, queryOptions = {}) {
1358
+ const client = usePredictClient();
1359
+ const resolved = resolveSportsTaxonomyParams(params);
1360
+ return useQuery({
1361
+ queryKey: sportsTaxonomyQueryKey(resolved),
1362
+ queryFn: () => fetchSportsTaxonomy(client, resolved),
1363
+ ...queryOptions
1364
+ });
1365
+ }
1366
+ function useSportsMatches(params = {}, queryOptions) {
1367
+ const client = usePredictClient();
1368
+ const resolved = resolveSportsMatchesParams(params);
1369
+ return useInfiniteQuery({
1370
+ queryKey: sportsMatchesQueryKey(resolved),
1371
+ queryFn: ({ pageParam }) => fetchSportsMatches(client, {
1372
+ ...resolved,
1373
+ ...pageParam !== void 0 ? { cursor: pageParam } : {}
1374
+ }),
1375
+ initialPageParam: void 0,
1376
+ getNextPageParam: (lastPage) => lastPage.has_more && lastPage.next_cursor ? lastPage.next_cursor : void 0,
1377
+ enabled: queryOptions?.enabled ?? true
1378
+ });
1379
+ }
1380
+ function useSportsProps(params = {}, queryOptions) {
1381
+ const client = usePredictClient();
1382
+ const resolved = resolveSportsPropsParams(params);
1383
+ return useInfiniteQuery({
1384
+ queryKey: sportsPropsQueryKey(resolved),
1385
+ queryFn: ({ pageParam }) => fetchSportsProps(client, {
1386
+ ...resolved,
1387
+ ...pageParam !== void 0 ? { cursor: pageParam } : {}
1388
+ }),
1389
+ initialPageParam: void 0,
1390
+ getNextPageParam: (lastPage) => lastPage.has_more && lastPage.next_cursor ? lastPage.next_cursor : void 0,
1391
+ enabled: queryOptions?.enabled ?? true
1392
+ });
1393
+ }
1394
+
1395
+ // src/hooks/predict/esports.params.ts
1396
+ function esportsTaxonomyQueryKey(params) {
1397
+ return ["predict", "esports", "taxonomy", params];
1398
+ }
1399
+ function esportsMatchesQueryKey(params) {
1400
+ return ["predict", "esports", "matches", params];
1401
+ }
1402
+ function esportsPropsQueryKey(params) {
1403
+ return ["predict", "esports", "props", params];
1404
+ }
1405
+ function resolveEsportsTaxonomyParams(params = {}) {
1406
+ return params;
1407
+ }
1408
+ function resolveEsportsMatchesParams(params = {}) {
1409
+ return params;
1410
+ }
1411
+ function resolveEsportsPropsParams(params = {}) {
1412
+ return params;
1413
+ }
1414
+ async function fetchEsportsTaxonomy(client, params) {
1415
+ return client.getEsportsTaxonomy(resolveEsportsTaxonomyParams(params));
1416
+ }
1417
+ async function fetchEsportsMatches(client, params) {
1418
+ return client.getEsportsMatches(resolveEsportsMatchesParams(params));
1419
+ }
1420
+ async function fetchEsportsProps(client, params) {
1421
+ return client.getEsportsProps(resolveEsportsPropsParams(params));
1422
+ }
1423
+
1424
+ // src/hooks/predict/useEsportsTaxonomy.ts
1425
+ function useEsportsTaxonomy(params = {}, queryOptions = {}) {
1426
+ const client = usePredictClient();
1427
+ const resolved = resolveEsportsTaxonomyParams(params);
1428
+ return useQuery({
1429
+ queryKey: esportsTaxonomyQueryKey(resolved),
1430
+ queryFn: () => fetchEsportsTaxonomy(client, resolved),
1431
+ ...queryOptions
1432
+ });
1433
+ }
1434
+ function useEsportsMatches(params = {}, queryOptions) {
1435
+ const client = usePredictClient();
1436
+ const resolved = resolveEsportsMatchesParams(params);
1437
+ return useInfiniteQuery({
1438
+ queryKey: esportsMatchesQueryKey(resolved),
1439
+ queryFn: ({ pageParam }) => fetchEsportsMatches(client, {
1440
+ ...resolved,
1441
+ ...pageParam !== void 0 ? { cursor: pageParam } : {}
1442
+ }),
1443
+ initialPageParam: void 0,
1444
+ getNextPageParam: (lastPage) => lastPage.has_more && lastPage.next_cursor ? lastPage.next_cursor : void 0,
1445
+ enabled: queryOptions?.enabled ?? true
1446
+ });
1447
+ }
1448
+ function useEsportsProps(params = {}, queryOptions) {
1449
+ const client = usePredictClient();
1450
+ const resolved = resolveEsportsPropsParams(params);
1451
+ return useInfiniteQuery({
1452
+ queryKey: esportsPropsQueryKey(resolved),
1453
+ queryFn: ({ pageParam }) => fetchEsportsProps(client, {
1454
+ ...resolved,
1455
+ ...pageParam !== void 0 ? { cursor: pageParam } : {}
1456
+ }),
1457
+ initialPageParam: void 0,
1458
+ getNextPageParam: (lastPage) => lastPage.has_more && lastPage.next_cursor ? lastPage.next_cursor : void 0,
1459
+ enabled: queryOptions?.enabled ?? true
1460
+ });
1461
+ }
1462
+
1463
+ // src/hooks/predict/sports-routing.params.ts
1464
+ function sportsRoutingQueryKey(slug, params) {
1465
+ return ["predict", "sports", "routing", slug, params];
1466
+ }
1467
+ function resolveSportsRoutingParams(params = {}) {
1468
+ return params;
1469
+ }
1470
+ async function fetchSportsRouting(client, slug, params) {
1471
+ return client.getSportsRouting(slug, resolveSportsRoutingParams(params));
1472
+ }
1473
+
1474
+ // src/hooks/predict/useSportsRouting.ts
1475
+ function useSportsRouting(slug, params = {}, queryOptions = {}) {
1476
+ const client = usePredictClient();
1477
+ const resolved = resolveSportsRoutingParams(params);
1478
+ return useQuery({
1479
+ queryKey: sportsRoutingQueryKey(slug, resolved),
1480
+ queryFn: () => fetchSportsRouting(client, slug, resolved),
1481
+ enabled: Boolean(slug),
1482
+ ...queryOptions
1483
+ });
1484
+ }
1485
+
1486
+ // src/hooks/predict/sports-match-detail.params.ts
1487
+ function sportsMatchDetailQueryKey(section, matchGroupSlug, params) {
1488
+ return ["predict", section, "match-detail", matchGroupSlug, params];
1489
+ }
1490
+ function resolveSportsMatchDetailParams(params = {}) {
1491
+ return params;
1492
+ }
1493
+ async function fetchSportsMatchDetail(client, section, matchGroupSlug, params) {
1494
+ return client.getSportsMatchDetail(
1495
+ section,
1496
+ matchGroupSlug,
1497
+ resolveSportsMatchDetailParams(params)
1498
+ );
1499
+ }
1500
+
1501
+ // src/hooks/predict/useSportsMatchDetail.ts
1502
+ function useSportsMatchDetail(section, matchGroupSlug, params = {}, queryOptions = {}) {
1503
+ const client = usePredictClient();
1504
+ const resolved = resolveSportsMatchDetailParams(params);
1505
+ return useQuery({
1506
+ queryKey: sportsMatchDetailQueryKey(section, matchGroupSlug, resolved),
1507
+ queryFn: () => fetchSportsMatchDetail(client, section, matchGroupSlug, resolved),
1508
+ enabled: Boolean(section && matchGroupSlug),
1509
+ ...queryOptions
1510
+ });
1511
+ }
1512
+ function orderbookQueryKey(slug, source, outcome = "yes") {
1513
+ return ["predict", "orderbook", slug, source, outcome];
1514
+ }
1515
+ function useOrderbook(params, queryOptions = {}) {
1516
+ const client = usePredictClient();
1517
+ const outcome = params.outcome ?? "yes";
1518
+ return useQuery({
1519
+ queryKey: orderbookQueryKey(params.slug, params.source, outcome),
1520
+ queryFn: () => client.getOrderbook(params.slug, params.source, outcome),
1521
+ enabled: Boolean(params.slug),
1522
+ refetchInterval: 3e4,
1523
+ ...queryOptions
1524
+ });
1525
+ }
1526
+ function useOrderbookSubscription({
1527
+ wsClient,
1528
+ slug,
1529
+ enabled = true,
1530
+ outcome,
1531
+ onUpdate
1532
+ }) {
1533
+ const [orderbook, setOrderbook] = useState(null);
1534
+ const [isSubscribed, setIsSubscribed] = useState(false);
1535
+ const onUpdateRef = useRef(onUpdate);
1536
+ onUpdateRef.current = onUpdate;
1537
+ const handleUpdate = useCallback(
1538
+ (msg) => {
1539
+ if (msg.data.market_slug === slug) {
1540
+ if (!outcome || msg.data.outcome === outcome) {
1541
+ setOrderbook(msg.data);
1542
+ }
1543
+ onUpdateRef.current?.(msg);
1544
+ }
1545
+ },
1546
+ [slug, outcome]
1547
+ );
1548
+ useEffect(() => {
1549
+ if (!wsClient || !enabled || !slug) {
1550
+ setIsSubscribed(false);
1551
+ return;
1552
+ }
1553
+ setOrderbook(null);
1554
+ const unsub = wsClient.subscribeOrderbook([slug], handleUpdate);
1555
+ setIsSubscribed(true);
1556
+ return () => {
1557
+ unsub();
1558
+ setIsSubscribed(false);
1559
+ };
1560
+ }, [wsClient, enabled, slug, handleUpdate]);
1561
+ return { orderbook, isSubscribed };
1562
+ }
1563
+ function usePredictWsClient() {
1564
+ const context = useContext(PredictContext);
1565
+ if (!context) {
1566
+ throw new Error("usePredictWsClient must be used within a PredictProvider");
1567
+ }
1568
+ const { wsClient } = context;
1569
+ const [wsStatus, setWsStatus] = useState(
1570
+ wsClient?.getStatus() ?? "disconnected"
1571
+ );
1572
+ useEffect(() => {
1573
+ if (!wsClient) {
1574
+ setWsStatus("disconnected");
1575
+ return;
1576
+ }
1577
+ setWsStatus(wsClient.getStatus());
1578
+ return wsClient.onStatusChange(setWsStatus);
1579
+ }, [wsClient]);
1580
+ return {
1581
+ wsClient,
1582
+ wsStatus,
1583
+ isWsConnected: wsStatus === "connected"
1584
+ };
1585
+ }
1586
+
1587
+ // src/hooks/predict/useRealtimeOrderbook.ts
1588
+ var REST_POLL_INTERVAL = 5e3;
1589
+ function useRealtimeOrderbook(params, queryOptions = {}) {
1590
+ const { wsClient } = usePredictWsClient();
1591
+ const queryClient = useQueryClient();
1592
+ const outcome = params.outcome ?? "yes";
1593
+ const handleUpdate = useCallback(
1594
+ (msg) => {
1595
+ if (msg.data.market_slug !== params.slug) return;
1596
+ if (msg.data.outcome !== "yes" && msg.data.outcome !== "no") return;
1597
+ const ob = {
1598
+ market_id: msg.data.market_slug,
1599
+ outcome: msg.data.outcome,
1600
+ bids: msg.data.bids,
1601
+ asks: msg.data.asks,
1602
+ spread: msg.data.spread
1603
+ };
1604
+ queryClient.setQueryData(
1605
+ orderbookQueryKey(params.slug, params.source, msg.data.outcome),
1606
+ ob
1607
+ );
1608
+ },
1609
+ [params.slug, params.source, queryClient]
1610
+ );
1611
+ const subParams = {
1612
+ wsClient,
1613
+ slug: params.slug,
1614
+ enabled: Boolean(params.slug),
1615
+ outcome,
1616
+ onUpdate: handleUpdate
1617
+ };
1618
+ const { isSubscribed } = useOrderbookSubscription(subParams);
1619
+ return useOrderbook(params, {
1620
+ refetchInterval: isSubscribed ? false : REST_POLL_INTERVAL,
1621
+ ...queryOptions
1622
+ });
1623
+ }
1624
+
1625
+ // src/hooks/predict/useSportsOrderbook.ts
1626
+ function useSportsOrderbook(key) {
1627
+ return useRealtimeOrderbook({
1628
+ slug: key.market_slug,
1629
+ source: key.source,
1630
+ outcome: key.outcome
1631
+ });
1632
+ }
1222
1633
  function useInfiniteEvents(params, queryOptions = {}) {
1223
1634
  const client = usePredictClient();
1224
1635
  return useInfiniteQuery({
@@ -1317,8 +1728,8 @@ function useMarket(params, queryOptions = {}) {
1317
1728
  ...queryOptions
1318
1729
  });
1319
1730
  }
1320
- function priceHistoryQueryKey(slug, source, range) {
1321
- return ["predict", "price-history", slug, source, range];
1731
+ function priceHistoryQueryKey(slug, source, rangeOrParams) {
1732
+ return ["predict", "price-history", slug, source, rangeOrParams];
1322
1733
  }
1323
1734
  function usePriceHistory(params, queryOptions = {}) {
1324
1735
  const client = usePredictClient();
@@ -1333,73 +1744,147 @@ function usePriceHistory(params, queryOptions = {}) {
1333
1744
 
1334
1745
  // src/hooks/predict/useMarketHistory.ts
1335
1746
  var ChartRange = {
1747
+ ONE_HOUR: "1h",
1748
+ SIX_HOURS: "6h",
1336
1749
  ONE_DAY: "1d",
1337
- ONE_WEEK: "1w",
1338
1750
  ONE_MONTH: "1m",
1339
1751
  ALL: "all"
1340
1752
  };
1341
1753
  var RANGE_MAP = {
1754
+ [ChartRange.ONE_HOUR]: "1h",
1755
+ [ChartRange.SIX_HOURS]: "6h",
1342
1756
  [ChartRange.ONE_DAY]: "1d",
1343
- [ChartRange.ONE_WEEK]: "1w",
1344
1757
  [ChartRange.ONE_MONTH]: "1m",
1345
1758
  [ChartRange.ALL]: "all"
1346
1759
  };
1347
- function useMarketHistory(markets, range = ChartRange.ALL) {
1760
+ var RANGE_DURATION_SECONDS = {
1761
+ [ChartRange.ONE_HOUR]: 60 * 60,
1762
+ [ChartRange.SIX_HOURS]: 6 * 60 * 60,
1763
+ [ChartRange.ONE_DAY]: 24 * 60 * 60,
1764
+ [ChartRange.ONE_MONTH]: 30 * 24 * 60 * 60,
1765
+ [ChartRange.ALL]: null
1766
+ };
1767
+ var RANGE_FIDELITY_MINUTES = {
1768
+ [ChartRange.ONE_HOUR]: 1,
1769
+ [ChartRange.SIX_HOURS]: 1,
1770
+ [ChartRange.ONE_DAY]: 5,
1771
+ [ChartRange.ONE_MONTH]: 15,
1772
+ [ChartRange.ALL]: 15
1773
+ };
1774
+ var LONG_RANGE_FIDELITY_MINUTES = {
1775
+ SHORT: 15,
1776
+ MONTH: 4 * 60,
1777
+ LONG: 24 * 60
1778
+ };
1779
+ var LONG_RANGE_SPAN_SECONDS = {
1780
+ WEEK: 7 * 24 * 60 * 60,
1781
+ MONTH: 31 * 24 * 60 * 60
1782
+ };
1783
+ function unixSecondsFromIso(value) {
1784
+ if (!value) return void 0;
1785
+ const ms = Date.parse(value);
1786
+ return Number.isFinite(ms) ? Math.floor(ms / 1e3) : void 0;
1787
+ }
1788
+ function firstFinitePrice(market) {
1789
+ const yesOutcome = market.outcomes?.find((o) => o.label.toLowerCase() === "yes") ?? market.outcomes?.[0];
1790
+ const price = yesOutcome?.best_ask ?? yesOutcome?.best_bid ?? yesOutcome?.price;
1791
+ return price != null && Number.isFinite(price) ? price : 0.5;
1792
+ }
1793
+ function fidelityMinutesForRange(range, startTs, endTs) {
1794
+ if (range !== ChartRange.ONE_MONTH && range !== ChartRange.ALL) {
1795
+ return RANGE_FIDELITY_MINUTES[range];
1796
+ }
1797
+ const spanSeconds = startTs != null ? Math.max(0, endTs - startTs) : 0;
1798
+ if (spanSeconds <= LONG_RANGE_SPAN_SECONDS.WEEK) {
1799
+ return LONG_RANGE_FIDELITY_MINUTES.SHORT;
1800
+ }
1801
+ if (spanSeconds <= LONG_RANGE_SPAN_SECONDS.MONTH) {
1802
+ return LONG_RANGE_FIDELITY_MINUTES.MONTH;
1803
+ }
1804
+ return LONG_RANGE_FIDELITY_MINUTES.LONG;
1805
+ }
1806
+ function buildRangeParams(range, market, anchoredEndTs) {
1807
+ const endTs = anchoredEndTs;
1808
+ const duration = RANGE_DURATION_SECONDS[range];
1809
+ const createdAt = unixSecondsFromIso(market.created_at);
1810
+ const rangeStartTs = duration == null ? void 0 : Math.max(0, endTs - duration);
1811
+ const startTs = createdAt != null && rangeStartTs != null ? Math.max(createdAt, rangeStartTs) : createdAt ?? rangeStartTs;
1812
+ return {
1813
+ range: RANGE_MAP[range],
1814
+ startTs,
1815
+ endTs,
1816
+ fidelity: fidelityMinutesForRange(range, startTs, endTs)
1817
+ };
1818
+ }
1819
+ function normalizeHistoryPoints(points, params, fallbackPrice) {
1820
+ const startMs = params.startTs != null ? params.startTs * 1e3 : void 0;
1821
+ const endMs = params.endTs != null ? params.endTs * 1e3 : void 0;
1822
+ const sorted = points.filter((pt) => Number.isFinite(pt.t) && Number.isFinite(pt.p)).map((pt) => ({ timestamp: pt.t * 1e3, price: pt.p })).filter((pt) => {
1823
+ if (startMs != null && pt.timestamp < startMs) return false;
1824
+ if (endMs != null && pt.timestamp > endMs) return false;
1825
+ return true;
1826
+ }).sort((a, b) => a.timestamp - b.timestamp);
1827
+ if (sorted.length === 0) {
1828
+ const now = endMs ?? Date.now();
1829
+ const start = startMs ?? now - 7 * 864e5;
1830
+ return [
1831
+ { timestamp: start, price: fallbackPrice },
1832
+ { timestamp: now, price: fallbackPrice }
1833
+ ];
1834
+ }
1835
+ const result = [...sorted];
1836
+ if (endMs != null && result[result.length - 1].timestamp < endMs) {
1837
+ result.push({
1838
+ timestamp: endMs,
1839
+ price: result[result.length - 1].price
1840
+ });
1841
+ }
1842
+ return result;
1843
+ }
1844
+ function useMarketHistory(markets, range = ChartRange.ALL, options = {}) {
1348
1845
  const client = usePredictClient();
1349
- const apiRange = RANGE_MAP[range];
1846
+ const rangeAnchorRef = useRef(null);
1847
+ const requestedEndTs = options.endTs;
1848
+ if (rangeAnchorRef.current?.range !== range || requestedEndTs != null && rangeAnchorRef.current?.endTs !== requestedEndTs) {
1849
+ rangeAnchorRef.current = {
1850
+ range,
1851
+ endTs: requestedEndTs ?? Math.floor(Date.now() / 1e3)
1852
+ };
1853
+ }
1854
+ const anchoredEndTs = rangeAnchorRef.current.endTs;
1855
+ const marketParams = useMemo(
1856
+ () => markets.map((market) => ({
1857
+ market,
1858
+ params: buildRangeParams(range, market, anchoredEndTs)
1859
+ })),
1860
+ [markets, range, anchoredEndTs]
1861
+ );
1350
1862
  const queries = useQueries({
1351
- queries: markets.map((market) => ({
1352
- queryKey: priceHistoryQueryKey(market.slug, market.source, apiRange),
1353
- queryFn: () => client.getPriceHistory(market.slug, market.source, apiRange),
1863
+ queries: marketParams.map(({ market, params }) => ({
1864
+ queryKey: priceHistoryQueryKey(market.slug, market.source, params),
1865
+ queryFn: () => client.getPriceHistory(market.slug, {
1866
+ source: market.source,
1867
+ ...params
1868
+ }),
1354
1869
  staleTime: 6e4,
1355
1870
  enabled: Boolean(market.slug)
1356
1871
  }))
1357
1872
  });
1358
1873
  const isLoading = queries.some((q) => q.isLoading);
1359
1874
  const series = useMemo(() => {
1360
- return markets.map((market, idx) => {
1875
+ return marketParams.map(({ market, params }, idx) => {
1361
1876
  const result = queries[idx];
1362
1877
  const points = result?.data?.points ?? [];
1363
- if (points.length > 0) {
1364
- return {
1365
- marketSlug: market.slug,
1366
- label: market.outcomes?.[0]?.label ?? market.question,
1367
- data: points.map((pt) => ({
1368
- timestamp: pt.t * 1e3,
1369
- price: pt.p
1370
- }))
1371
- };
1372
- }
1373
- const yesOutcome = market.outcomes?.find((o) => o.label.toLowerCase() === "yes") ?? market.outcomes?.[0];
1374
- const currentPrice = yesOutcome?.price ?? 0.5;
1375
- const now = Date.now();
1376
- const dayMs = 864e5;
1878
+ const fallbackPrice = firstFinitePrice(market);
1377
1879
  return {
1378
1880
  marketSlug: market.slug,
1379
1881
  label: market.outcomes?.[0]?.label ?? market.question,
1380
- data: [
1381
- { timestamp: now - 7 * dayMs, price: currentPrice },
1382
- { timestamp: now, price: currentPrice }
1383
- ]
1882
+ data: normalizeHistoryPoints(points, params, fallbackPrice)
1384
1883
  };
1385
1884
  });
1386
- }, [markets, queries]);
1885
+ }, [marketParams, queries]);
1387
1886
  return { series, isLoading };
1388
1887
  }
1389
- function orderbookQueryKey(slug, source, outcome = "yes") {
1390
- return ["predict", "orderbook", slug, source, outcome];
1391
- }
1392
- function useOrderbook(params, queryOptions = {}) {
1393
- const client = usePredictClient();
1394
- const outcome = params.outcome ?? "yes";
1395
- return useQuery({
1396
- queryKey: orderbookQueryKey(params.slug, params.source, outcome),
1397
- queryFn: () => client.getOrderbook(params.slug, params.source, outcome),
1398
- enabled: Boolean(params.slug),
1399
- refetchInterval: 3e4,
1400
- ...queryOptions
1401
- });
1402
- }
1403
1888
  function marketTradesQueryKey(slug, params) {
1404
1889
  return ["predict", "market-trades", slug, params];
1405
1890
  }
@@ -2593,29 +3078,6 @@ function useRebateConfig(queryOptions = {}) {
2593
3078
  ...queryOptions
2594
3079
  });
2595
3080
  }
2596
- function usePredictWsClient() {
2597
- const context = useContext(PredictContext);
2598
- if (!context) {
2599
- throw new Error("usePredictWsClient must be used within a PredictProvider");
2600
- }
2601
- const { wsClient } = context;
2602
- const [wsStatus, setWsStatus] = useState(
2603
- wsClient?.getStatus() ?? "disconnected"
2604
- );
2605
- useEffect(() => {
2606
- if (!wsClient) {
2607
- setWsStatus("disconnected");
2608
- return;
2609
- }
2610
- setWsStatus(wsClient.getStatus());
2611
- return wsClient.onStatusChange(setWsStatus);
2612
- }, [wsClient]);
2613
- return {
2614
- wsClient,
2615
- wsStatus,
2616
- isWsConnected: wsStatus === "connected"
2617
- };
2618
- }
2619
3081
  function usePricesSubscription({
2620
3082
  wsClient,
2621
3083
  slugs,
@@ -2651,43 +3113,6 @@ function usePricesSubscription({
2651
3113
  }, [wsClient, enabled, slugsKey, handleUpdate]);
2652
3114
  return { prices, isSubscribed };
2653
3115
  }
2654
- function useOrderbookSubscription({
2655
- wsClient,
2656
- slug,
2657
- enabled = true,
2658
- outcome,
2659
- onUpdate
2660
- }) {
2661
- const [orderbook, setOrderbook] = useState(null);
2662
- const [isSubscribed, setIsSubscribed] = useState(false);
2663
- const onUpdateRef = useRef(onUpdate);
2664
- onUpdateRef.current = onUpdate;
2665
- const handleUpdate = useCallback(
2666
- (msg) => {
2667
- if (msg.data.market_slug === slug) {
2668
- if (!outcome || msg.data.outcome === outcome) {
2669
- setOrderbook(msg.data);
2670
- }
2671
- onUpdateRef.current?.(msg);
2672
- }
2673
- },
2674
- [slug, outcome]
2675
- );
2676
- useEffect(() => {
2677
- if (!wsClient || !enabled || !slug) {
2678
- setIsSubscribed(false);
2679
- return;
2680
- }
2681
- setOrderbook(null);
2682
- const unsub = wsClient.subscribeOrderbook([slug], handleUpdate);
2683
- setIsSubscribed(true);
2684
- return () => {
2685
- unsub();
2686
- setIsSubscribed(false);
2687
- };
2688
- }, [wsClient, enabled, slug, handleUpdate]);
2689
- return { orderbook, isSubscribed };
2690
- }
2691
3116
  var DEFAULT_MAX_HISTORY = 100;
2692
3117
  function useTradesSubscription({
2693
3118
  wsClient,
@@ -2732,42 +3157,6 @@ function useTradesSubscription({
2732
3157
  }, [wsClient, enabled, slug, handleUpdate]);
2733
3158
  return { trades, isSubscribed, clearHistory };
2734
3159
  }
2735
- var REST_POLL_INTERVAL = 5e3;
2736
- function useRealtimeOrderbook(params, queryOptions = {}) {
2737
- const { wsClient } = usePredictWsClient();
2738
- const queryClient = useQueryClient();
2739
- const outcome = params.outcome ?? "yes";
2740
- const handleUpdate = useCallback(
2741
- (msg) => {
2742
- if (msg.data.market_slug !== params.slug) return;
2743
- if (msg.data.outcome !== "yes" && msg.data.outcome !== "no") return;
2744
- const ob = {
2745
- market_id: msg.data.market_slug,
2746
- outcome: msg.data.outcome,
2747
- bids: msg.data.bids,
2748
- asks: msg.data.asks,
2749
- spread: msg.data.spread
2750
- };
2751
- queryClient.setQueryData(
2752
- orderbookQueryKey(params.slug, params.source, msg.data.outcome),
2753
- ob
2754
- );
2755
- },
2756
- [params.slug, params.source, queryClient]
2757
- );
2758
- const subParams = {
2759
- wsClient,
2760
- slug: params.slug,
2761
- enabled: Boolean(params.slug),
2762
- outcome,
2763
- onUpdate: handleUpdate
2764
- };
2765
- const { isSubscribed } = useOrderbookSubscription(subParams);
2766
- return useOrderbook(params, {
2767
- refetchInterval: isSubscribed ? false : REST_POLL_INTERVAL,
2768
- ...queryOptions
2769
- });
2770
- }
2771
3160
 
2772
3161
  // src/hooks/predict/useRealtimePrices.ts
2773
3162
  function useRealtimePrices({
@@ -3285,6 +3674,6 @@ function walkOrderbook({
3285
3674
  };
3286
3675
  }
3287
3676
 
3288
- export { CLOB_AUTH_DOMAIN, CLOB_AUTH_TYPES, CTF_EXCHANGE_ADDRESS, CTF_ORDER_TYPES, ChartRange, NEG_RISK_CTF_EXCHANGE_ADDRESS, ORDER_TYPE, POLYGON_CHAIN_ID, PolymarketContext, PolymarketProvider, PredictClient, PredictContext, PredictProvider, PredictWsClient, SIDE, USDC_ADDRESS, availableSharesQueryKey, balanceQueryKey, buildClobAuthMessage, buildClobPayload, buildCtfExchangeDomain, buildOrderMessage, buildPolymarketL2Headers, buildSignedOrder, buildSignedV2OrderPayload, candlesticksQueryKey, createPredictClient, createPredictWsClient, derivePolymarketApiKey, dflowKYCQueryKey, dflowQuoteQueryKey, eventQueryKey, eventStatsQueryKey, eventsQueryKey, feeRateQueryKey, fetchEvent, fetchEvents, fetchEventsPage, fetchMarket, fetchMatchMarketsPage, fetchMatchesPage, getPolymarketSharesPrecision, hmacSha256Base64, infiniteCommentsQueryKey, infiniteEventsQueryKey, infiniteOrdersQueryKey, infiniteTradesMultiQueryKey, infiniteTradesQueryKey, marketQueryKey, marketTradesQueryKey, matchMarketsQueryKey, matchQueryKey, matchesQueryKey, normalizePolymarketTickSize, orderQueryKey, orderbookQueryKey, ordersMultiQueryKey, ordersQueryKey, pickBestAsk, pickBestBid, polymarketDepositAddressesQueryKey, polymarketSetupQueryKey, polymarketSupportedAssetsQueryKey, polymarketWithdrawStatusQueryKey, positionValueMultiQueryKey, positionValueQueryKey, positionsMultiQueryKey, positionsQueryKey, priceHistoryQueryKey, rebateConfigQueryKey, resolveEventsParams, resolveTagSlug, similarEventsQueryKey, tickSizeQueryKey, tradesQueryKey, updatePolymarketBalanceAllowance, useAvailableShares, useBalance, useCancelOrder, useCandlesticks, useCreatePolymarketOrder, useDFlowKYC, useDFlowQuote, useDFlowSubmit, useDeployPolymarketDepositWallet, useEvent, useEventStats, useEvents, useFeeRate, useInfiniteComments, useInfiniteEvents, useInfiniteMatchMarkets, useInfiniteMatches, useInfiniteOrders, useInfiniteTrades, useInfiniteTradesMulti, useMarket, useMarketHistory, useMarketTrades, useMatch, useOrder, useOrderbook, useOrderbookSubscription, useOrders, useOrdersMulti, usePolymarket, usePolymarketDeposit, usePolymarketDepositAddresses, usePolymarketSetup, usePolymarketSupportedAssets, usePolymarketWithdraw, usePolymarketWithdrawPrepareMutation, usePolymarketWithdrawQuoteMutation, usePolymarketWithdrawRelayBuildMutation, usePolymarketWithdrawRelaySubmitMutation, usePolymarketWithdrawStatusQuery, usePositionValue, usePositionValueMulti, usePositions, usePositionsMulti, usePredictClient, usePredictWsClient, usePriceHistory, usePricesSubscription, useRealtimeOrderbook, useRealtimePrices, useRealtimeTrades, useRebateConfig, useRedeemPosition, useRunPolymarketSetup, useSearchEvents, useSimilarEvents, useTickSize, useTradeResultConfirmation, useTrades, useTradesSubscription, useWithdrawBuildMutation, useWithdrawStatusQuery, useWithdrawSubmitMutation, walkOrderbook, withdrawStatusQueryKey };
3677
+ export { CLOB_AUTH_DOMAIN, CLOB_AUTH_TYPES, CTF_EXCHANGE_ADDRESS, CTF_ORDER_TYPES, ChartRange, NEG_RISK_CTF_EXCHANGE_ADDRESS, ORDER_TYPE, POLYGON_CHAIN_ID, PolymarketContext, PolymarketProvider, PredictClient, PredictContext, PredictProvider, PredictWsClient, SIDE, USDC_ADDRESS, availableSharesQueryKey, balanceQueryKey, buildClobAuthMessage, buildClobPayload, buildCtfExchangeDomain, buildOrderMessage, buildPolymarketL2Headers, buildSignedOrder, buildSignedV2OrderPayload, candlesticksQueryKey, createPredictClient, createPredictWsClient, derivePolymarketApiKey, dflowKYCQueryKey, dflowQuoteQueryKey, esportsMatchesQueryKey, esportsPropsQueryKey, esportsTaxonomyQueryKey, eventQueryKey, eventStatsQueryKey, eventsQueryKey, feeRateQueryKey, fetchEsportsMatches, fetchEsportsProps, fetchEsportsTaxonomy, fetchEvent, fetchEvents, fetchEventsPage, fetchMarket, fetchMatchMarketsPage, fetchMatchesPage, fetchPredictSearch, fetchSportsMatchDetail, fetchSportsMatches, fetchSportsProps, fetchSportsRouting, fetchSportsTaxonomy, getPolymarketSharesPrecision, hmacSha256Base64, infiniteCommentsQueryKey, infiniteEventsQueryKey, infiniteOrdersQueryKey, infiniteTradesMultiQueryKey, infiniteTradesQueryKey, marketQueryKey, marketTradesQueryKey, matchMarketsQueryKey, matchQueryKey, matchesQueryKey, normalizePolymarketTickSize, orderQueryKey, orderbookQueryKey, ordersMultiQueryKey, ordersQueryKey, pickBestAsk, pickBestBid, polymarketDepositAddressesQueryKey, polymarketSetupQueryKey, polymarketSupportedAssetsQueryKey, polymarketWithdrawStatusQueryKey, positionValueMultiQueryKey, positionValueQueryKey, positionsMultiQueryKey, positionsQueryKey, predictSearchQueryKey, priceHistoryQueryKey, rebateConfigQueryKey, resolveEventsParams, resolveTagSlug, similarEventsQueryKey, sportsMatchDetailQueryKey, sportsMatchesQueryKey, sportsPropsQueryKey, sportsRoutingQueryKey, sportsTaxonomyQueryKey, tickSizeQueryKey, tradesQueryKey, updatePolymarketBalanceAllowance, useAvailableShares, useBalance, useCancelOrder, useCandlesticks, useCreatePolymarketOrder, useDFlowKYC, useDFlowQuote, useDFlowSubmit, useDeployPolymarketDepositWallet, useEsportsMatches, useEsportsProps, useEsportsTaxonomy, useEvent, useEventStats, useEvents, useFeeRate, useInfiniteComments, useInfiniteEvents, useInfiniteMatchMarkets, useInfiniteMatches, useInfiniteOrders, useInfinitePredictSearch, useInfiniteTrades, useInfiniteTradesMulti, useMarket, useMarketHistory, useMarketTrades, useMatch, useOrder, useOrderbook, useOrderbookSubscription, useOrders, useOrdersMulti, usePolymarket, usePolymarketDeposit, usePolymarketDepositAddresses, usePolymarketSetup, usePolymarketSupportedAssets, usePolymarketWithdraw, usePolymarketWithdrawPrepareMutation, usePolymarketWithdrawQuoteMutation, usePolymarketWithdrawRelayBuildMutation, usePolymarketWithdrawRelaySubmitMutation, usePolymarketWithdrawStatusQuery, usePositionValue, usePositionValueMulti, usePositions, usePositionsMulti, usePredictClient, usePredictSearch, usePredictWsClient, usePriceHistory, usePricesSubscription, useRealtimeOrderbook, useRealtimePrices, useRealtimeTrades, useRebateConfig, useRedeemPosition, useRunPolymarketSetup, useSearchEvents, useSimilarEvents, useSportsMatchDetail, useSportsMatches, useSportsOrderbook, useSportsProps, useSportsRouting, useSportsTaxonomy, useTickSize, useTradeResultConfirmation, useTrades, useTradesSubscription, useWithdrawBuildMutation, useWithdrawStatusQuery, useWithdrawSubmitMutation, walkOrderbook, withdrawStatusQueryKey };
3289
3678
  //# sourceMappingURL=index.mjs.map
3290
3679
  //# sourceMappingURL=index.mjs.map