pmxtjs 2.49.6 → 2.49.8

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.
@@ -40,6 +40,26 @@ export interface OrderBook {
40
40
  * @memberof OrderBook
41
41
  */
42
42
  datetime?: string;
43
+ /**
44
+ * Whether the venue marks this snapshot as a negative-risk market.
45
+ * @type {boolean}
46
+ * @memberof OrderBook
47
+ */
48
+ isNegRisk?: boolean;
49
+ /**
50
+ * Last traded price from venues that include it with the book snapshot.
51
+ * @type {number}
52
+ * @memberof OrderBook
53
+ */
54
+ lastTradePrice?: number;
55
+ /**
56
+ * Venue-specific metadata preserved from the raw order book snapshot.
57
+ * @type {{ [key: string]: any; }}
58
+ * @memberof OrderBook
59
+ */
60
+ sourceMetadata?: {
61
+ [key: string]: any;
62
+ };
43
63
  }
44
64
  /**
45
65
  * Check if a given object implements the OrderBook interface.
@@ -34,6 +34,9 @@ export function OrderBookFromJSONTyped(json, ignoreDiscriminator) {
34
34
  'asks': (json['asks'].map(OrderLevelFromJSON)),
35
35
  'timestamp': json['timestamp'] == null ? undefined : json['timestamp'],
36
36
  'datetime': json['datetime'] == null ? undefined : json['datetime'],
37
+ 'isNegRisk': json['isNegRisk'] == null ? undefined : json['isNegRisk'],
38
+ 'lastTradePrice': json['lastTradePrice'] == null ? undefined : json['lastTradePrice'],
39
+ 'sourceMetadata': json['sourceMetadata'] == null ? undefined : json['sourceMetadata'],
37
40
  };
38
41
  }
39
42
  export function OrderBookToJSON(json) {
@@ -48,5 +51,8 @@ export function OrderBookToJSONTyped(value, ignoreDiscriminator = false) {
48
51
  'asks': (value['asks'].map(OrderLevelToJSON)),
49
52
  'timestamp': value['timestamp'],
50
53
  'datetime': value['datetime'],
54
+ 'isNegRisk': value['isNegRisk'],
55
+ 'lastTradePrice': value['lastTradePrice'],
56
+ 'sourceMetadata': value['sourceMetadata'],
51
57
  };
52
58
  }
@@ -23,7 +23,7 @@ import { ServerManager } from "./pmxt/server-manager.js";
23
23
  import { FeedClient } from "./pmxt/feed-client.js";
24
24
  import * as models from "./pmxt/models.js";
25
25
  import * as errors from "./pmxt/errors.js";
26
- export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock, PolymarketOptions } from "./pmxt/client.js";
26
+ export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock, PolymarketOptions } from "./pmxt/client.js";
27
27
  export { FeedClient } from "./pmxt/feed-client.js";
28
28
  export type { Ticker, Tickers, OHLCV, Market as FeedMarket, OracleRound, FeedClientOptions } from "./pmxt/feed-client.js";
29
29
  export { Router } from "./pmxt/router.js";
@@ -95,6 +95,7 @@ declare const pmxt: {
95
95
  GeminiTitan: typeof GeminiTitan;
96
96
  Hyperliquid: typeof Hyperliquid;
97
97
  SuiBets: typeof SuiBets;
98
+ Suibets: typeof SuiBets;
98
99
  Mock: typeof Mock;
99
100
  Router: typeof Router;
100
101
  ServerManager: typeof ServerManager;
package/dist/esm/index.js CHANGED
@@ -17,13 +17,13 @@
17
17
  * console.log(markets[0].title);
18
18
  * ```
19
19
  */
20
- import { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock } from "./pmxt/client.js";
20
+ import { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock } from "./pmxt/client.js";
21
21
  import { Router } from "./pmxt/router.js";
22
22
  import { ServerManager } from "./pmxt/server-manager.js";
23
23
  import { FeedClient } from "./pmxt/feed-client.js";
24
24
  import * as models from "./pmxt/models.js";
25
25
  import * as errors from "./pmxt/errors.js";
26
- export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock } from "./pmxt/client.js";
26
+ export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock } from "./pmxt/client.js";
27
27
  export { FeedClient } from "./pmxt/feed-client.js";
28
28
  export { Router } from "./pmxt/router.js";
29
29
  export { ServerManager } from "./pmxt/server-manager.js";
