pmxt-core 2.37.1 → 2.37.3

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.
Files changed (33) hide show
  1. package/dist/exchanges/baozi/websocket.d.ts +6 -0
  2. package/dist/exchanges/baozi/websocket.js +7 -1
  3. package/dist/exchanges/kalshi/api.d.ts +1 -1
  4. package/dist/exchanges/kalshi/api.js +1 -1
  5. package/dist/exchanges/kalshi/websocket.d.ts +2 -0
  6. package/dist/exchanges/kalshi/websocket.js +7 -3
  7. package/dist/exchanges/limitless/api.d.ts +1 -1
  8. package/dist/exchanges/limitless/api.js +1 -1
  9. package/dist/exchanges/myriad/api.d.ts +1 -1
  10. package/dist/exchanges/myriad/api.js +1 -1
  11. package/dist/exchanges/opinion/api.d.ts +1 -1
  12. package/dist/exchanges/opinion/api.js +1 -1
  13. package/dist/exchanges/opinion/websocket.d.ts +2 -0
  14. package/dist/exchanges/opinion/websocket.js +5 -2
  15. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  16. package/dist/exchanges/polymarket/api-clob.js +1 -1
  17. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  18. package/dist/exchanges/polymarket/api-data.js +1 -1
  19. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  20. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  21. package/dist/exchanges/polymarket/fetcher.js +3 -1
  22. package/dist/exchanges/polymarket/websocket.d.ts +2 -0
  23. package/dist/exchanges/polymarket/websocket.js +5 -2
  24. package/dist/exchanges/polymarket_us/websocket.d.ts +6 -1
  25. package/dist/exchanges/polymarket_us/websocket.js +8 -3
  26. package/dist/exchanges/probable/api.d.ts +1 -1
  27. package/dist/exchanges/probable/api.js +1 -1
  28. package/dist/exchanges/probable/websocket.d.ts +2 -0
  29. package/dist/exchanges/probable/websocket.js +3 -1
  30. package/dist/utils/validation.js +2 -1
  31. package/dist/utils/watch-timeout.d.ts +18 -0
  32. package/dist/utils/watch-timeout.js +35 -0
  33. package/package.json +3 -3
@@ -1,13 +1,19 @@
1
1
  import { Connection } from '@solana/web3.js';
2
2
  import { OrderBook } from '../../types';
3
+ export interface BaoziWebSocketConfig {
4
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
5
+ watchTimeoutMs?: number;
6
+ }
3
7
  /**
4
8
  * Uses Solana's onAccountChange to watch market PDA updates.
5
9
  * When the account data changes (new bet placed), we re-parse
6
10
  * and emit a new synthetic order book.
7
11
  */
