@liberfi.io/react-predict 0.3.46 → 0.3.48

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,4 +1,4 @@
1
- import { httpGet, httpDelete, httpPost } from '@liberfi.io/utils';
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
4
  import { useQuery, useInfiniteQuery, useQueries, useQueryClient, useMutation } from '@tanstack/react-query';
@@ -113,6 +113,17 @@ var PredictClient = class {
113
113
  const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/orderbook${query}`;
114
114
  return await httpGet(url);
115
115
  }
116
+ /**
117
+ * Maps to `POST /api/v1/markets/orderbooks`.
118
+ * Fetches order books for many markets in a single request (max 100 items).
119
+ * Results are returned in the same order as `items`; per-item failures are
120
+ * reported via `OrderbookBatchResult.error` and never fail the whole batch.
121
+ */
122
+ async getOrderbooks(items) {
123
+ const url = `${this.endpoint}/api/v1/markets/orderbooks`;
124
+ const res = await httpPost(url, { items });
125
+ return res.results;
126
+ }
116
127
  /** Maps to `GET /api/v1/markets/:slug/trades?source=...`. */
117
128
  async listMarketTrades(slug, params) {
118
129
  const query = buildQuery(params);
@@ -537,6 +548,13 @@ var DEFAULT_RECONNECT_BASE = 1e3;
537
548
  var DEFAULT_RECONNECT_MAX = 3e4;
538
549
  var DEFAULT_PING_INTERVAL = 2e4;
539
550
  var DEFAULT_PONG_TIMEOUT = 1e4;
551
+ var MAX_SUBSCRIPTION_FRAME_BYTES = 3500;
552
+ function byteLength(str) {
553
+ if (typeof TextEncoder !== "undefined") {
554
+ return new TextEncoder().encode(str).length;
555
+ }
556
+ return str.length;
557
+ }
540
558
  var PredictWsClient = class {
541
559
  ws = null;
542
560
  wsUrl;
@@ -654,7 +672,7 @@ var PredictWsClient = class {
654
672
  const set = this.subs.channels.get(ch);
655
673
  for (const slug of marketSlugs) set.add(slug);
656
674
  }
657
- this.send({ type: "subscribe", channels, market_slugs: marketSlugs });
675
+ this.sendChunkedSubscription("subscribe", channels, marketSlugs);
658
676
  }
659
677
  /**
660
678
  * Unsubscribe from one or more channels for the given market slugs.
@@ -664,7 +682,7 @@ var PredictWsClient = class {
664
682
  const set = this.subs.channels.get(ch);
665
683
  for (const slug of marketSlugs) set.delete(slug);
666
684
  }
667
- this.send({ type: "unsubscribe", channels, market_slugs: marketSlugs });
685
+ this.sendChunkedSubscription("unsubscribe", channels, marketSlugs);
668
686
  }
669
687
  // -------------------------------------------------------------------------
670
688
  // Subscription — convenience (single channel)
@@ -820,14 +838,40 @@ var PredictWsClient = class {
820
838
  restoreSubscriptions() {
821
839
  for (const [channel, slugs] of this.subs.channels.entries()) {
822
840
  if (slugs.size > 0) {
823
- this.send({
824
- type: "subscribe",
825
- channels: [channel],
826
- market_slugs: Array.from(slugs)
827
- });
841
+ this.sendChunkedSubscription("subscribe", [channel], Array.from(slugs));
828
842
  }
829
843
  }
830
844
  }
845
+ /**
846
+ * Send a subscribe/unsubscribe message, splitting `marketSlugs` across
847
+ * multiple frames so no single frame exceeds the server read limit.
848
+ */
849
+ sendChunkedSubscription(type, channels, marketSlugs) {
850
+ if (marketSlugs.length === 0) {
851
+ this.send({ type, channels, market_slugs: [] });
852
+ return;
853
+ }
854
+ const envelopeBytes = byteLength(
855
+ JSON.stringify({ type, channels, market_slugs: [] })
856
+ );
857
+ const budget = MAX_SUBSCRIPTION_FRAME_BYTES - envelopeBytes;
858
+ let chunk = [];
859
+ let chunkBytes = 0;
860
+ const flush = () => {
861
+ if (chunk.length > 0) {
862
+ this.send({ type, channels, market_slugs: chunk });
863
+ chunk = [];
864
+ chunkBytes = 0;
865
+ }
866
+ };
867
+ for (const slug of marketSlugs) {
868
+ const slugBytes = byteLength(JSON.stringify(slug)) + 1;
869
+ if (chunk.length > 0 && chunkBytes + slugBytes > budget) flush();
870
+ chunk.push(slug);
871
+ chunkBytes += slugBytes;
872
+ }
873
+ flush();
874
+ }
831
875
  startPing() {
832
876
  this.stopPing();
833
877
  this.pingTimer = setInterval(() => {