@@ -76,6 +76,7 @@ const pmxt = {
76
76
  GeminiTitan,
77
77
  Hyperliquid,
78
78
  SuiBets,
79
+ Suibets,
79
80
  Mock,
80
81
  Router,
81
82
  ServerManager,
@@ -837,6 +837,7 @@ export declare class SuiBets extends Exchange {
837
837
  */
838
838
  protected getCredentials(): ExchangeCredentials | undefined;
839
839
  }
840
+ export declare const Suibets: typeof SuiBets;
840
841
  /**
841
842
  * Mock exchange client.
842
843
  *
@@ -10,6 +10,7 @@ import { ServerManager } from "./server-manager.js";
10
10
  import { PmxtError, fromServerError, InvalidOrder, NotSupported } from "./errors.js";
11
11
  import { resolvePmxtBaseUrl } from "./constants.js";
12
12
  import { SidecarWsClient } from "./ws-client.js";
13
+ import { logger } from "./logger.js";
13
14
  // Hosted-mode trading dispatch.
14
15
  // These modules are introduced as part of the hosted trading mode rollout.
15
16
  // Some of them may be authored by parallel agents; until they all land, the
@@ -364,8 +365,8 @@ export class Exchange {
364
365
  try {
365
366
  await this.serverManager.ensureServerRunning();
366
367
  }
367
- catch {
368
- // Restart failed continue retrying anyway
368
+ catch (err) {
369
+ logger.warn('PmxtClient: server restart failed during retry', { attempt, error: String(err) });
369
370
  }
370
371
  }
371
372
  await new Promise(resolve => setTimeout(resolve, delays[attempt]));
@@ -405,7 +406,8 @@ export class Exchange {
405
406
  throw new Error("WS handshake failed");
406
407
  }
407
408
  }
408
- catch {
409
+ catch (err) {
410
+ logger.warn('PmxtClient: WebSocket probe failed, falling back to HTTP', { error: String(err) });
409
411
  this._wsUnsupported = true;
410
412
  client.close();
411
413
  return null;
@@ -923,6 +925,9 @@ export class Exchange {
923
925
  return this._hostedSubmitOrder(built);
924
926
  }
925
927
  await this.initPromise;
928
+ if (this.isHosted) {
929
+ throw new PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.");
930
+ }
926
931
  try {
927
932
  const args = [];
928
933
  args.push(built);
@@ -2111,7 +2116,8 @@ export class Exchange {
2111
2116
  this._hostedAccount = {};
2112
2117
  }
2113
2118
  }
2114
- catch {
2119
+ catch (err) {
2120
+ logger.warn('PmxtClient: hosted account discovery failed', { error: String(err) });
2115
2121
  this._hostedAccount = {};
2116
2122
  }
2117
2123
  })();
@@ -2988,6 +2994,8 @@ export class SuiBets extends Exchange {
2988
2994
  };
2989
2995
  }
2990
2996
  }
2997
+ // Backwards-compatible casing alias matching the Python SDK export.
2998
+ export const Suibets = SuiBets;
2991
2999
  /**
2992
3000
  * Mock exchange client.
2993
3001
  *
@@ -96,7 +96,11 @@ export function userTradeFromV0(payload) {
96
96
  const trade = {
97
97
  id: strOrEmpty(payload["id"]),
98
98
  price: floatOrZero(payload["price"]),
99
- amount: floatOrZero(payload["amount"]),
99
+ // The v0 wire sends trade amounts in 6-dec micro-shares (verified
100
+ // live: 58139533.0 == 58.139533 shares, matching the same position's
101
+ // decimal `shares`). Normalize so UserTrade.amount means shares,
102
+ // like everywhere else in the SDK.
103
+ amount: floatOrZero(payload["amount"]) / 1_000_000,
100
104
  side,
101
105
  timestamp: timestampToMs(payload["timestamp"]),
102
106
  };
@@ -116,7 +120,8 @@ export function userTradeToV0(trade) {
116
120
  const out = {
117
121
  id: trade.id,
118
122
  side: trade.side,
119
- amount: trade.amount,
123
+ // Inverse of userTradeFromV0: decimal shares -> 6-dec micro-shares.
124
+ amount: Math.round(trade.amount * 1_000_000),
120
125
  price: trade.price,
121
126
  timestamp: msToTimestamp(trade.timestamp),
122
127
  };
@@ -313,6 +313,18 @@ const SIX_DEC_DIVISOR = 1_000_000;
313
313
  function validateWorstPrice(message, route, buildRequest, buildResponse) {
314
314
  const worstPriceMicro = messageBigInt(message, "worst_price", "worstPrice");
315
315
  const worstPrice = Number(worstPriceMicro) / SIX_DEC_DIVISOR;
316
+ // Hosted MARKET orders pin worst_price to the tick-grid extreme by
317
+ // design ("textbook market semantics"): the binding user protection is
318
+ // max_cost_usdc (buys) / shares_6dec (sells), validated above. A
319
+ // slippage bound on worst_price would reject every server-built market
320
+ // order, so only sanity-check the price domain here.
321
+ const orderType = String(firstPresent(getField(buildRequest, "order_type"), getField(buildRequest, "orderType"), "market")).toLowerCase();
322
+ if (orderType === "market") {
323
+ if (!(worstPrice > 0 && worstPrice < 1)) {
324
+ economicFail(`worst_price expected within (0, 1) got ${worstPrice}`);
325
+ }
326
+ return;
327
+ }
316
328
  const slippagePctRaw = firstPresent(getField(buildRequest, "slippage_pct"), getField(buildRequest, "slippagePct"), getField(buildResponse, "slippage_pct"), getField(buildResponse, "slippagePct"), 20);
317
329
  const slippagePct = toFiniteNumber(slippagePctRaw, "slippage_pct");
318
330
  if (route === "polymarket_buy") {
@@ -44,6 +44,8 @@ export declare class Router extends Exchange {
44
44
  marketId?: string;
45
45
  slug?: string;
46
46
  url?: string;
47
+ query?: string;
48
+ category?: string;
47
49
  relation?: MatchRelation;
48
50
  minConfidence?: number;
49
51
  limit?: number;
@@ -58,6 +60,8 @@ export declare class Router extends Exchange {
58
60
  marketId?: string;
59
61
  slug?: string;
60
62
  url?: string;
63
+ query?: string;
64
+ category?: string;
61
65
  relation?: MatchRelation;
62
66
  minConfidence?: number;
63
67
  limit?: number;
@@ -73,6 +77,8 @@ export declare class Router extends Exchange {
73
77
  event?: UnifiedEvent;
74
78
  eventId?: string;
75
79
  slug?: string;
80
+ query?: string;
81
+ category?: string;
76
82
  relation?: MatchRelation;
77
83
  minConfidence?: number;
78
84
  limit?: number;
@@ -166,6 +166,10 @@ export class Router extends Exchange {
166
166
  query.slug = params.slug ?? params.market?.slug;
167
167
  if (params.url)
168
168
  query.url = params.url;
169
+ if (params.query)
170
+ query.query = params.query;
171
+ if (params.category)
172
+ query.category = params.category;
169
173
  if (params.relation)
170
174
  query.relation = params.relation;
171
175
  if (params.minConfidence !== undefined)
@@ -203,6 +207,10 @@ export class Router extends Exchange {
203
207
  query.eventId = eventId;
204
208
  if (params.slug ?? params.event?.slug)
205
209
  query.slug = params.slug ?? params.event?.slug;
210
+ if (params.query)
211
+ query.query = params.query;
212
+ if (params.category)
213
+ query.category = params.category;
206
214
  if (params.relation)
207
215
  query.relation = params.relation;
208
216
  if (params.minConfidence !== undefined)
@@ -7,6 +7,7 @@ import { DefaultApi, Configuration } from "../generated/src/index.js";
7
7
  import { readFileSync, existsSync } from "fs";
8
8
  import { homedir } from "os";
9
9
  import { join, dirname } from "path";
10
+ import { logger } from "./logger.js";
10
11
  export class ServerManager {
11
12
  baseUrl;
12
13
  maxRetries;
@@ -123,8 +124,8 @@ export class ServerManager {
123
124
  return;
124
125
  }
125
126
  }
126
- catch {
127
- // Not ready yet
127
+ catch (err) {
128
+ logger.debug('server-manager: health poll error', { error: String(err) });
128
129
  }
129
130
  }
130
131
  await new Promise((resolve) => setTimeout(resolve, this.retryDelayMs));
@@ -230,8 +231,8 @@ export class ServerManager {
230
231
  }
231
232
  }
232
233
  }
233
- catch {
234
- // Ignore errors
234
+ catch (err) {
235
+ logger.warn('server-manager: version check failed', { error: String(err) });
235
236
  }
236
237
  return false;
237
238
  }
@@ -343,6 +344,9 @@ export class ServerManager {
343
344
  const { unlinkSync } = await import('fs');
344
345
  unlinkSync(this.lockPath);
345
346
  }
346
- catch { }
347
+ catch (err) {
348
+ // Best-effort — expected when file was already removed.
349
+ logger.debug('server-manager: lock file removal failed', { path: this.lockPath, error: String(err) });
350
+ }
347
351
  }
348
352
  }
@@ -273,8 +273,8 @@ export class SidecarWsClient {
273
273
  try {
274
274
  this.ws.close();
275
275
  }
276
- catch {
277
- // ignore
276
+ catch (err) {
277
+ logger.debug('[SidecarWsClient] error during ws.close()', { error: String(err) });
278
278
  }
279
279
  this.ws = null;
280
280
  }
@@ -40,6 +40,26 @@ export interface OrderBook {
40
40
  * @memberof OrderBook
41
41
  */
42
42
  datetime?: string;
43
+ /**
44
+ * Whether the venue marks this snapshot as a negative-risk market.
45
+ * @type {boolean}
46
+ * @memberof OrderBook
47
+ */
48
+ isNegRisk?: boolean;
49
+ /**
50
+ * Last traded price from venues that include it with the book snapshot.
51
+ * @type {number}
52
+ * @memberof OrderBook
53
+ */
54
+ lastTradePrice?: number;
55
+ /**
56
+ * Venue-specific metadata preserved from the raw order book snapshot.
57
+ * @type {{ [key: string]: any; }}
58
+ * @memberof OrderBook
59
+ */
60
+ sourceMetadata?: {
61
+ [key: string]: any;
62
+ };
43
63
  }