8
12
  export declare class BaoziWebSocket {
13
+ private config;
9
14
  private orderBookResolvers;
10
15
  private subscriptions;
16
+ constructor(config?: BaoziWebSocketConfig);
11
17
  watchOrderBook(connection: Connection, outcomeId: string): Promise<OrderBook>;
12
18
  private resolveOrderBook;
13
19
  close(connection: Connection): Promise<void>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaoziWebSocket = void 0;
4
4
  const web3_js_1 = require("@solana/web3.js");
5
+ const watch_timeout_1 = require("../../utils/watch-timeout");
5
6
  const utils_1 = require("./utils");
6
7
  /**
7
8
  * Uses Solana's onAccountChange to watch market PDA updates.
@@ -9,8 +10,12 @@ const utils_1 = require("./utils");
9
10
  * and emit a new synthetic order book.
10
11
  */
11
12
  class BaoziWebSocket {
13
+ config;
12
14
  orderBookResolvers = new Map();
13
15
  subscriptions = new Map();
16
+ constructor(config = {}) {
17
+ this.config = config;
18
+ }
14
19
  async watchOrderBook(connection, outcomeId) {
15
20
  const marketPubkey = outcomeId.replace(/-YES$|-NO$|-\d+$/, '');
16
21
  const marketKey = new web3_js_1.PublicKey(marketPubkey);
@@ -45,12 +50,13 @@ class BaoziWebSocket {
45
50
  }, 'confirmed');
46
51
  this.subscriptions.set(marketPubkey, subId);
47
52
  }
48
- return new Promise((resolve, reject) => {
53
+ const dataPromise = new Promise((resolve, reject) => {
49
54
  if (!this.orderBookResolvers.has(marketPubkey)) {
50
55
  this.orderBookResolvers.set(marketPubkey, []);
51
56
  }
52
57
  this.orderBookResolvers.get(marketPubkey).push({ resolve, reject });
53
58
  });
59
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${outcomeId}')`);
54
60
  }
55
61
  resolveOrderBook(marketPubkey, orderBook) {
56
62
  const resolvers = this.orderBookResolvers.get(marketPubkey);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
3
- * Generated at: 2026-05-03T09:04:43.064Z
3
+ * Generated at: 2026-05-03T09:34:33.989Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const kalshiApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.kalshiApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
6
- * Generated at: 2026-05-03T09:04:43.064Z
6
+ * Generated at: 2026-05-03T09:34:33.989Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.kalshiApiSpec = {
@@ -5,6 +5,8 @@ export interface KalshiWebSocketConfig {
5
5
  wsUrl?: string;
6
6
  /** Reconnection interval in milliseconds (default: 5000) */
7
7
  reconnectIntervalMs?: number;
8
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
9
+ watchTimeoutMs?: number;
8
10
  }
9
11
  /**
10
12
  * Kalshi WebSocket implementation for real-time order book and trade streaming.
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.KalshiWebSocket = void 0;
7
7
  const ws_1 = __importDefault(require("ws"));
8
+ const watch_timeout_1 = require("../../utils/watch-timeout");
8
9
  /**
9
10
  * Kalshi WebSocket implementation for real-time order book and trade streaming.
10
11
  * Follows CCXT Pro-style async iterator pattern.
@@ -340,12 +341,13 @@ class KalshiWebSocket {
340
341
  this.subscribeToOrderbook([ticker]);
341
342
  }
342
343
  // Return a promise that resolves on the next orderbook update
343
- return new Promise((resolve, reject) => {
344
+ const dataPromise = new Promise((resolve, reject) => {
344
345
  if (!this.orderBookResolvers.has(ticker)) {
345
346
  this.orderBookResolvers.set(ticker, []);
346
347
  }
347
348
  this.orderBookResolvers.get(ticker).push({ resolve, reject });
348
349
  });
350
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${ticker}')`);
349
351
  }
350
352
  async watchOrderBooks(tickers) {
351
353
  if (this.isTerminated) {
@@ -366,7 +368,7 @@ class KalshiWebSocket {
366
368
  this.subscribeToOrderbook(newTickers);
367
369
  }
368
370
  // Wait for all tickers to receive at least one snapshot/update
369
- const entries = await Promise.all(tickers.map((ticker) => new Promise((resolve, reject) => {
371
+ const dataPromise = Promise.all(tickers.map((ticker) => new Promise((resolve, reject) => {
370
372
  if (!this.orderBookResolvers.has(ticker)) {
371
373
  this.orderBookResolvers.set(ticker, []);
372
374
  }
@@ -377,6 +379,7 @@ class KalshiWebSocket {
377
379
  reject,
378
380
  });
379
381
  })));
382
+ const entries = await (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBooks(${JSON.stringify(tickers)})`);
380
383
  const result = {};
381
384
  for (const [ticker, book] of entries) {
382
385
  result[ticker] = book;
@@ -398,12 +401,13 @@ class KalshiWebSocket {
398
401
  else {
399
402
  this.subscribeToTrades([ticker]);
400
403
  }
401
- return new Promise((resolve, reject) => {
404
+ const dataPromise = new Promise((resolve, reject) => {
402
405
  if (!this.tradeResolvers.has(ticker)) {
403
406
  this.tradeResolvers.set(ticker, []);
404
407
  }
405
408
  this.tradeResolvers.get(ticker).push({ resolve, reject });
406
409
  });
410
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchTrades('${ticker}')`);
407
411
  }
408
412
  async close() {
409
413
  this.isTerminated = true;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
3
- * Generated at: 2026-05-03T09:04:43.109Z
3
+ * Generated at: 2026-05-03T09:34:34.027Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const limitlessApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.limitlessApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
6
- * Generated at: 2026-05-03T09:04:43.109Z
6
+ * Generated at: 2026-05-03T09:34:34.027Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.limitlessApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
3
- * Generated at: 2026-05-03T09:04:43.127Z
3
+ * Generated at: 2026-05-03T09:34:34.040Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const myriadApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.myriadApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
6
- * Generated at: 2026-05-03T09:04:43.127Z
6
+ * Generated at: 2026-05-03T09:34:34.040Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.myriadApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
3
- * Generated at: 2026-05-03T09:04:43.132Z
3
+ * Generated at: 2026-05-03T09:34:34.045Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const opinionApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.opinionApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
6
- * Generated at: 2026-05-03T09:04:43.132Z
6
+ * Generated at: 2026-05-03T09:34:34.045Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.opinionApiSpec = {
@@ -2,6 +2,8 @@ import { OrderBook, Trade } from "../../types";
2
2
  export interface OpinionWebSocketConfig {
3
3
  /** Reconnection interval in milliseconds (default: 5000) */
4
4
  reconnectIntervalMs?: number;
5
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
6
+ watchTimeoutMs?: number;
5
7
  }
6
8
  /**
7
9
  * Opinion Trade WebSocket implementation for real-time order book and trade streaming.
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OpinionWebSocket = void 0;
7
7
  const ws_1 = __importDefault(require("ws"));
8
+ const watch_timeout_1 = require("../../utils/watch-timeout");
8
9
  /**
9
10
  * Opinion Trade WebSocket implementation for real-time order book and trade streaming.
10
11
  * Follows CCXT Pro-style async iterator pattern.
@@ -262,12 +263,13 @@ class OpinionWebSocket {
262
263
  else {
263
264
  this.sendSubscribe("market.depth.diff", marketId);
264
265
  }
265
- return new Promise((resolve, reject) => {
266
+ const dataPromise = new Promise((resolve, reject) => {
266
267
  if (!this.orderBookResolvers.has(marketId)) {
267
268
  this.orderBookResolvers.set(marketId, []);
268
269
  }
269
270
  this.orderBookResolvers.get(marketId).push({ resolve, reject });
270
271
  });
272
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${marketId}')`);
271
273
  }
272
274
  /**
273
275
  * Watch trade updates for a given binary market.
@@ -288,12 +290,13 @@ class OpinionWebSocket {
288
290
  else {
289
291
  this.sendSubscribe("market.last.trade", marketId);
290
292
  }
291
- return new Promise((resolve, reject) => {
293
+ const dataPromise = new Promise((resolve, reject) => {
292
294
  if (!this.tradeResolvers.has(marketId)) {
293
295
  this.tradeResolvers.set(marketId, []);
294
296
  }
295
297
  this.tradeResolvers.get(marketId).push({ resolve, reject });
296
298
  });
299
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchTrades('${marketId}')`);
297
300
  }
298
301
  /**
299
302
  * Close the WebSocket connection and reject all pending promises.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
3
- * Generated at: 2026-05-03T09:04:43.075Z
3
+ * Generated at: 2026-05-03T09:34:33.994Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketClobSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
6
- * Generated at: 2026-05-03T09:04:43.075Z
6
+ * Generated at: 2026-05-03T09:34:33.994Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
3
- * Generated at: 2026-05-03T09:04:43.088Z
3
+ * Generated at: 2026-05-03T09:34:34.011Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketDataSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketDataSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
6
- * Generated at: 2026-05-03T09:04:43.088Z
6
+ * Generated at: 2026-05-03T09:34:34.011Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketDataSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
3
- * Generated at: 2026-05-03T09:04:43.086Z
3
+ * Generated at: 2026-05-03T09:34:34.007Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketGammaSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketGammaSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
6
- * Generated at: 2026-05-03T09:04:43.086Z
6
+ * Generated at: 2026-05-03T09:34:34.007Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -154,7 +154,9 @@ class PolymarketFetcher {
154
154
  // which the heuristic mapper mis-categorises as OrderNotFound.
155
155
  // Normalise to NotFound so all venues behave the same for order-book lookups.
156
156
  if (mapped instanceof errors_1.OrderNotFound) {
157
- throw new errors_1.NotFound(`Order book not found: ${id}`, 'Polymarket');
157
+ throw new errors_1.NotFound(`Order book not found: ${id}. ` +
158
+ `fetchOrderBook requires an outcome token ID (market.yes.outcomeId or market.no.outcomeId from fetchMarkets), ` +
159
+ `not a market slug or condition ID.`, 'Polymarket');
158
160
  }
159
161
  throw mapped;
160
162
  }
@@ -15,6 +15,8 @@ export interface PolymarketWebSocketConfig {
15
15
  flushIntervalMs?: number;
16
16
  /** Watcher subscription configurations */
17
17
  watcherConfig?: WatcherConfig;
18
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
19
+ watchTimeoutMs?: number;
18
20
  }
19
21
  /**
20
22
  * Wrapper around @nevuamarkets/poly-websockets that provides CCXT Pro-style
@@ -43,6 +43,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.PolymarketWebSocket = void 0;
44
44
  const goldsky_1 = require("../../subscriber/external/goldsky");
45
45
  const watcher_1 = require("../../subscriber/watcher");
46
+ const watch_timeout_1 = require("../../utils/watch-timeout");
46
47
  /**
47
48
  * Wrapper around @nevuamarkets/poly-websockets that provides CCXT Pro-style
48
49
  * watchOrderBook() and watchTrades() methods.
@@ -75,12 +76,13 @@ class PolymarketWebSocket {
75
76
  await this.manager.addSubscriptions([id]);
76
77
  }
77
78
  // Return a promise that resolves on the next orderbook update
78
- return new Promise((resolve, reject) => {
79
+ const dataPromise = new Promise((resolve, reject) => {
79
80
  if (!this.orderBookResolvers.has(id)) {
80
81
  this.orderBookResolvers.set(id, []);
81
82
  }
82
83
  this.orderBookResolvers.get(id).push({ resolve, reject });
83
84
  });
85
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${id}')`);
84
86
  }
85
87
  async unwatchOrderBook(id) {
86
88
  if (!this.manager) {
@@ -108,12 +110,13 @@ class PolymarketWebSocket {
108
110
  await this.manager.addSubscriptions([id]);
109
111
  }
110
112
  // Return a promise that resolves on the next trade
111
- return new Promise((resolve, reject) => {
113
+ const dataPromise = new Promise((resolve, reject) => {
112
114
  if (!this.tradeResolvers.has(id)) {
113
115
  this.tradeResolvers.set(id, []);
114
116
  }
115
117
  this.tradeResolvers.get(id).push({ resolve, reject });
116
118
  });
119
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchTrades('${id}')`);
117
120
  }
118
121
  async watchAddress(address, types) {
119
122
  return this.watcher.watch(address, types);
@@ -16,16 +16,21 @@
16
16
  import type { PolymarketUS as PolymarketUSClient } from 'polymarket-us';
17
17
  import { OrderBook, Trade } from '../../types';
18
18
  import { PolymarketUSNormalizer } from './normalizer';
19
+ export interface PolymarketUSWebSocketConfig {
20
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
21
+ watchTimeoutMs?: number;
22
+ }
19
23
  export declare class PolymarketUSWebSocket {
20
24
  private readonly client;
21
25
  private readonly normalizer;
26
+ private readonly config;
22
27
  private socket;
23
28
  private initializationPromise?;
24
29
  private readonly bookSubscriptions;
25
30
  private readonly tradeSubscriptions;
26
31
  private readonly orderBookResolvers;
27
32
  private readonly tradeResolvers;
28
- constructor(client: PolymarketUSClient, normalizer: PolymarketUSNormalizer);
33
+ constructor(client: PolymarketUSClient, normalizer: PolymarketUSNormalizer, config?: PolymarketUSWebSocketConfig);
29
34
  watchOrderBook(id: string): Promise<OrderBook>;
30
35
  watchTrades(id: string): Promise<Trade[]>;
31
36
  close(): Promise<void>;
@@ -16,6 +16,7 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.PolymarketUSWebSocket = void 0;
19
+ const watch_timeout_1 = require("../../utils/watch-timeout");
19
20
  const price_1 = require("./price");
20
21
  function sideFromOrderSide(raw) {
21
22
  if (raw === 'ORDER_SIDE_BUY')
@@ -44,15 +45,17 @@ function slugFromId(id) {
44
45
  class PolymarketUSWebSocket {
45
46
  client;
46
47
  normalizer;
48
+ config;
47
49
  socket = null;
48
50
  initializationPromise;
49
51
  bookSubscriptions = new Set();
50
52
  tradeSubscriptions = new Set();
51
53
  orderBookResolvers = new Map();
52
54
  tradeResolvers = new Map();
53
- constructor(client, normalizer) {
55
+ constructor(client, normalizer, config = {}) {
54
56
  this.client = client;
55
57
  this.normalizer = normalizer;
58
+ this.config = config;
56
59
  }
57
60
  async watchOrderBook(id) {
58
61
  const slug = slugFromId(id);
@@ -61,11 +64,12 @@ class PolymarketUSWebSocket {
61
64
  this.bookSubscriptions.add(slug);
62
65
  this.socket.subscribeMarketData(`book:${slug}`, [slug]);
63
66
  }
64
- return new Promise((resolve, reject) => {
67
+ const dataPromise = new Promise((resolve, reject) => {
65
68
  const queue = this.orderBookResolvers.get(slug) ?? [];
66
69
  queue.push({ resolve, reject });
67
70
  this.orderBookResolvers.set(slug, queue);
68
71
  });
72
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${id}')`);
69
73
  }
70
74
  async watchTrades(id) {
71
75
  const slug = slugFromId(id);
@@ -74,11 +78,12 @@ class PolymarketUSWebSocket {
74
78
  this.tradeSubscriptions.add(slug);
75
79
  this.socket.subscribeTrades(`trade:${slug}`, [slug]);
76
80
  }
77
- return new Promise((resolve, reject) => {
81
+ const dataPromise = new Promise((resolve, reject) => {
78
82
  const queue = this.tradeResolvers.get(slug) ?? [];
79
83
  queue.push({ resolve, reject });
80
84
  this.tradeResolvers.set(slug, queue);
81
85
  });
86
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchTrades('${id}')`);
82
87
  }
83
88
  async close() {
84
89
  if (this.socket) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
3
- * Generated at: 2026-05-03T09:04:43.115Z
3
+ * Generated at: 2026-05-03T09:34:34.033Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const probableApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.probableApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
6
- * Generated at: 2026-05-03T09:04:43.115Z
6
+ * Generated at: 2026-05-03T09:34:34.033Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -6,6 +6,8 @@ export interface ProbableWebSocketConfig {
6
6
  baseUrl?: string;
7
7
  /** Chain ID (default: 56 for BSC mainnet) */
8
8
  chainId?: number;
9
+ /** Timeout in ms for watch methods to receive data (default: 30000). 0 = no timeout. */
10
+ watchTimeoutMs?: number;
9
11
  }
10
12
  /**
11
13
  * Probable WebSocket implementation for real-time order book streaming.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProbableWebSocket = void 0;
4
+ const watch_timeout_1 = require("../../utils/watch-timeout");
4
5
  /**
5
6
  * Probable WebSocket implementation for real-time order book streaming.
6
7
  * Uses the @prob/clob SDK's subscribePublicStream (no auth required).
@@ -42,12 +43,13 @@ class ProbableWebSocket {
42
43
  this.subscriptions.set(tokenId, sub);
43
44
  }
44
45
  // Return a promise that resolves on the next orderbook update
45
- return new Promise((resolve, reject) => {
46
+ const dataPromise = new Promise((resolve, reject) => {
46
47
  if (!this.orderBookResolvers.has(tokenId)) {
47
48
  this.orderBookResolvers.set(tokenId, []);
48
49
  }
49
50
  this.orderBookResolvers.get(tokenId).push({ resolve, reject });
50
51
  });
52
+ return (0, watch_timeout_1.withWatchTimeout)(dataPromise, this.config.watchTimeoutMs ?? watch_timeout_1.DEFAULT_WATCH_TIMEOUT_MS, `watchOrderBook('${tokenId}')`);
51
53
  }
52
54
  handleOrderBookUpdate(tokenId, data) {
53
55
  const bids = (data.bids || []).map((b) => ({
@@ -12,7 +12,8 @@ function validateOutcomeId(id, context) {
12
12
  // Short numeric IDs are invalid for trading operations
13
13
  if (id.length < 10 && /^\d+$/.test(id)) {
14
14
  throw new errors_1.ValidationError(`Invalid outcome ID for ${context}: "${id}". ` +
15
- `Numeric outcome IDs must be at least 10 digits. Please use the correct outcome ID.`, 'id');
15
+ `fetchOrderBook requires an outcome token ID, not a market slug or condition ID. ` +
16
+ `Use fetchMarkets to find the market, then pass market.yes.outcomeId or market.no.outcomeId.`, 'id');
16
17
  }
17
18
  }
18
19
  function validateIdFormat(id, context) {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Default timeout for watch methods (30 seconds).
3
+ *
4
+ * Generous enough for valid but illiquid markets, but prevents
5
+ * hanging forever on non-existing IDs.
6
+ */
7
+ export declare const DEFAULT_WATCH_TIMEOUT_MS = 30000;
8
+ /**
9
+ * Wrap a watch promise with a timeout that rejects if no data arrives.
10
+ *
11
+ * Used by all exchange WebSocket implementations to prevent indefinite
12
+ * hangs when subscribing to non-existing market IDs.
13
+ *
14
+ * @param promise - The data promise (resolves when WS data arrives)
15
+ * @param timeoutMs - Maximum time to wait in milliseconds (0 = no timeout)
16
+ * @param label - Human-readable label for the error message
17
+ */
18
+ export declare function withWatchTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_WATCH_TIMEOUT_MS = void 0;
4
+ exports.withWatchTimeout = withWatchTimeout;
5
+ /**
6
+ * Default timeout for watch methods (30 seconds).
7
+ *
8
+ * Generous enough for valid but illiquid markets, but prevents
9
+ * hanging forever on non-existing IDs.
10
+ */
11
+ exports.DEFAULT_WATCH_TIMEOUT_MS = 30_000;
12
+ /**
13
+ * Wrap a watch promise with a timeout that rejects if no data arrives.
14
+ *
15
+ * Used by all exchange WebSocket implementations to prevent indefinite
16
+ * hangs when subscribing to non-existing market IDs.
17
+ *
18
+ * @param promise - The data promise (resolves when WS data arrives)
19
+ * @param timeoutMs - Maximum time to wait in milliseconds (0 = no timeout)
20
+ * @param label - Human-readable label for the error message
21
+ */
22
+ function withWatchTimeout(promise, timeoutMs, label) {
23
+ if (timeoutMs <= 0)
24
+ return promise;
25
+ let timer;
26
+ const timeoutPromise = new Promise((_, reject) => {
27
+ timer = setTimeout(() => {
28
+ reject(new Error(`${label}: timed out after ${timeoutMs}ms waiting for data. ` +
29
+ `The ID may not exist on this exchange.`));
30
+ }, timeoutMs);
31
+ });
32
+ return Promise.race([promise, timeoutPromise]).finally(() => {
33
+ clearTimeout(timer);
34
+ });
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxt-core",
3
- "version": "2.37.1",
3
+ "version": "2.37.3",
4
4
  "description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "test": "jest -c jest.config.js",
30
30
  "server": "tsx watch src/server/index.ts",
31
31
  "server:prod": "node dist/server/index.js",
32
- "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.37.1,library=urllib3",
33
- "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.37.1,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
32
+ "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.37.3,library=urllib3",
33
+ "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.37.3,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
34
34
  "fetch:openapi": "node scripts/fetch-openapi-specs.js",
35
35
  "extract:jsdoc": "node ../scripts/extract-jsdoc.js",
36
36
  "generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",