pmxt-core 2.48.5 → 2.49.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.
Files changed (68) hide show
  1. package/dist/BaseExchange.js +2 -0
  2. package/dist/exchanges/baozi/normalizer.js +3 -3
  3. package/dist/exchanges/gemini-titan/normalizer.js +9 -3
  4. package/dist/exchanges/gemini-titan/websocket.js +17 -5
  5. package/dist/exchanges/hyperliquid/normalizer.js +2 -0
  6. package/dist/exchanges/interfaces.d.ts +2 -2
  7. package/dist/exchanges/kalshi/api.d.ts +1 -1
  8. package/dist/exchanges/kalshi/api.js +2 -2
  9. package/dist/exchanges/kalshi/config.d.ts +6 -6
  10. package/dist/exchanges/kalshi/config.js +8 -8
  11. package/dist/exchanges/kalshi/fetcher.d.ts +2 -0
  12. package/dist/exchanges/kalshi/fetcher.js +6 -7
  13. package/dist/exchanges/kalshi/normalizer.js +6 -1
  14. package/dist/exchanges/kalshi/websocket.js +21 -9
  15. package/dist/exchanges/limitless/api.d.ts +1 -1
  16. package/dist/exchanges/limitless/api.js +1 -1
  17. package/dist/exchanges/limitless/client.js +2 -2
  18. package/dist/exchanges/limitless/config.d.ts +2 -0
  19. package/dist/exchanges/limitless/config.js +3 -1
  20. package/dist/exchanges/limitless/fetcher.d.ts +10 -0
  21. package/dist/exchanges/limitless/fetcher.js +2 -1
  22. package/dist/exchanges/limitless/index.js +1 -1
  23. package/dist/exchanges/limitless/utils.js +3 -3
  24. package/dist/exchanges/limitless/websocket.js +8 -11
  25. package/dist/exchanges/metaculus/utils.js +0 -1
  26. package/dist/exchanges/myriad/api.d.ts +1 -1
  27. package/dist/exchanges/myriad/api.js +17 -2
  28. package/dist/exchanges/myriad/normalizer.js +10 -5
  29. package/dist/exchanges/myriad/utils.js +2 -0
  30. package/dist/exchanges/opinion/api.d.ts +16 -1
  31. package/dist/exchanges/opinion/api.js +20 -1
  32. package/dist/exchanges/opinion/normalizer.js +9 -5
  33. package/dist/exchanges/opinion/utils.d.ts +1 -1
  34. package/dist/exchanges/opinion/utils.js +3 -1
  35. package/dist/exchanges/opinion/websocket.js +21 -14
  36. package/dist/exchanges/polymarket/api-clob.d.ts +13 -1
  37. package/dist/exchanges/polymarket/api-clob.js +26 -1
  38. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  39. package/dist/exchanges/polymarket/api-data.js +1 -1
  40. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  41. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  42. package/dist/exchanges/polymarket/auth.js +3 -3
  43. package/dist/exchanges/polymarket/config.d.ts +1 -0
  44. package/dist/exchanges/polymarket/config.js +4 -0
  45. package/dist/exchanges/polymarket/index.js +2 -1
  46. package/dist/exchanges/polymarket_us/websocket.js +3 -2
  47. package/dist/exchanges/probable/api.d.ts +1 -1
  48. package/dist/exchanges/probable/api.js +1 -1
  49. package/dist/exchanges/probable/auth.js +5 -4
  50. package/dist/exchanges/probable/config.d.ts +2 -0
  51. package/dist/exchanges/probable/config.js +5 -0
  52. package/dist/exchanges/probable/websocket.js +2 -1
  53. package/dist/exchanges/suibets/api.d.ts +1 -1
  54. package/dist/exchanges/suibets/api.js +1 -1
  55. package/dist/exchanges/suibets/config.d.ts +1 -1
  56. package/dist/exchanges/suibets/config.js +2 -2
  57. package/dist/exchanges/suibets/errors.js +9 -0
  58. package/dist/exchanges/suibets/fetcher.d.ts +22 -2
  59. package/dist/exchanges/suibets/fetcher.js +23 -5
  60. package/dist/exchanges/suibets/index.d.ts +1 -1
  61. package/dist/exchanges/suibets/index.js +1 -1
  62. package/dist/exchanges/suibets/normalizer.js +2 -22
  63. package/dist/feeds/binance/binance-feed.js +6 -3
  64. package/dist/feeds/chainlink/chainlink-feed.js +5 -2
  65. package/dist/server/openapi.yaml +5 -2
  66. package/dist/types.d.ts +5 -2
  67. package/dist/utils/throttler.js +3 -5
  68. package/package.json +4 -4