44
64
  /**
45
65
  * Check if a given object implements the OrderBook interface.
@@ -41,6 +41,9 @@ function OrderBookFromJSONTyped(json, ignoreDiscriminator) {
41
41
  'asks': (json['asks'].map(OrderLevel_1.OrderLevelFromJSON)),
42
42
  'timestamp': json['timestamp'] == null ? undefined : json['timestamp'],
43
43
  'datetime': json['datetime'] == null ? undefined : json['datetime'],
44
+ 'isNegRisk': json['isNegRisk'] == null ? undefined : json['isNegRisk'],
45
+ 'lastTradePrice': json['lastTradePrice'] == null ? undefined : json['lastTradePrice'],
46
+ 'sourceMetadata': json['sourceMetadata'] == null ? undefined : json['sourceMetadata'],
44
47
  };
45
48
  }
46
49
  function OrderBookToJSON(json) {
@@ -55,5 +58,8 @@ function OrderBookToJSONTyped(value, ignoreDiscriminator = false) {
55
58
  'asks': (value['asks'].map(OrderLevel_1.OrderLevelToJSON)),
56
59
  'timestamp': value['timestamp'],
57
60
  'datetime': value['datetime'],
61
+ 'isNegRisk': value['isNegRisk'],
62
+ 'lastTradePrice': value['lastTradePrice'],
63
+ 'sourceMetadata': value['sourceMetadata'],
58
64
  };
59
65
  }
package/dist/index.d.ts CHANGED
@@ -23,7 +23,7 @@ import { ServerManager } from "./pmxt/server-manager.js";
23
23
  import { FeedClient } from "./pmxt/feed-client.js";
24
24
  import * as models from "./pmxt/models.js";
25
25
  import * as errors from "./pmxt/errors.js";
26
- export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock, PolymarketOptions } from "./pmxt/client.js";
26
+ export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock, PolymarketOptions } from "./pmxt/client.js";
27
27
  export { FeedClient } from "./pmxt/feed-client.js";
28
28
  export type { Ticker, Tickers, OHLCV, Market as FeedMarket, OracleRound, FeedClientOptions } from "./pmxt/feed-client.js";
29
29
  export { Router } from "./pmxt/router.js";
@@ -95,6 +95,7 @@ declare const pmxt: {
95
95
  GeminiTitan: typeof GeminiTitan;
96
96
  Hyperliquid: typeof Hyperliquid;
97
97
  SuiBets: typeof SuiBets;
98
+ Suibets: typeof SuiBets;
98
99
  Mock: typeof Mock;
99
100
  Router: typeof Router;
100
101
  ServerManager: typeof ServerManager;
package/dist/index.js CHANGED
@@ -55,7 +55,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
55
55
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
56
56
  };
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
- exports.server = exports.MarketList = exports.resolvePmxtBaseUrl = exports.ENV = exports.LOCAL_URL = exports.HOSTED_URL = exports.ServerManager = exports.Router = exports.FeedClient = exports.Mock = exports.SuiBets = exports.Hyperliquid = exports.GeminiTitan = exports.PolymarketUS = exports.Smarkets = exports.Metaculus = exports.Opinion = exports.Baozi = exports.Probable = exports.Myriad = exports.Limitless = exports.KalshiDemo = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
58
+ exports.server = exports.MarketList = exports.resolvePmxtBaseUrl = exports.ENV = exports.LOCAL_URL = exports.HOSTED_URL = exports.ServerManager = exports.Router = exports.FeedClient = exports.Mock = exports.Suibets = exports.SuiBets = exports.Hyperliquid = exports.GeminiTitan = exports.PolymarketUS = exports.Smarkets = exports.Metaculus = exports.Opinion = exports.Baozi = exports.Probable = exports.Myriad = exports.Limitless = exports.KalshiDemo = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
59
59
  const client_js_1 = require("./pmxt/client.js");
60
60
  const router_js_1 = require("./pmxt/router.js");
61
61
  const server_manager_js_1 = require("./pmxt/server-manager.js");
@@ -78,6 +78,7 @@ Object.defineProperty(exports, "PolymarketUS", { enumerable: true, get: function
78
78
  Object.defineProperty(exports, "GeminiTitan", { enumerable: true, get: function () { return client_js_2.GeminiTitan; } });
79
79
  Object.defineProperty(exports, "Hyperliquid", { enumerable: true, get: function () { return client_js_2.Hyperliquid; } });
80
80
  Object.defineProperty(exports, "SuiBets", { enumerable: true, get: function () { return client_js_2.SuiBets; } });
81
+ Object.defineProperty(exports, "Suibets", { enumerable: true, get: function () { return client_js_2.Suibets; } });
81
82
  Object.defineProperty(exports, "Mock", { enumerable: true, get: function () { return client_js_2.Mock; } });
82
83
  var feed_client_js_2 = require("./pmxt/feed-client.js");
83
84
  Object.defineProperty(exports, "FeedClient", { enumerable: true, get: function () { return feed_client_js_2.FeedClient; } });
@@ -139,6 +140,7 @@ const pmxt = {
139
140
  GeminiTitan: client_js_1.GeminiTitan,
140
141
  Hyperliquid: client_js_1.Hyperliquid,
141
142
  SuiBets: client_js_1.SuiBets,
143
+ Suibets: client_js_1.Suibets,
142
144
  Mock: client_js_1.Mock,
143
145
  Router: router_js_1.Router,
144
146
  ServerManager: server_manager_js_1.ServerManager,
@@ -837,6 +837,7 @@ export declare class SuiBets extends Exchange {
837
837
  */
838
838
  protected getCredentials(): ExchangeCredentials | undefined;
839
839
  }
840
+ export declare const Suibets: typeof SuiBets;
840
841
  /**
841
842
  * Mock exchange client.
842
843
  *
@@ -6,13 +6,14 @@
6
6
  * OpenAPI client, matching the Python API exactly.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.Mock = exports.SuiBets = exports.Hyperliquid = exports.GeminiTitan = exports.PolymarketUS = exports.Smarkets = exports.Metaculus = exports.Opinion = exports.Baozi = exports.Probable = exports.Myriad = exports.KalshiDemo = exports.Limitless = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
9
+ exports.Mock = exports.Suibets = exports.SuiBets = exports.Hyperliquid = exports.GeminiTitan = exports.PolymarketUS = exports.Smarkets = exports.Metaculus = exports.Opinion = exports.Baozi = exports.Probable = exports.Myriad = exports.KalshiDemo = exports.Limitless = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
10
10
  const index_js_1 = require("../generated/src/index.js");
11
11
  const models_js_1 = require("./models.js");
12
12
  const server_manager_js_1 = require("./server-manager.js");
13
13
  const errors_js_1 = require("./errors.js");
14
14
  const constants_js_1 = require("./constants.js");
15
15
  const ws_client_js_1 = require("./ws-client.js");
16
+ const logger_js_1 = require("./logger.js");
16
17
  // Hosted-mode trading dispatch.
17
18
  // These modules are introduced as part of the hosted trading mode rollout.
18
19
  // Some of them may be authored by parallel agents; until they all land, the
@@ -367,8 +368,8 @@ class Exchange {
367
368
  try {
368
369
  await this.serverManager.ensureServerRunning();
369
370
  }
370
- catch {
371
- // Restart failed continue retrying anyway
371
+ catch (err) {
372
+ logger_js_1.logger.warn('PmxtClient: server restart failed during retry', { attempt, error: String(err) });
372
373
  }
373
374
  }
374
375
  await new Promise(resolve => setTimeout(resolve, delays[attempt]));
@@ -408,7 +409,8 @@ class Exchange {
408
409
  throw new Error("WS handshake failed");
409
410
  }
410
411
  }
411
- catch {
412
+ catch (err) {
413
+ logger_js_1.logger.warn('PmxtClient: WebSocket probe failed, falling back to HTTP', { error: String(err) });
412
414
  this._wsUnsupported = true;
413
415
  client.close();
414
416
  return null;
@@ -926,6 +928,9 @@ class Exchange {
926
928
  return this._hostedSubmitOrder(built);
927
929
  }
928
930
  await this.initPromise;
931
+ if (this.isHosted) {
932
+ throw new errors_js_1.PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.");
933
+ }
929
934
  try {
930
935
  const args = [];
931
936
  args.push(built);
@@ -2114,7 +2119,8 @@ class Exchange {
2114
2119
  this._hostedAccount = {};
2115
2120
  }
2116
2121
  }
2117
- catch {
2122
+ catch (err) {
2123
+ logger_js_1.logger.warn('PmxtClient: hosted account discovery failed', { error: String(err) });
2118
2124
  this._hostedAccount = {};
2119
2125
  }
2120
2126
  })();
@@ -3006,6 +3012,8 @@ class SuiBets extends Exchange {
3006
3012
  }
3007
3013
  }
3008
3014
  exports.SuiBets = SuiBets;
3015
+ // Backwards-compatible casing alias matching the Python SDK export.
3016
+ exports.Suibets = SuiBets;
3009
3017
  /**
3010
3018
  * Mock exchange client.
3011
3019
  *
@@ -107,7 +107,11 @@ function userTradeFromV0(payload) {
107
107
  const trade = {
108
108
  id: strOrEmpty(payload["id"]),
109
109
  price: floatOrZero(payload["price"]),
110
- amount: floatOrZero(payload["amount"]),
110
+ // The v0 wire sends trade amounts in 6-dec micro-shares (verified
111
+ // live: 58139533.0 == 58.139533 shares, matching the same position's
112
+ // decimal `shares`). Normalize so UserTrade.amount means shares,
113
+ // like everywhere else in the SDK.
114
+ amount: floatOrZero(payload["amount"]) / 1_000_000,
111
115
  side,
112
116
  timestamp: timestampToMs(payload["timestamp"]),
113
117
  };
@@ -127,7 +131,8 @@ function userTradeToV0(trade) {
127
131
  const out = {
128
132
  id: trade.id,
129
133
  side: trade.side,
130
- amount: trade.amount,
134
+ // Inverse of userTradeFromV0: decimal shares -> 6-dec micro-shares.
135
+ amount: Math.round(trade.amount * 1_000_000),
131
136
  price: trade.price,
132
137
  timestamp: msToTimestamp(trade.timestamp),
133
138
  };
@@ -352,6 +352,18 @@ const SIX_DEC_DIVISOR = 1_000_000;
352
352
  function validateWorstPrice(message, route, buildRequest, buildResponse) {
353
353
  const worstPriceMicro = messageBigInt(message, "worst_price", "worstPrice");
354
354
  const worstPrice = Number(worstPriceMicro) / SIX_DEC_DIVISOR;
355
+ // Hosted MARKET orders pin worst_price to the tick-grid extreme by
356
+ // design ("textbook market semantics"): the binding user protection is
357
+ // max_cost_usdc (buys) / shares_6dec (sells), validated above. A
358
+ // slippage bound on worst_price would reject every server-built market
359
+ // order, so only sanity-check the price domain here.
360
+ const orderType = String(firstPresent(getField(buildRequest, "order_type"), getField(buildRequest, "orderType"), "market")).toLowerCase();
361
+ if (orderType === "market") {
362
+ if (!(worstPrice > 0 && worstPrice < 1)) {
363
+ economicFail(`worst_price expected within (0, 1) got ${worstPrice}`);
364
+ }
365
+ return;
366
+ }
355
367
  const slippagePctRaw = firstPresent(getField(buildRequest, "slippage_pct"), getField(buildRequest, "slippagePct"), getField(buildResponse, "slippage_pct"), getField(buildResponse, "slippagePct"), 20);
356
368
  const slippagePct = toFiniteNumber(slippagePctRaw, "slippage_pct");
357
369
  if (route === "polymarket_buy") {
@@ -44,6 +44,8 @@ export declare class Router extends Exchange {
44
44
  marketId?: string;
45
45
  slug?: string;
46
46
  url?: string;
47
+ query?: string;
48
+ category?: string;
47
49
  relation?: MatchRelation;
48
50
  minConfidence?: number;
49
51
  limit?: number;
@@ -58,6 +60,8 @@ export declare class Router extends Exchange {
58
60
  marketId?: string;
59
61
  slug?: string;
60
62
  url?: string;
63
+ query?: string;
64
+ category?: string;
61
65
  relation?: MatchRelation;
62
66
  minConfidence?: number;
63
67
  limit?: number;
@@ -73,6 +77,8 @@ export declare class Router extends Exchange {
73
77
  event?: UnifiedEvent;
74
78
  eventId?: string;
75
79
  slug?: string;
80
+ query?: string;
81
+ category?: string;
76
82
  relation?: MatchRelation;
77
83
  minConfidence?: number;
78
84
  limit?: number;
@@ -202,6 +202,10 @@ class Router extends client_js_1.Exchange {
202
202
  query.slug = params.slug ?? params.market?.slug;
203
203
  if (params.url)
204
204
  query.url = params.url;
205
+ if (params.query)
206
+ query.query = params.query;
207
+ if (params.category)
208
+ query.category = params.category;
205
209
  if (params.relation)
206
210
  query.relation = params.relation;
207
211
  if (params.minConfidence !== undefined)
@@ -239,6 +243,10 @@ class Router extends client_js_1.Exchange {
239
243
  query.eventId = eventId;
240
244
  if (params.slug ?? params.event?.slug)
241
245
  query.slug = params.slug ?? params.event?.slug;
246
+ if (params.query)
247
+ query.query = params.query;
248
+ if (params.category)
249
+ query.category = params.category;
242
250
  if (params.relation)
243
251
  query.relation = params.relation;
244
252
  if (params.minConfidence !== undefined)
@@ -43,6 +43,7 @@ const index_js_1 = require("../generated/src/index.js");
43
43
  const fs_1 = require("fs");
44
44
  const os_1 = require("os");
45
45
  const path_1 = require("path");
46
+ const logger_js_1 = require("./logger.js");
46
47
  class ServerManager {
47
48
  baseUrl;
48
49
  maxRetries;
@@ -159,8 +160,8 @@ class ServerManager {
159
160
  return;
160
161
  }
161
162
  }
162
- catch {
163
- // Not ready yet
163
+ catch (err) {
164
+ logger_js_1.logger.debug('server-manager: health poll error', { error: String(err) });
164
165
  }
165
166
  }
166
167
  await new Promise((resolve) => setTimeout(resolve, this.retryDelayMs));
@@ -266,8 +267,8 @@ class ServerManager {
266
267
  }
267
268
  }
268
269
  }
269
- catch {
270
- // Ignore errors
270
+ catch (err) {
271
+ logger_js_1.logger.warn('server-manager: version check failed', { error: String(err) });
271
272
  }
272
273
  return false;
273
274
  }
@@ -379,7 +380,10 @@ class ServerManager {
379
380
  const { unlinkSync } = await Promise.resolve().then(() => __importStar(require('fs')));
380
381
  unlinkSync(this.lockPath);
381
382
  }
382
- catch { }
383
+ catch (err) {
384
+ // Best-effort — expected when file was already removed.
385
+ logger_js_1.logger.debug('server-manager: lock file removal failed', { path: this.lockPath, error: String(err) });
386
+ }
383
387
  }
384
388
  }
385
389
  exports.ServerManager = ServerManager;
@@ -276,8 +276,8 @@ class SidecarWsClient {
276
276
  try {
277
277
  this.ws.close();
278
278
  }
279
- catch {
280
- // ignore
279
+ catch (err) {
280
+ logger_js_1.logger.debug('[SidecarWsClient] error during ws.close()', { error: String(err) });
281
281
  }
282
282
  this.ws = null;
283
283
  }
@@ -10,6 +10,9 @@ Name | Type
10
10
  `asks` | [Array&lt;OrderLevel&gt;](OrderLevel.md)
11
11
  `timestamp` | number
12
12
  `datetime` | string
13
+ `isNegRisk` | boolean
14
+ `lastTradePrice` | number
15
+ `sourceMetadata` | { [key: string]: object; }
13
16
 
14
17
  ## Example
15
18
 
@@ -22,6 +25,9 @@ const example = {
22
25
  "asks": null,
23
26
  "timestamp": null,
24
27
  "datetime": null,
28
+ "isNegRisk": null,
29
+ "lastTradePrice": null,
30
+ "sourceMetadata": null,
25
31
  } satisfies GetExecutionPriceRequestArgsInner
26
32
 
27
33
  console.log(example)
@@ -10,6 +10,9 @@ Name | Type
10
10
  `asks` | [Array&lt;OrderLevel&gt;](OrderLevel.md)
11
11
  `timestamp` | number
12
12
  `datetime` | string
13
+ `isNegRisk` | boolean
14
+ `lastTradePrice` | number
15
+ `sourceMetadata` | { [key: string]: any; }
13
16
 
14
17
  ## Example
15
18
 
@@ -22,6 +25,9 @@ const example = {
22
25
  "asks": null,
23
26
  "timestamp": null,
24
27
  "datetime": null,
28
+ "isNegRisk": null,
29
+ "lastTradePrice": null,
30
+ "sourceMetadata": null,
25
31
  } satisfies OrderBook
26
32
 
27
33
  console.log(example)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.49.6",
3
+ "version": "2.49.8",
4
4
  "description": "OpenAPI client for pmxtjs",
5
5
  "author": "OpenAPI-Generator",
6
6
  "repository": {
@@ -51,6 +51,24 @@ export interface OrderBook {
51
51
  * @memberof OrderBook
52
52
  */