@@ -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-06-02T16:35:55.847Z
3
+ * Generated at: 2026-06-08T19:06:11.875Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const opinionApiSpec: {
@@ -113,6 +113,21 @@ export declare const opinionApiSpec: {
113
113
  }[];
114
114
  };
115
115
  };
116
+ "/market/slug/{slug}": {
117
+ get: {
118
+ tags: string[];
119
+ summary: string;
120
+ operationId: string;
121
+ parameters: {
122
+ name: string;
123
+ in: string;
124
+ required: boolean;
125
+ schema: {
126
+ type: string;
127
+ };
128
+ }[];
129
+ };
130
+ };
116
131
  "/market/categorical/{marketId}": {
117
132
  get: {
118
133
  tags: string[];
@@ -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-06-02T16:35:55.847Z
6
+ * Generated at: 2026-06-08T19:06:11.875Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.opinionApiSpec = {
@@ -150,6 +150,25 @@ exports.opinionApiSpec = {
150
150
  ]
151
151
  }
152
152
  },
153
+ "/market/slug/{slug}": {
154
+ "get": {
155
+ "tags": [
156
+ "Market"
157
+ ],
158
+ "summary": "Get market detail by slug",
159
+ "operationId": "getMarketDetailBySlug",
160
+ "parameters": [
161
+ {
162
+ "name": "slug",
163
+ "in": "path",
164
+ "required": true,
165
+ "schema": {
166
+ "type": "string"
167
+ }
168
+ }
169
+ ]
170
+ }
171
+ },
153
172
  "/market/categorical/{marketId}": {
154
173
  "get": {
155
174
  "tags": [
@@ -157,7 +157,7 @@ class OpinionNormalizer {
157
157
  normalizeTrade(raw, index) {
158
158
  return {
159
159
  id: raw.txHash || String(index),
160
- timestamp: (0, utils_1.toMillis)(raw.createdAt),
160
+ timestamp: (0, utils_1.toMillis)(raw.createdAt) ?? 0,
161
161
  price: (0, utils_1.parseNumStr)(raw.price),
162
162
  amount: (0, utils_1.parseNumStr)(raw.shares),
163
163
  side: raw.side === 'BUY' ? 'buy' : raw.side === 'SELL' ? 'sell' : 'unknown',
@@ -167,7 +167,7 @@ class OpinionNormalizer {
167
167
  normalizeUserTrade(raw, index) {
168
168
  return {
169
169
  id: raw.txHash || String(index),
170
- timestamp: (0, utils_1.toMillis)(raw.createdAt),
170
+ timestamp: (0, utils_1.toMillis)(raw.createdAt) ?? 0,
171
171
  price: (0, utils_1.parseNumStr)(raw.price),
172
172
  amount: (0, utils_1.parseNumStr)(raw.shares),
173
173
  side: raw.side === 'BUY' ? 'buy' : raw.side === 'SELL' ? 'sell' : 'unknown',
@@ -203,7 +203,7 @@ class OpinionNormalizer {
203
203
  status: (0, utils_1.mapOrderStatus)(raw.status),
204
204
  filled: filledShares,
205
205
  remaining: orderShares - filledShares,
206
- timestamp: (0, utils_1.toMillis)(raw.createdAt),
206
+ timestamp: (0, utils_1.toMillis)(raw.createdAt) ?? 0,
207
207
  };
208
208
  }
209
209
  // -- Price enrichment -----------------------------------------------------
@@ -279,7 +279,9 @@ class OpinionNormalizer {
279
279
  title: raw.marketTitle || '',
280
280
  description: raw.rules || '',
281
281
  outcomes: [yesOutcome, noOutcome],
282
- resolutionDate: new Date((0, utils_1.toMillis)(raw.cutoffAt)),
282
+ resolutionDate: (0, utils_1.toMillis)(raw.cutoffAt) !== null
283
+ ? new Date((0, utils_1.toMillis)(raw.cutoffAt))
284
+ : undefined,
283
285
  volume24h: (0, utils_1.parseNumStr)(raw.volume24h),
284
286
  volume: (0, utils_1.parseNumStr)(raw.volume),
285
287
  liquidity: 0,
@@ -324,7 +326,9 @@ class OpinionNormalizer {
324
326
  title: combinedTitle,
325
327
  description: child.rules || '',
326
328
  outcomes: [yesOutcome, noOutcome],
327
- resolutionDate: new Date((0, utils_1.toMillis)(child.cutoffAt)),
329
+ resolutionDate: (0, utils_1.toMillis)(child.cutoffAt || parent.cutoffAt) !== null
330
+ ? new Date((0, utils_1.toMillis)(child.cutoffAt || parent.cutoffAt))
331
+ : undefined,
328
332
  volume24h,
329
333
  volume: (0, utils_1.parseNumStr)(child.volume),
330
334
  liquidity: 0,
@@ -19,5 +19,5 @@ export declare function mapSortToOpinion(sort?: string): number | undefined;
19
19
  export declare function mapIntervalToOpinion(interval: CandleInterval): string;
20
20
  export declare function mapOrderStatus(status: number): 'pending' | 'open' | 'filled' | 'canceled' | 'rejected';
21
21
  export declare function parseNumStr(value: string | undefined | null): number;
22
- export declare function toMillis(ts: number | undefined | null): number;
22
+ export declare function toMillis(ts: number | undefined | null): number | null;
23
23
  export declare function intervalToMs(interval: CandleInterval): number;
@@ -76,9 +76,11 @@ function parseNumStr(value) {
76
76
  }
77
77
  // Convert a raw timestamp to milliseconds.
78
78
  // If the value is under 10_000_000_000 it is assumed to be in seconds.
79
+ // Returns null when the input is missing/zero so callers can distinguish
80
+ // "no timestamp" from "epoch" instead of coercing both to 1970-01-01.
79
81
  function toMillis(ts) {
80
82
  if (!ts)
81
- return 0;
83
+ return null;
82
84
  return ts < 10_000_000_000 ? ts * 1000 : ts;
83
85
  }
84
86
  // Return the bucket size in milliseconds for a given CandleInterval
@@ -200,10 +200,7 @@ class OpinionWebSocket {
200
200
  if (isNaN(price)) {
201
201
  return;
202
202
  }
203
- const existing = this.orderBooks.get(marketId);
204
- const book = existing
205
- ? { ...existing }
206
- : { bids: [], asks: [], timestamp: Date.now() };
203
+ const book = this.orderBooks.get(marketId) ?? { bids: [], asks: [], timestamp: Date.now() };
207
204
  if (side === "bids") {
208
205
  book.bids = applyLevelUpdate(book.bids, price, size, "desc");
209
206
  }
@@ -280,8 +277,11 @@ class OpinionWebSocket {
280
277
  this.subscribedDepthMarketIds.add(marketId);
281
278
  }
282
279
  if (!this.isConnected) {
283
- this.connect().catch(() => {
284
- // Swallow scheduleReconnect will retry. Resolvers stay pending.
280
+ this.connect().catch((err) => {
281
+ logger_1.logger.warn("Opinion WebSocket connect failed during watchOrderBook", { error: String(err) });
282
+ if (!this.isTerminated) {
283
+ this.scheduleReconnect();
284
+ }
285
285
  });
286
286
  }
287
287
  else {
@@ -310,8 +310,11 @@ class OpinionWebSocket {
310
310
  this.subscribedTradeMarketIds.add(marketId);
311
311
  }
312
312
  if (!this.isConnected) {
313
- this.connect().catch(() => {
314
- // Swallow scheduleReconnect will retry. Resolvers stay pending.
313
+ this.connect().catch((err) => {
314
+ logger_1.logger.warn("Opinion WebSocket connect failed during watchTrades", { error: String(err) });
315
+ if (!this.isTerminated) {
316
+ this.scheduleReconnect();
317
+ }
315
318
  });
316
319
  }
317
320
  else {
@@ -378,20 +381,24 @@ exports.OpinionWebSocket = OpinionWebSocket;
378
381
  // ---------------------------------------------------------------------------
379
382
  /**
380
383
  * Apply an absolute-size level update to one side of the book.
381
- * A size of 0 (or NaN) removes the level. Returns a new sorted array.
384
+ * A size of 0 (or NaN) removes the level. Mutates the provided array in place
385
+ * and keeps it sorted.
382
386
  */
383
387
  function applyLevelUpdate(levels, price, size, sortOrder) {
384
- const updated = levels.filter((l) => Math.abs(l.price - price) >= 0.0001);
388
+ const idx = levels.findIndex((l) => l.price === price);
389
+ if (idx !== -1) {
390
+ levels.splice(idx, 1);
391
+ }
385
392
  if (!isNaN(size) && size > 0) {
386
- updated.push({ price, size });
393
+ levels.push({ price, size });
387
394
  }
388
395
  if (sortOrder === "desc") {
389
- updated.sort((a, b) => b.price - a.price);
396
+ levels.sort((a, b) => b.price - a.price);
390
397
  }
391
398
  else {
392
- updated.sort((a, b) => a.price - b.price);
399
+ levels.sort((a, b) => a.price - b.price);
393
400
  }
394
- return updated;
401
+ return levels;
395
402
  }
396
403
  /**
397
404
  * Map Opinion's trade side string to our unified type.
@@ -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-06-02T16:35:55.801Z
3
+ * Generated at: 2026-06-08T19:06:11.828Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -243,6 +243,18 @@ export declare const polymarketClobSpec: {
243
243
  }[];
244
244
  };
245
245
  };
246
+ "/v1/heartbeats": {
247
+ post: {
248
+ summary: string;
249
+ tags: string[];
250
+ security: {
251
+ L2Auth: never[];
252
+ }[];
253
+ parameters: {
254
+ $ref: string;
255
+ }[];
256
+ };
257
+ };
246
258
  "/data/order/{id}": {
247
259
  get: {
248
260
  summary: string;
@@ -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-06-02T16:35:55.801Z
6
+ * Generated at: 2026-06-08T19:06:11.828Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -349,6 +349,24 @@ exports.polymarketClobSpec = {
349
349
  ]
350
350
  }
351
351
  },
352
+ "/v1/heartbeats": {
353
+ "post": {
354
+ "summary": "Refresh authenticated session heartbeat",
355
+ "tags": [
356
+ "Orders"
357
+ ],
358
+ "security": [
359
+ {
360
+ "L2Auth": []
361
+ }
362
+ ],
363
+ "parameters": [
364
+ {
365
+ "$ref": "#/components/parameters/L2Headers"
366
+ }
367
+ ]
368
+ }
369
+ },
352
370
  "/data/order/{id}": {
353
371
  "get": {
354
372
  "summary": "Get Order",
@@ -410,6 +428,13 @@ exports.polymarketClobSpec = {
410
428
  "schema": {
411
429
  "type": "string"
412
430
  }
431
+ },
432
+ {
433
+ "name": "next_cursor",
434
+ "in": "query",
435
+ "schema": {
436
+ "type": "string"
437
+ }
413
438
  }
414
439
  ]
415
440
  }
@@ -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-06-02T16:35:55.817Z
3
+ * Generated at: 2026-06-08T19:06:11.840Z
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-06-02T16:35:55.817Z
6
+ * Generated at: 2026-06-08T19:06:11.840Z
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-06-02T16:35:55.815Z
3
+ * Generated at: 2026-06-08T19:06:11.836Z
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-06-02T16:35:55.815Z
6
+ * Generated at: 2026-06-08T19:06:11.836Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -10,9 +10,9 @@ const accounts_1 = require("viem/accounts");
10
10
  const chains_1 = require("viem/chains");
11
11
  const axios_1 = __importDefault(require("axios"));
12
12
  const logger_1 = require("../../utils/logger");
13
+ const config_1 = require("./config");
13
14
  const errors_1 = require("./errors");
14
15
  const DEFAULT_POLYMARKET_HOST = process.env.POLYMARKET_CLOB_URL || 'https://clob.polymarket.com';
15
- const POLYGON_CHAIN_ID = 137;
16
16
  // Polymarket CLOB signature types — determines how the CLOB API
17
17
  // resolves the on-chain address holding the user's funds.
18
18
  const SIG_TYPE_EOA = 0;
@@ -83,7 +83,7 @@ class PolymarketAuth {
83
83
  // Otherwise, derive/create them using L1 auth
84
84
  const l1Client = new clob_client_v2_1.ClobClient({
85
85
  host: this.host,
86
- chain: POLYGON_CHAIN_ID,
86
+ chain: config_1.POLYMARKET_CHAIN_ID,
87
87
  signer: this.signer,
88
88
  });
89
89
  // Robust derivation strategy:
@@ -253,7 +253,7 @@ class PolymarketAuth {
253
253
  // console.log(`[PolymarketAuth] Initializing ClobClient | Signer: ${signerAddress} | Funder: ${finalProxyAddress} | SigType: ${finalSignatureType}`);
254
254
  this.clobClient = new clob_client_v2_1.ClobClient({
255
255
  host: this.host,
256
- chain: POLYGON_CHAIN_ID,
256
+ chain: config_1.POLYMARKET_CHAIN_ID,
257
257
  signer: this.signer,
258
258
  creds: apiCreds,
259
259
  signatureType: finalSignatureType,
@@ -0,0 +1 @@
1
+ export declare const POLYMARKET_CHAIN_ID = 137;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.POLYMARKET_CHAIN_ID = void 0;
4
+ exports.POLYMARKET_CHAIN_ID = 137; // Polygon mainnet
@@ -14,6 +14,7 @@ const api_clob_1 = require("./api-clob");
14
14
  const api_data_1 = require("./api-data");
15
15
  const api_gamma_1 = require("./api-gamma");
16
16
  const auth_1 = require("./auth");
17
+ const config_1 = require("./config");
17
18
  const logger_1 = require("../../utils/logger");
18
19
  const errors_2 = require("./errors");
19
20
  const fetcher_1 = require("./fetcher");
@@ -629,7 +630,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
629
630
  // Static network avoids ethers v5 auto-detect (eth_chainId), which can throw
630
631
  // noNetwork / NETWORK_ERROR on flaky public RPCs (#92).
631
632
  const provider = new ethers.providers.StaticJsonRpcProvider('https://polygon-rpc.com', {
632
- chainId: 137,
633
+ chainId: config_1.POLYMARKET_CHAIN_ID,
633
634
  name: 'matic',
634
635
  });
635
636
  const pusdAddress = '0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB'; // pUSD (Polymarket USD)
@@ -16,6 +16,7 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.PolymarketUSWebSocket = void 0;
19
+ const logger_1 = require("../../utils/logger");
19
20
  const watch_timeout_1 = require("../../utils/watch-timeout");
20
21
  const price_1 = require("./price");
21
22
  function sideFromOrderSide(raw) {
@@ -96,8 +97,8 @@ class PolymarketUSWebSocket {
96
97
  try {
97
98
  this.socket.close();
98
99
  }
99
- catch {
100
- // Ignore close errors.
100
+ catch (error) {
101
+ logger_1.logger.debug('[polymarket_us] error during socket close', { error: String(error) });
101
102
  }
102
103
  this.socket = null;
103
104
  }
@@ -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-06-02T16:35:55.837Z
3
+ * Generated at: 2026-06-08T19:06:11.866Z
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-06-02T16:35:55.837Z
6
+ * Generated at: 2026-06-08T19:06:11.866Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -5,6 +5,7 @@ const clob_1 = require("@prob/clob");
5
5
  const accounts_1 = require("viem/accounts");
6
6
  const viem_1 = require("viem");
7
7
  const chains_1 = require("viem/chains");
8
+ const config_1 = require("./config");
8
9
  /**
9
10
  * Manages Probable authentication and CLOB client initialization.
10
11
  * Requires a privateKey and pre-generated API key triplet (apiKey, apiSecret, passphrase).
@@ -29,8 +30,8 @@ class ProbableAuth {
29
30
  if (this.clobClient) {
30
31
  return this.clobClient;
31
32
  }
32
- const chainId = parseInt(process.env.PROBABLE_CHAIN_ID || '56', 10);
33
- const chain = chainId === 97 ? chains_1.bscTestnet : chains_1.bsc;
33
+ const chainId = parseInt(process.env.PROBABLE_CHAIN_ID || String(config_1.PROBABLE_CHAIN_ID), 10);
34
+ const chain = chainId === config_1.PROBABLE_TESTNET_CHAIN_ID ? chains_1.bscTestnet : chains_1.bsc;
34
35
  const account = (0, accounts_1.privateKeyToAccount)(this.credentials.privateKey);
35
36
  const wallet = (0, viem_1.createWalletClient)({
36
37
  account,
@@ -45,9 +46,9 @@ class ProbableAuth {
45
46
  // @prob/clob may resolve a different viem copy than this package; types then
46
47
  // disagree on WalletClient. Runtime shape is identical.
47
48
  const walletForClob = wallet;
48
- if (chainId === 56) {
49
+ if (chainId === config_1.PROBABLE_CHAIN_ID) {
49
50
  this.clobClient = (0, clob_1.createClobClient)({
50
- chainId: 56,
51
+ chainId: config_1.PROBABLE_CHAIN_ID,
51
52
  wallet: walletForClob,
52
53
  credential,
53
54
  });
@@ -0,0 +1,2 @@
1
+ export declare const PROBABLE_CHAIN_ID = 56;
2
+ export declare const PROBABLE_TESTNET_CHAIN_ID = 97;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROBABLE_TESTNET_CHAIN_ID = exports.PROBABLE_CHAIN_ID = void 0;
4
+ exports.PROBABLE_CHAIN_ID = 56; // BSC mainnet
5
+ exports.PROBABLE_TESTNET_CHAIN_ID = 97; // BSC testnet
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProbableWebSocket = void 0;
4
4
  const watch_timeout_1 = require("../../utils/watch-timeout");
5
+ const config_1 = require("./config");
5
6
  /**
6
7
  * Probable WebSocket implementation for real-time order book streaming.
7
8
  * Uses the @prob/clob SDK's subscribePublicStream (no auth required).
@@ -19,7 +20,7 @@ class ProbableWebSocket {
19
20
  async ensureClient() {
20
21
  if (this.client)
21
22
  return this.client;
22
- const chainId = this.config.chainId || parseInt(process.env.PROBABLE_CHAIN_ID || '56', 10);
23
+ const chainId = this.config.chainId || parseInt(process.env.PROBABLE_CHAIN_ID || String(config_1.PROBABLE_CHAIN_ID), 10);
23
24
  const wsUrl = this.config.wsUrl || process.env.PROBABLE_WS_URL || 'wss://ws.probable.markets/public/api/v1';
24
25
  const baseUrl = this.config.baseUrl || process.env.PROBABLE_BASE_URL || 'https://api.probable.markets/public/api/v1';
25
26
  // Dynamically import @prob/clob using eval to bypass TS compilation to require()
@@ -5,7 +5,7 @@
5
5
  * It is NOT wired into defineImplicitApi — the fetcher calls these endpoints
6
6
  * directly via FetcherContext.http (the rate-limited HTTP client).
7
7
  *
8
- * Base URL: https://suibets.replit.app
8
+ * Base URL: https://www.suibets.com
9
9
  *
10
10
  * Endpoints:
11
11
  * GET /api/p2p/offers - List open P2P offers (status, matchId, sport, limit, offset)
@@ -6,7 +6,7 @@
6
6
  * It is NOT wired into defineImplicitApi — the fetcher calls these endpoints
7
7
  * directly via FetcherContext.http (the rate-limited HTTP client).
8
8
  *
9
- * Base URL: https://suibets.replit.app
9
+ * Base URL: https://www.suibets.com
10
10
  *
11
11
  * Endpoints:
12
12
  * GET /api/p2p/offers - List open P2P offers (status, matchId, sport, limit, offset)
@@ -1,4 +1,4 @@
1
- export declare const SUIBETS_BASE_URL = "https://suibets.replit.app";
1
+ export declare const SUIBETS_BASE_URL = "https://www.suibets.com";
2
2
  export declare const SUIBETS_PLATFORM_FEE = 0.02;
3
3
  export declare const MIST_PER_SUI = 1000000000;
4
4
  export declare const MIN_PRICE = 0.01;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ALLOWED_HOSTS = exports.RATE_LIMIT_MS = exports.MAX_PRICE = exports.MIN_PRICE = exports.MIST_PER_SUI = exports.SUIBETS_PLATFORM_FEE = exports.SUIBETS_BASE_URL = void 0;
4
4
  exports.validateBaseUrl = validateBaseUrl;
5
5
  exports.getSuibetsConfig = getSuibetsConfig;
6
- exports.SUIBETS_BASE_URL = 'https://suibets.replit.app';
6
+ exports.SUIBETS_BASE_URL = 'https://www.suibets.com';
7
7
  // SuiBets is a P2P sports betting platform on Sui blockchain.
8
8
  // Platform takes a 2% fee on settled markets.
9
9
  exports.SUIBETS_PLATFORM_FEE = 0.02;
@@ -15,7 +15,7 @@ exports.MAX_PRICE = 0.99;
15
15
  // Minimum delay between outbound requests (milliseconds)
16
16
  exports.RATE_LIMIT_MS = 300;
17
17
  // Allowlist of permitted hostnames for SSRF protection
18
- exports.ALLOWED_HOSTS = ['suibets.replit.app'];
18
+ exports.ALLOWED_HOSTS = ['www.suibets.com'];
19
19
  /**
20
20
  * Validates that the given URL's hostname is in the ALLOWED_HOSTS allowlist.
21
21
  * Throws if the hostname is not permitted, to prevent SSRF.
@@ -41,6 +41,15 @@ class SuibetsErrorMapper extends error_mapper_1.ErrorMapper {
41
41
  mapError(error) {
42
42
  if (axios_1.default.isAxiosError(error)) {
43
43
  const status = error.response?.status;
44
+ // HTML body = hosting/gateway outage — not a missing resource.
45
+ // Return ExchangeNotAvailable so callers can distinguish
46
+ // "offer not found" from "upstream server is down".
47
+ const responseData = error.response?.data;
48
+ const isHtml = typeof responseData === 'string' &&
49
+ responseData.trimStart().startsWith('<');
50
+ if (isHtml) {
51
+ return new errors_1.ExchangeNotAvailable('SuiBets API is unavailable. Check https://www.suibets.com for service status.', this.exchangeName);
52
+ }
44
53
  if (status === 429) {
45
54
  const retryAfter = error.response?.headers?.['retry-after'];
46
55
  const retryAfterSeconds = retryAfter ? parseInt(retryAfter, 10) : undefined;
@@ -33,7 +33,24 @@ export interface SuibetsRawEvent {
33
33
  status: string;
34
34
  offers?: SuibetsRawOffer[];
35
35
  }
36
- export declare class SuibetsFetcher implements IExchangeFetcher<SuibetsRawOffer, SuibetsRawEvent> {
36
+ /**
37
+ * Structured return type for fetchRawPositions.
38
+ * Keeps the three position-array types separate so each is normalised
39
+ * with the correct shape instead of being cast from unknown[].
40
+ */
41
+ export interface SuibetsRawPositions {
42
+ createdOffers: SuibetsRawOffer[];
43
+ matchedBets: unknown[];
44
+ parlays: unknown[];
45
+ }
46
+ /**
47
+ * Type guard: true only when the value has the core fields that
48
+ * SuibetsNormalizer.normalizePosition() reads (id, creatorOdds, creatorStake).
49
+ * Guards against silent garbage output when matchedBets or parlays
50
+ * are accidentally passed in as SuibetsRawOffer.
51
+ */
52
+ export declare function isSuibetsRawOffer(value: unknown): value is SuibetsRawOffer;
53
+ export declare class SuibetsFetcher implements IExchangeFetcher<SuibetsRawOffer, SuibetsRawEvent, SuibetsRawPositions> {
37
54
  private readonly ctx;
38
55
  private readonly baseUrl;
39
56
  constructor(ctx: FetcherContext, baseUrl: string);
@@ -59,6 +76,9 @@ export declare class SuibetsFetcher implements IExchangeFetcher<SuibetsRawOffer,
59
76
  /**
60
77
  * Fetches raw positions (created offers, matched bets, parlays) for a
61
78
  * given Sui wallet address.
79
+ *
80
+ * Returns each array separately and typed so that normalisation uses
81
+ * the correct shape per position type rather than casting from unknown[].
62
82
  */
63
- fetchRawPositions(walletAddress: string): Promise<unknown[]>;
83
+ fetchRawPositions(walletAddress: string): Promise<SuibetsRawPositions>;
64
84
  }
@@ -1,7 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SuibetsFetcher = void 0;
4
+ exports.isSuibetsRawOffer = isSuibetsRawOffer;
4
5
  const errors_1 = require("./errors");
6
+ /**
7
+ * Type guard: true only when the value has the core fields that
8
+ * SuibetsNormalizer.normalizePosition() reads (id, creatorOdds, creatorStake).
9
+ * Guards against silent garbage output when matchedBets or parlays
10
+ * are accidentally passed in as SuibetsRawOffer.
11
+ */
12
+ function isSuibetsRawOffer(value) {
13
+ if (typeof value !== 'object' || value === null)
14
+ return false;
15
+ const v = value;
16
+ return ((typeof v['id'] === 'string' || typeof v['id'] === 'number') &&
17
+ typeof v['creatorOdds'] === 'number' &&
18
+ typeof v['creatorStake'] === 'number');
19
+ }
5
20
  class SuibetsFetcher {
6
21
  ctx;
7
22
  baseUrl;
@@ -115,14 +130,17 @@ class SuibetsFetcher {
115
130
  /**
116
131
  * Fetches raw positions (created offers, matched bets, parlays) for a
117
132
  * given Sui wallet address.
133
+ *
134
+ * Returns each array separately and typed so that normalisation uses
135
+ * the correct shape per position type rather than casting from unknown[].
118
136
  */
119
137
  async fetchRawPositions(walletAddress) {
120
138
  const data = await this.get('/api/p2p/my', { wallet: walletAddress });
121
- return [
122
- ...(data.createdOffers ?? []),
123
- ...(data.matchedBets ?? []),
124
- ...(data.parlays ?? []),
125
- ];
139
+ return {
140
+ createdOffers: (data.createdOffers ?? []).filter(isSuibetsRawOffer),
141
+ matchedBets: data.matchedBets ?? [],
142
+ parlays: data.parlays ?? [],
143
+ };
126
144
  }
127
145
  }
128
146
  exports.SuibetsFetcher = SuibetsFetcher;
@@ -3,7 +3,7 @@ import { UnifiedMarket, UnifiedEvent, OrderBook, Position } from '../../types';
3
3
  export interface SuibetsCredentials extends ExchangeCredentials {
4
4
  /** Sui wallet address for fetching personal positions */
5
5
  walletAddress?: string;
6
- /** Override API base URL (default: https://suibets.replit.app) */
6
+ /** Override API base URL (default: https://www.suibets.com) */
7
7
  baseUrl?: string;
8
8
  }
9
9
  /**
@@ -113,7 +113,7 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
113
113
  'Pass it via new SuiBetsExchange({ walletAddress: "0x..." }).', 'SuiBets');
114
114
  }
115
115
  const raw = await this.fetcher.fetchRawPositions(wallet);
116
- return raw.map(r => this.normalizer.normalizePosition(r));
116
+ return raw.createdOffers.map(r => this.normalizer.normalizePosition(r));
117
117
  }
118
118
  }
119
119
  exports.SuiBetsExchange = SuiBetsExchange;