53
53
  datetime?: string;
54
+ /**
55
+ * Whether the venue marks this snapshot as a negative-risk market.
56
+ * @type {boolean}
57
+ * @memberof OrderBook
58
+ */
59
+ isNegRisk?: boolean;
60
+ /**
61
+ * Last traded price from venues that include it with the book snapshot.
62
+ * @type {number}
63
+ * @memberof OrderBook
64
+ */
65
+ lastTradePrice?: number;
66
+ /**
67
+ * Venue-specific metadata preserved from the raw order book snapshot.
68
+ * @type {{ [key: string]: any; }}
69
+ * @memberof OrderBook
70
+ */
71
+ sourceMetadata?: { [key: string]: any; };
54
72
  }
55
73
 
56
74
  /**
@@ -76,6 +94,9 @@ export function OrderBookFromJSONTyped(json: any, ignoreDiscriminator: boolean):
76
94
  'asks': ((json['asks'] as Array<any>).map(OrderLevelFromJSON)),
77
95
  'timestamp': json['timestamp'] == null ? undefined : json['timestamp'],
78
96
  'datetime': json['datetime'] == null ? undefined : json['datetime'],
97
+ 'isNegRisk': json['isNegRisk'] == null ? undefined : json['isNegRisk'],
98
+ 'lastTradePrice': json['lastTradePrice'] == null ? undefined : json['lastTradePrice'],
99
+ 'sourceMetadata': json['sourceMetadata'] == null ? undefined : json['sourceMetadata'],
79
100
  };
80
101
  }
81
102
 
@@ -94,6 +115,9 @@ export function OrderBookToJSONTyped(value?: OrderBook | null, ignoreDiscriminat
94
115
  'asks': ((value['asks'] as Array<any>).map(OrderLevelToJSON)),
95
116
  'timestamp': value['timestamp'],
96
117
  'datetime': value['datetime'],
118
+ 'isNegRisk': value['isNegRisk'],
119
+ 'lastTradePrice': value['lastTradePrice'],
120
+ 'sourceMetadata': value['sourceMetadata'],
97
121
  };
98
122
  }
99
123
 
package/index.ts CHANGED
@@ -19,14 +19,14 @@
19
19
  */
20
20
 
21
21
 
22
- import { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock } from "./pmxt/client.js";
22
+ import { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock } from "./pmxt/client.js";
23
23
  import { Router } from "./pmxt/router.js";
24
24
  import { ServerManager } from "./pmxt/server-manager.js";
25
25
  import { FeedClient } from "./pmxt/feed-client.js";
26
26
  import * as models from "./pmxt/models.js";
27
27
  import * as errors from "./pmxt/errors.js";
28
28
 
29
- export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Mock, PolymarketOptions } from "./pmxt/client.js";
29
+ export { Exchange, Polymarket, Kalshi, KalshiDemo, Limitless, Myriad, Probable, Baozi, Opinion, Metaculus, Smarkets, PolymarketUS, GeminiTitan, Hyperliquid, SuiBets, Suibets, Mock, PolymarketOptions } from "./pmxt/client.js";
30
30
  export { FeedClient } from "./pmxt/feed-client.js";
31
31
  export type { Ticker, Tickers, OHLCV, Market as FeedMarket, OracleRound, FeedClientOptions } from "./pmxt/feed-client.js";
32
32
  export { Router } from "./pmxt/router.js";
@@ -88,6 +88,7 @@ const pmxt = {
88
88
  GeminiTitan,
89
89
  Hyperliquid,
90
90
  SuiBets,
91
+ Suibets,
91
92
  Mock,
92
93
  Router,
93
94
  ServerManager,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.49.6",
3
+ "version": "2.49.8",
4
4
  "description": "Unified prediction market data API - The ccxt for prediction markets",
5
5
  "author": "PMXT Contributors",
6
6
  "repository": {
@@ -43,7 +43,7 @@
43
43
  "unified"
44
44
  ],
45
45
  "dependencies": {
46
- "pmxt-core": "2.49.6",
46
+ "pmxt-core": "2.49.8",
47
47
  "ws": "^8.18.0"
48
48
  },
49
49
  "peerDependencies": {
package/pmxt/client.ts CHANGED
@@ -53,6 +53,7 @@ import { buildArgsWithOptionalOptions } from "./args.js";
53
53
  import { PmxtError, fromServerError, InvalidOrder, NotSupported } from "./errors.js";
54
54
  import { LOCAL_URL, resolvePmxtBaseUrl } from "./constants.js";
55
55
  import { SidecarWsClient } from "./ws-client.js";
56
+ import { logger } from "./logger.js";
56
57
 
57
58
  // Hosted-mode trading dispatch.
58
59
  // These modules are introduced as part of the hosted trading mode rollout.
@@ -547,8 +548,8 @@ export abstract class Exchange {
547
548
  if (attempt === 0 && !this.isHosted) {
548
549
  try {
549
550
  await this.serverManager.ensureServerRunning();
550
- } catch {
551
- // Restart failed continue retrying anyway
551
+ } catch (err) {
552
+ logger.warn('PmxtClient: server restart failed during retry', { attempt, error: String(err) });
552
553
  }
553
554
  }
554
555
  await new Promise(resolve => setTimeout(resolve, delays[attempt]));
@@ -594,7 +595,8 @@ export abstract class Exchange {
594
595
  if (!client.connected) {
595
596
  throw new Error("WS handshake failed");
596
597
  }
597
- } catch {
598
+ } catch (err) {
599
+ logger.warn('PmxtClient: WebSocket probe failed, falling back to HTTP', { error: String(err) });
598
600
  this._wsUnsupported = true;
599
601
  client.close();
600
602
  return null;
@@ -1133,6 +1135,9 @@ export abstract class Exchange {
1133
1135
  return this._hostedSubmitOrder(built);
1134
1136
  }
1135
1137
  await this.initPromise;
1138
+ if (this.isHosted) {
1139
+ throw new PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.");
1140
+ }
1136
1141
  try {
1137
1142
  const args: any[] = [];
1138
1143
  args.push(built);
@@ -2352,7 +2357,10 @@ export abstract class Exchange {
2352
2357
  const body = await res.json();
2353
2358
  this._hostedAccount = { depositWallet: body.deposit_wallet, signatureType: body.signature_type };
2354
2359
  } else { this._hostedAccount = {}; }
2355
- } catch { this._hostedAccount = {}; }
2360
+ } catch (err) {
2361
+ logger.warn('PmxtClient: hosted account discovery failed', { error: String(err) });
2362
+ this._hostedAccount = {};
2363
+ }
2356
2364
  })();
2357
2365
  }
2358
2366
  await this._accountDiscoveryPromise;
@@ -3362,6 +3370,9 @@ export class SuiBets extends Exchange {
3362
3370
  }
3363
3371
  }
3364
3372
 
3373
+ // Backwards-compatible casing alias matching the Python SDK export.
3374
+ export const Suibets = SuiBets;
3375
+
3365
3376
  /**
3366
3377
  * Mock exchange client.
3367
3378
  *
@@ -108,7 +108,11 @@ export function userTradeFromV0(payload: Record<string, unknown>): UserTrade {
108
108
  const trade: UserTrade = {
109
109
  id: strOrEmpty(payload["id"]),
110
110
  price: floatOrZero(payload["price"]),
111
- amount: floatOrZero(payload["amount"]),
111
+ // The v0 wire sends trade amounts in 6-dec micro-shares (verified
112
+ // live: 58139533.0 == 58.139533 shares, matching the same position's
113
+ // decimal `shares`). Normalize so UserTrade.amount means shares,
114
+ // like everywhere else in the SDK.
115
+ amount: floatOrZero(payload["amount"]) / 1_000_000,
112
116
  side,
113
117
  timestamp: timestampToMs(payload["timestamp"]),
114
118
  };
@@ -130,7 +134,8 @@ export function userTradeToV0(trade: UserTrade): Record<string, unknown> {
130
134
  const out: Record<string, unknown> = {
131
135
  id: trade.id,
132
136
  side: trade.side,
133
- amount: trade.amount,
137
+ // Inverse of userTradeFromV0: decimal shares -> 6-dec micro-shares.
138
+ amount: Math.round(trade.amount * 1_000_000),
134
139
  price: trade.price,
135
140
  timestamp: msToTimestamp(trade.timestamp),
136
141
  };
@@ -442,6 +442,28 @@ function validateWorstPrice(
442
442
  ): void {
443
443
  const worstPriceMicro = messageBigInt(message, "worst_price", "worstPrice");
444
444
  const worstPrice = Number(worstPriceMicro) / SIX_DEC_DIVISOR;
445
+
446
+ // Hosted MARKET orders pin worst_price to the tick-grid extreme by
447
+ // design ("textbook market semantics"): the binding user protection is
448
+ // max_cost_usdc (buys) / shares_6dec (sells), validated above. A
449
+ // slippage bound on worst_price would reject every server-built market
450
+ // order, so only sanity-check the price domain here.
451
+ const orderType = String(
452
+ firstPresent(
453
+ getField(buildRequest, "order_type"),
454
+ getField(buildRequest, "orderType"),
455
+ "market",
456
+ ),
457
+ ).toLowerCase();
458
+ if (orderType === "market") {
459
+ if (!(worstPrice > 0 && worstPrice < 1)) {
460
+ economicFail(
461
+ `worst_price expected within (0, 1) got ${worstPrice}`,
462
+ );
463
+ }
464
+ return;
465
+ }
466
+
445
467
  const slippagePctRaw = firstPresent(
446
468
  getField(buildRequest, "slippage_pct"),
447
469
  getField(buildRequest, "slippagePct"),
package/pmxt/router.ts CHANGED
@@ -224,6 +224,8 @@ export class Router extends Exchange {
224
224
  marketId?: string;
225
225
  slug?: string;
226
226
  url?: string;
227
+ query?: string;
228
+ category?: string;
227
229
  relation?: MatchRelation;
228
230
  minConfidence?: number;
229
231
  limit?: number;
@@ -234,6 +236,8 @@ export class Router extends Exchange {
234
236
  marketId?: string;
235
237
  slug?: string;
236
238
  url?: string;
239
+ query?: string;
240
+ category?: string;
237
241
  relation?: MatchRelation;
238
242
  minConfidence?: number;
239
243
  limit?: number;
@@ -246,6 +250,8 @@ export class Router extends Exchange {
246
250
  if (marketId) query.marketId = marketId;
247
251
  if (params.slug ?? params.market?.slug) query.slug = params.slug ?? params.market?.slug;
248
252
  if (params.url) query.url = params.url;
253
+ if (params.query) query.query = params.query;
254
+ if (params.category) query.category = params.category;
249
255
  if (params.relation) query.relation = params.relation;
250
256
  if (params.minConfidence !== undefined) query.minConfidence = params.minConfidence;
251
257
  if (params.limit !== undefined) query.limit = params.limit;
@@ -274,6 +280,8 @@ export class Router extends Exchange {
274
280
  marketId?: string;
275
281
  slug?: string;
276
282
  url?: string;
283
+ query?: string;
284
+ category?: string;
277
285
  relation?: MatchRelation;
278
286
  minConfidence?: number;
279
287
  limit?: number;
@@ -284,6 +292,8 @@ export class Router extends Exchange {
284
292
  marketId?: string;
285
293
  slug?: string;
286
294
  url?: string;
295
+ query?: string;
296
+ category?: string;
287
297
  relation?: MatchRelation;
288
298
  minConfidence?: number;
289
299
  limit?: number;
@@ -303,6 +313,8 @@ export class Router extends Exchange {
303
313
  event?: UnifiedEvent;
304
314
  eventId?: string;
305
315
  slug?: string;
316
+ query?: string;
317
+ category?: string;
306
318
  relation?: MatchRelation;
307
319
  minConfidence?: number;
308
320
  limit?: number;
@@ -312,6 +324,8 @@ export class Router extends Exchange {
312
324
  event?: UnifiedEvent;
313
325
  eventId?: string;
314
326
  slug?: string;
327
+ query?: string;
328
+ category?: string;
315
329
  relation?: MatchRelation;
316
330
  minConfidence?: number;
317
331
  limit?: number;
@@ -323,6 +337,8 @@ export class Router extends Exchange {
323
337
  const eventId = params.eventId ?? (!params.event?.slug ? params.event?.id : undefined);
324
338
  if (eventId) query.eventId = eventId;
325
339
  if (params.slug ?? params.event?.slug) query.slug = params.slug ?? params.event?.slug;
340
+ if (params.query) query.query = params.query;
341
+ if (params.category) query.category = params.category;
326
342
  if (params.relation) query.relation = params.relation;
327
343
  if (params.minConfidence !== undefined) query.minConfidence = params.minConfidence;
328
344
  if (params.limit !== undefined) query.limit = params.limit;
@@ -8,6 +8,7 @@ import { DefaultApi, Configuration } from "../generated/src/index.js";
8
8
  import { readFileSync, existsSync } from "fs";
9
9
  import { homedir } from "os";
10
10
  import { join, dirname } from "path";
11
+ import { logger } from "./logger.js";
11
12
 
12
13
  export interface ServerManagerOptions {
13
14
  baseUrl?: string;
@@ -145,8 +146,8 @@ export class ServerManager {
145
146
  const data = await response.json() as any;
146
147
  if (data.status === "ok") return;
147
148
  }
148
- } catch {
149
- // Not ready yet
149
+ } catch (err) {
150
+ logger.debug('server-manager: health poll error', { error: String(err) });
150
151
  }
151
152
  }
152
153
  await new Promise((resolve) => setTimeout(resolve, this.retryDelayMs));
@@ -264,8 +265,8 @@ export class ServerManager {
264
265
  return true;
265
266
  }
266
267
  }
267
- } catch {
268
- // Ignore errors
268
+ } catch (err) {
269
+ logger.warn('server-manager: version check failed', { error: String(err) });
269
270
  }
270
271
  return false;
271
272
  }
@@ -385,6 +386,9 @@ export class ServerManager {
385
386
  try {
386
387
  const { unlinkSync } = await import('fs');
387
388
  unlinkSync(this.lockPath);
388
- } catch { }
389
+ } catch (err) {
390
+ // Best-effort — expected when file was already removed.
391
+ logger.debug('server-manager: lock file removal failed', { path: this.lockPath, error: String(err) });
392
+ }
389
393
  }
390
394
  }
package/pmxt/ws-client.ts CHANGED
@@ -343,8 +343,8 @@ export class SidecarWsClient {
343
343
  if (this.ws) {
344
344
  try {
345
345
  this.ws.close();
346
- } catch {
347
- // ignore
346
+ } catch (err) {
347
+ logger.debug('[SidecarWsClient] error during ws.close()', { error: String(err) });
348
348
  }
349
349
  this.ws = null;
350
350
  }