pmxtjs 2.43.19 → 2.43.24

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 (42) hide show
  1. package/dist/esm/generated/src/models/Order.d.ts +1 -1
  2. package/dist/esm/generated/src/models/Order.js +1 -1
  3. package/dist/esm/index.d.ts +1 -1
  4. package/dist/esm/pmxt/args.d.ts +1 -1
  5. package/dist/esm/pmxt/client.js +4 -1
  6. package/dist/esm/pmxt/errors.d.ts +2 -2
  7. package/dist/esm/pmxt/errors.js +14 -14
  8. package/dist/esm/pmxt/feed-client.d.ts +2 -2
  9. package/dist/esm/pmxt/feed-client.js +5 -2
  10. package/dist/esm/pmxt/logger.d.ts +18 -0
  11. package/dist/esm/pmxt/logger.js +74 -0
  12. package/dist/esm/pmxt/models.d.ts +2 -2
  13. package/dist/esm/pmxt/router.js +3 -1
  14. package/dist/esm/pmxt/server-manager.js +6 -2
  15. package/dist/esm/pmxt/ws-client.js +21 -2
  16. package/dist/generated/src/models/Order.d.ts +1 -1
  17. package/dist/generated/src/models/Order.js +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/pmxt/args.d.ts +1 -1
  20. package/dist/pmxt/client.js +4 -1
  21. package/dist/pmxt/errors.d.ts +2 -2
  22. package/dist/pmxt/errors.js +14 -14
  23. package/dist/pmxt/feed-client.d.ts +2 -2
  24. package/dist/pmxt/feed-client.js +5 -2
  25. package/dist/pmxt/logger.d.ts +18 -0
  26. package/dist/pmxt/logger.js +77 -0
  27. package/dist/pmxt/models.d.ts +2 -2
  28. package/dist/pmxt/router.js +3 -1
  29. package/dist/pmxt/server-manager.js +6 -2
  30. package/dist/pmxt/ws-client.js +21 -2
  31. package/generated/package.json +1 -1
  32. package/generated/src/models/Order.ts +1 -1
  33. package/package.json +2 -2
  34. package/pmxt/args.ts +1 -1
  35. package/pmxt/client.ts +4 -1
  36. package/pmxt/errors.ts +16 -15
  37. package/pmxt/feed-client.ts +7 -4
  38. package/pmxt/logger.ts +78 -0
  39. package/pmxt/models.ts +2 -2
  40. package/pmxt/router.ts +3 -1
  41. package/pmxt/server-manager.ts +6 -2
  42. package/pmxt/ws-client.ts +21 -4
@@ -123,7 +123,7 @@ export declare const OrderStatusEnum: {
123
123
  readonly Pending: "pending";
124
124
  readonly Open: "open";
125
125
  readonly Filled: "filled";
126
- readonly Cancelled: "cancelled";
126
+ readonly Canceled: "canceled";
127
127
  readonly Rejected: "rejected";
128
128
  };
129
129
  export type OrderStatusEnum = typeof OrderStatusEnum[keyof typeof OrderStatusEnum];
@@ -32,7 +32,7 @@ export const OrderStatusEnum = {
32
32
  Pending: 'pending',
33
33
  Open: 'open',
34
34
  Filled: 'filled',
35
- Cancelled: 'cancelled',
35
+ Canceled: 'canceled',
36
36
  Rejected: 'rejected'
37
37
  };
38
38
  /**
@@ -57,7 +57,7 @@ export declare const server: {
57
57
  readonly logs: (n?: number) => string[];
58
58
  };
59
59
  declare const pmxt: {
60
- fromServerError(errorData: any): errors.PmxtError;
60
+ fromServerError(errorData: unknown): errors.PmxtError;
61
61
  PmxtError: typeof errors.PmxtError;
62
62
  BadRequest: typeof errors.BadRequest;
63
63
  AuthenticationError: typeof errors.AuthenticationError;
@@ -1 +1 @@
1
- export declare function buildArgsWithOptionalOptions(primary?: any): any[];
1
+ export declare function buildArgsWithOptionalOptions<T>(primary?: T): T[];
@@ -270,7 +270,10 @@ export class Exchange {
270
270
  let lastError;
271
271
  for (let attempt = 0; attempt <= delays.length; attempt++) {
272
272
  try {
273
- return await fetch(input, init);
273
+ return await fetch(input, {
274
+ ...init,
275
+ signal: AbortSignal.timeout(30_000),
276
+ });
274
277
  }
275
278
  catch (error) {
276
279
  lastError = error;
@@ -20,7 +20,7 @@ export declare class PermissionDenied extends PmxtError {
20
20
  constructor(message: string, exchange?: string);
21
21
  }
22
22
  export declare class NotFoundError extends PmxtError {
23
- constructor(message: string, exchange?: string);
23
+ constructor(message: string, exchange?: string, code?: string);
24
24
  }
25
25
  export declare class OrderNotFound extends NotFoundError {
26
26
  constructor(orderId: string, exchange?: string);
@@ -52,4 +52,4 @@ export declare class ExchangeNotAvailable extends PmxtError {
52
52
  constructor(message: string, exchange?: string);
53
53
  }
54
54
  /** Convert a server error response object into a typed PmxtError. */
55
- export declare function fromServerError(errorData: any): PmxtError;
55
+ export declare function fromServerError(errorData: unknown): PmxtError;
@@ -36,26 +36,23 @@ export class PermissionDenied extends PmxtError {
36
36
  }
37
37
  }
38
38
  export class NotFoundError extends PmxtError {
39
- constructor(message, exchange) {
40
- super(message, "NOT_FOUND", false, exchange);
39
+ constructor(message, exchange, code = "NOT_FOUND") {
40
+ super(message, code, false, exchange);
41
41
  }
42
42
  }
43
43
  export class OrderNotFound extends NotFoundError {
44
44
  constructor(orderId, exchange) {
45
- super(`Order not found: ${orderId}`, exchange);
46
- this.code = "ORDER_NOT_FOUND";
45
+ super(`Order not found: ${orderId}`, exchange, "ORDER_NOT_FOUND");
47
46
  }
48
47
  }
49
48
  export class MarketNotFound extends NotFoundError {
50
49
  constructor(marketId, exchange) {
51
- super(`Market not found: ${marketId}`, exchange);
52
- this.code = "MARKET_NOT_FOUND";
50
+ super(`Market not found: ${marketId}`, exchange, "MARKET_NOT_FOUND");
53
51
  }
54
52
  }
55
53
  export class EventNotFound extends NotFoundError {
56
54
  constructor(identifier, exchange) {
57
- super(`Event not found: ${identifier}`, exchange);
58
- this.code = "EVENT_NOT_FOUND";
55
+ super(`Event not found: ${identifier}`, exchange, "EVENT_NOT_FOUND");
59
56
  }
60
57
  }
61
58
  export class RateLimitExceeded extends PmxtError {
@@ -114,16 +111,19 @@ export function fromServerError(errorData) {
114
111
  if (typeof errorData === "string") {
115
112
  return new PmxtError(errorData);
116
113
  }
117
- const message = errorData.message || "Unknown error";
118
- const code = errorData.code || "UNKNOWN_ERROR";
119
- const retryable = errorData.retryable || false;
120
- const exchange = errorData.exchange;
114
+ const data = errorData;
115
+ const message = (typeof data.message === "string" ? data.message : undefined) || "Unknown error";
116
+ const code = (typeof data.code === "string" ? data.code : undefined) || "UNKNOWN_ERROR";
117
+ const retryable = typeof data.retryable === "boolean" ? data.retryable : false;
118
+ const exchange = typeof data.exchange === "string" ? data.exchange : undefined;
121
119
  const ErrorClass = ERROR_CODE_MAP[code];
122
120
  if (ErrorClass === RateLimitExceeded) {
123
- return new RateLimitExceeded(message, errorData.retryAfter, exchange);
121
+ const retryAfter = typeof data.retryAfter === "number" ? data.retryAfter : undefined;
122
+ return new RateLimitExceeded(message, retryAfter, exchange);
124
123
  }
125
124
  if (ErrorClass === ValidationError) {
126
- return new ValidationError(message, errorData.field, exchange);
125
+ const field = typeof data.field === "string" ? data.field : undefined;
126
+ return new ValidationError(message, field, exchange);
127
127
  }
128
128
  if (ErrorClass) {
129
129
  return new ErrorClass(message, exchange);
@@ -7,7 +7,7 @@
7
7
  */
8
8
  export interface Ticker {
9
9
  symbol: string;
10
- info: any;
10
+ info: Record<string, unknown>;
11
11
  timestamp: number | undefined;
12
12
  datetime: string | undefined;
13
13
  high: number | undefined;
@@ -38,7 +38,7 @@ export interface Market {
38
38
  quote: string;
39
39
  active: boolean;
40
40
  type: string;
41
- info: any;
41
+ info: Record<string, unknown>;
42
42
  }
43
43
  export interface OracleRound {
44
44
  feed: string;
@@ -34,7 +34,7 @@ export class FeedClient {
34
34
  params.symbols = symbols.join(',');
35
35
  return this.get('fetchTickers', params);
36
36
  }
37
- async fetchOHLCV(symbol, timeframe, since, limit) {
37
+ async fetchOHLCV(symbol, timeframe = '1h', since, limit) {
38
38
  return this.get('fetchOHLCV', { symbol, timeframe, since, limit });
39
39
  }
40
40
  async fetchOracleRound(feed) {
@@ -55,7 +55,10 @@ export class FeedClient {
55
55
  .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
56
56
  .join('&');
57
57
  const url = `${this.baseUrl}/api/feeds/${this.feedName}/${method}${qs ? '?' + qs : ''}`;
58
- const response = await fetch(url, { headers: this.headers });
58
+ const response = await fetch(url, {
59
+ headers: this.headers,
60
+ signal: AbortSignal.timeout(30_000),
61
+ });
59
62
  if (!response.ok) {
60
63
  const body = await response.json().catch(() => ({}));
61
64
  throw new PmxtError(body.error || response.statusText);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Structured logger for pmxt TypeScript SDK.
3
+ *
4
+ * Thin abstraction over console that:
5
+ * - Attaches a `[pmxt]` prefix for easy filtering
6
+ * - Supports log levels (debug, info, warn, error)
7
+ * - Respects a configurable level threshold via PMXT_LOG_LEVEL
8
+ * - Can be swapped for a real transport later
9
+ */
10
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
11
+ export declare const logger: {
12
+ debug(message: string, context?: Record<string, unknown>): void;
13
+ info(message: string, context?: Record<string, unknown>): void;
14
+ warn(message: string, context?: Record<string, unknown>): void;
15
+ error(message: string, context?: Record<string, unknown>): void;
16
+ setLevel(level: LogLevel): void;
17
+ getLevel(): LogLevel;
18
+ };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Structured logger for pmxt TypeScript SDK.
3
+ *
4
+ * Thin abstraction over console that:
5
+ * - Attaches a `[pmxt]` prefix for easy filtering
6
+ * - Supports log levels (debug, info, warn, error)
7
+ * - Respects a configurable level threshold via PMXT_LOG_LEVEL
8
+ * - Can be swapped for a real transport later
9
+ */
10
+ const LEVEL_PRIORITY = {
11
+ debug: 0,
12
+ info: 1,
13
+ warn: 2,
14
+ error: 3,
15
+ silent: 4,
16
+ };
17
+ function getDefaultLevel() {
18
+ if (typeof process !== 'undefined' && process.env?.PMXT_LOG_LEVEL) {
19
+ return process.env.PMXT_LOG_LEVEL;
20
+ }
21
+ return 'info';
22
+ }
23
+ let currentLevel = getDefaultLevel();
24
+ function shouldLog(level) {
25
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[currentLevel];
26
+ }
27
+ export const logger = {
28
+ debug(message, context) {
29
+ if (!shouldLog('debug'))
30
+ return;
31
+ if (context) {
32
+ console.debug(`[pmxt] ${message}`, context);
33
+ }
34
+ else {
35
+ console.debug(`[pmxt] ${message}`);
36
+ }
37
+ },
38
+ info(message, context) {
39
+ if (!shouldLog('info'))
40
+ return;
41
+ if (context) {
42
+ console.info(`[pmxt] ${message}`, context);
43
+ }
44
+ else {
45
+ console.info(`[pmxt] ${message}`);
46
+ }
47
+ },
48
+ warn(message, context) {
49
+ if (!shouldLog('warn'))
50
+ return;
51
+ if (context) {
52
+ console.warn(`[pmxt] ${message}`, context);
53
+ }
54
+ else {
55
+ console.warn(`[pmxt] ${message}`);
56
+ }
57
+ },
58
+ error(message, context) {
59
+ if (!shouldLog('error'))
60
+ return;
61
+ if (context) {
62
+ console.error(`[pmxt] ${message}`, context);
63
+ }
64
+ else {
65
+ console.error(`[pmxt] ${message}`);
66
+ }
67
+ },
68
+ setLevel(level) {
69
+ currentLevel = level;
70
+ },
71
+ getLevel() {
72
+ return currentLevel;
73
+ },
74
+ };
@@ -22,7 +22,7 @@ export interface MarketOutcome {
22
22
  /** 24-hour price change */
23
23
  priceChange24h?: number;
24
24
  /** Exchange-specific metadata */
25
- metadata?: Record<string, any>;
25
+ metadata?: Record<string, unknown>;
26
26
  /** Best bid price from the order book (when includePrices=True) */
27
27
  bestBid?: number;
28
28
  /** Best ask price from the order book (when includePrices=True) */
@@ -201,7 +201,7 @@ export interface Trade {
201
201
  side: "buy" | "sell" | "unknown";
202
202
  }
203
203
  /**
204
- * An order (open, filled, or cancelled).
204
+ * An order (open, filled, or canceled).
205
205
  */
206
206
  export interface Order {
207
207
  /** Order ID */
@@ -5,6 +5,7 @@
5
5
  * every venue PMXT supports. Only requires a PMXT API key.
6
6
  */
7
7
  import { Exchange } from "./client.js";
8
+ import { logger } from "./logger.js";
8
9
  function convertMarket(raw) {
9
10
  const outcomes = (raw.outcomes || []).map((o) => ({
10
11
  outcomeId: o.outcomeId,
@@ -131,7 +132,7 @@ export class Router extends Exchange {
131
132
  }
132
133
  }
133
134
  async fetchMatches(marketOrParams = {}) {
134
- console.warn('[pmxt] fetchMatches is deprecated, use fetchMarketMatches instead');
135
+ logger.warn('fetchMatches is deprecated, use fetchMarketMatches instead');
135
136
  return this.fetchMarketMatches(marketOrParams);
136
137
  }
137
138
  async fetchEventMatches(eventOrParams = {}) {
@@ -188,6 +189,7 @@ export class Router extends Exchange {
188
189
  method: 'POST',
189
190
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
190
191
  body: JSON.stringify({ args: [query], credentials: this.getCredentials() }),
192
+ signal: AbortSignal.timeout(30_000),
191
193
  });
192
194
  if (!response.ok) {
193
195
  const body = await response.json().catch(() => ({}));
@@ -85,7 +85,9 @@ export class ServerManager {
85
85
  try {
86
86
  // Use native fetch to check health on the actual running port
87
87
  // This avoids issues where this.api is configured with the wrong port
88
- const response = await fetch(`http://localhost:${port}/health`);
88
+ const response = await fetch(`http://localhost:${port}/health`, {
89
+ signal: AbortSignal.timeout(5_000),
90
+ });
89
91
  if (response.ok) {
90
92
  const data = await response.json();
91
93
  return data.status === "ok";
@@ -106,7 +108,9 @@ export class ServerManager {
106
108
  const info = this.getServerInfo();
107
109
  if (info) {
108
110
  try {
109
- const response = await fetch(`http://localhost:${info.port}/health`);
111
+ const response = await fetch(`http://localhost:${info.port}/health`, {
112
+ signal: AbortSignal.timeout(5_000),
113
+ });
110
114
  if (response.ok) {
111
115
  const data = await response.json();
112
116
  if (data.status === "ok")
@@ -101,8 +101,21 @@ export class SidecarWsClient {
101
101
  const raw = typeof event.data === "string"
102
102
  ? event.data
103
103
  : event.data.toString();
104
- const msg = JSON.parse(raw);
105
- this.dispatch(msg);
104
+ let msg;
105
+ try {
106
+ msg = JSON.parse(raw);
107
+ }
108
+ catch {
109
+ // Non-JSON control frame -- ignore.
110
+ return;
111
+ }
112
+ try {
113
+ this.dispatch(msg);
114
+ }
115
+ catch (err) {
116
+ // Dispatch bug -- log and continue; don't kill the connection.
117
+ console.error('[SidecarWsClient] dispatch error:', err);
118
+ }
106
119
  };
107
120
  });
108
121
  }
@@ -188,6 +201,9 @@ export class SidecarWsClient {
188
201
  if (credentials) {
189
202
  message.credentials = credentials;
190
203
  }
204
+ if (!this.ws) {
205
+ throw new PmxtError('[ws-client] Cannot send: WebSocket not connected');
206
+ }
191
207
  this.ws.send(JSON.stringify(message));
192
208
  return this.waitForData(requestId, timeoutMs);
193
209
  }
@@ -213,6 +229,9 @@ export class SidecarWsClient {
213
229
  if (credentials) {
214
230
  message.credentials = credentials;
215
231
  }
232
+ if (!this.ws) {
233
+ throw new PmxtError('[ws-client] Cannot send: WebSocket not connected');
234
+ }
216
235
  this.ws.send(JSON.stringify(message));
217
236
  // Wait for first data event
218
237
  await this.waitForData(requestId, timeoutMs);
@@ -123,7 +123,7 @@ export declare const OrderStatusEnum: {
123
123
  readonly Pending: "pending";
124
124
  readonly Open: "open";
125
125
  readonly Filled: "filled";
126
- readonly Cancelled: "cancelled";
126
+ readonly Canceled: "canceled";
127
127
  readonly Rejected: "rejected";
128
128
  };
129
129
  export type OrderStatusEnum = typeof OrderStatusEnum[keyof typeof OrderStatusEnum];
@@ -40,7 +40,7 @@ exports.OrderStatusEnum = {
40
40
  Pending: 'pending',
41
41
  Open: 'open',
42
42
  Filled: 'filled',
43
- Cancelled: 'cancelled',
43
+ Canceled: 'canceled',
44
44
  Rejected: 'rejected'
45
45
  };
46
46
  /**
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ export declare const server: {
57
57
  readonly logs: (n?: number) => string[];
58
58
  };
59
59
  declare const pmxt: {
60
- fromServerError(errorData: any): errors.PmxtError;
60
+ fromServerError(errorData: unknown): errors.PmxtError;
61
61
  PmxtError: typeof errors.PmxtError;
62
62
  BadRequest: typeof errors.BadRequest;
63
63
  AuthenticationError: typeof errors.AuthenticationError;
@@ -1 +1 @@
1
- export declare function buildArgsWithOptionalOptions(primary?: any): any[];
1
+ export declare function buildArgsWithOptionalOptions<T>(primary?: T): T[];
@@ -273,7 +273,10 @@ class Exchange {
273
273
  let lastError;
274
274
  for (let attempt = 0; attempt <= delays.length; attempt++) {
275
275
  try {
276
- return await fetch(input, init);
276
+ return await fetch(input, {
277
+ ...init,
278
+ signal: AbortSignal.timeout(30_000),
279
+ });
277
280
  }
278
281
  catch (error) {
279
282
  lastError = error;
@@ -20,7 +20,7 @@ export declare class PermissionDenied extends PmxtError {
20
20
  constructor(message: string, exchange?: string);
21
21
  }
22
22
  export declare class NotFoundError extends PmxtError {
23
- constructor(message: string, exchange?: string);
23
+ constructor(message: string, exchange?: string, code?: string);
24
24
  }
25
25
  export declare class OrderNotFound extends NotFoundError {
26
26
  constructor(orderId: string, exchange?: string);
@@ -52,4 +52,4 @@ export declare class ExchangeNotAvailable extends PmxtError {
52
52
  constructor(message: string, exchange?: string);
53
53
  }
54
54
  /** Convert a server error response object into a typed PmxtError. */
55
- export declare function fromServerError(errorData: any): PmxtError;
55
+ export declare function fromServerError(errorData: unknown): PmxtError;
@@ -44,29 +44,26 @@ class PermissionDenied extends PmxtError {
44
44
  }
45
45
  exports.PermissionDenied = PermissionDenied;
46
46
  class NotFoundError extends PmxtError {
47
- constructor(message, exchange) {
48
- super(message, "NOT_FOUND", false, exchange);
47
+ constructor(message, exchange, code = "NOT_FOUND") {
48
+ super(message, code, false, exchange);
49
49
  }
50
50
  }
51
51
  exports.NotFoundError = NotFoundError;
52
52
  class OrderNotFound extends NotFoundError {
53
53
  constructor(orderId, exchange) {
54
- super(`Order not found: ${orderId}`, exchange);
55
- this.code = "ORDER_NOT_FOUND";
54
+ super(`Order not found: ${orderId}`, exchange, "ORDER_NOT_FOUND");
56
55
  }
57
56
  }
58
57
  exports.OrderNotFound = OrderNotFound;
59
58
  class MarketNotFound extends NotFoundError {
60
59
  constructor(marketId, exchange) {
61
- super(`Market not found: ${marketId}`, exchange);
62
- this.code = "MARKET_NOT_FOUND";
60
+ super(`Market not found: ${marketId}`, exchange, "MARKET_NOT_FOUND");
63
61
  }
64
62
  }
65
63
  exports.MarketNotFound = MarketNotFound;
66
64
  class EventNotFound extends NotFoundError {
67
65
  constructor(identifier, exchange) {
68
- super(`Event not found: ${identifier}`, exchange);
69
- this.code = "EVENT_NOT_FOUND";
66
+ super(`Event not found: ${identifier}`, exchange, "EVENT_NOT_FOUND");
70
67
  }
71
68
  }
72
69
  exports.EventNotFound = EventNotFound;
@@ -132,16 +129,19 @@ function fromServerError(errorData) {
132
129
  if (typeof errorData === "string") {
133
130
  return new PmxtError(errorData);
134
131
  }
135
- const message = errorData.message || "Unknown error";
136
- const code = errorData.code || "UNKNOWN_ERROR";
137
- const retryable = errorData.retryable || false;
138
- const exchange = errorData.exchange;
132
+ const data = errorData;
133
+ const message = (typeof data.message === "string" ? data.message : undefined) || "Unknown error";
134
+ const code = (typeof data.code === "string" ? data.code : undefined) || "UNKNOWN_ERROR";
135
+ const retryable = typeof data.retryable === "boolean" ? data.retryable : false;
136
+ const exchange = typeof data.exchange === "string" ? data.exchange : undefined;
139
137
  const ErrorClass = ERROR_CODE_MAP[code];
140
138
  if (ErrorClass === RateLimitExceeded) {
141
- return new RateLimitExceeded(message, errorData.retryAfter, exchange);
139
+ const retryAfter = typeof data.retryAfter === "number" ? data.retryAfter : undefined;
140
+ return new RateLimitExceeded(message, retryAfter, exchange);
142
141
  }
143
142
  if (ErrorClass === ValidationError) {
144
- return new ValidationError(message, errorData.field, exchange);
143
+ const field = typeof data.field === "string" ? data.field : undefined;
144
+ return new ValidationError(message, field, exchange);
145
145
  }
146
146
  if (ErrorClass) {
147
147
  return new ErrorClass(message, exchange);
@@ -7,7 +7,7 @@
7
7
  */
8
8
  export interface Ticker {
9
9
  symbol: string;
10
- info: any;
10
+ info: Record<string, unknown>;
11
11
  timestamp: number | undefined;
12
12
  datetime: string | undefined;
13
13
  high: number | undefined;
@@ -38,7 +38,7 @@ export interface Market {
38
38
  quote: string;
39
39
  active: boolean;
40
40
  type: string;
41
- info: any;
41
+ info: Record<string, unknown>;
42
42
  }
43
43
  export interface OracleRound {
44
44
  feed: string;
@@ -37,7 +37,7 @@ class FeedClient {
37
37
  params.symbols = symbols.join(',');
38
38
  return this.get('fetchTickers', params);
39
39
  }
40
- async fetchOHLCV(symbol, timeframe, since, limit) {
40
+ async fetchOHLCV(symbol, timeframe = '1h', since, limit) {
41
41
  return this.get('fetchOHLCV', { symbol, timeframe, since, limit });
42
42
  }
43
43
  async fetchOracleRound(feed) {
@@ -58,7 +58,10 @@ class FeedClient {
58
58
  .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
59
59
  .join('&');
60
60
  const url = `${this.baseUrl}/api/feeds/${this.feedName}/${method}${qs ? '?' + qs : ''}`;
61
- const response = await fetch(url, { headers: this.headers });
61
+ const response = await fetch(url, {
62
+ headers: this.headers,
63
+ signal: AbortSignal.timeout(30_000),
64
+ });
62
65
  if (!response.ok) {
63
66
  const body = await response.json().catch(() => ({}));
64
67
  throw new errors_js_1.PmxtError(body.error || response.statusText);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Structured logger for pmxt TypeScript SDK.
3
+ *
4
+ * Thin abstraction over console that:
5
+ * - Attaches a `[pmxt]` prefix for easy filtering
6
+ * - Supports log levels (debug, info, warn, error)
7
+ * - Respects a configurable level threshold via PMXT_LOG_LEVEL
8
+ * - Can be swapped for a real transport later
9
+ */
10
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
11
+ export declare const logger: {
12
+ debug(message: string, context?: Record<string, unknown>): void;
13
+ info(message: string, context?: Record<string, unknown>): void;
14
+ warn(message: string, context?: Record<string, unknown>): void;
15
+ error(message: string, context?: Record<string, unknown>): void;
16
+ setLevel(level: LogLevel): void;
17
+ getLevel(): LogLevel;
18
+ };
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Structured logger for pmxt TypeScript SDK.
4
+ *
5
+ * Thin abstraction over console that:
6
+ * - Attaches a `[pmxt]` prefix for easy filtering
7
+ * - Supports log levels (debug, info, warn, error)
8
+ * - Respects a configurable level threshold via PMXT_LOG_LEVEL
9
+ * - Can be swapped for a real transport later
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.logger = void 0;
13
+ const LEVEL_PRIORITY = {
14
+ debug: 0,
15
+ info: 1,
16
+ warn: 2,
17
+ error: 3,
18
+ silent: 4,
19
+ };
20
+ function getDefaultLevel() {
21
+ if (typeof process !== 'undefined' && process.env?.PMXT_LOG_LEVEL) {
22
+ return process.env.PMXT_LOG_LEVEL;
23
+ }
24
+ return 'info';
25
+ }
26
+ let currentLevel = getDefaultLevel();
27
+ function shouldLog(level) {
28
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[currentLevel];
29
+ }
30
+ exports.logger = {
31
+ debug(message, context) {
32
+ if (!shouldLog('debug'))
33
+ return;
34
+ if (context) {
35
+ console.debug(`[pmxt] ${message}`, context);
36
+ }
37
+ else {
38
+ console.debug(`[pmxt] ${message}`);
39
+ }
40
+ },
41
+ info(message, context) {
42
+ if (!shouldLog('info'))
43
+ return;
44
+ if (context) {
45
+ console.info(`[pmxt] ${message}`, context);
46
+ }
47
+ else {
48
+ console.info(`[pmxt] ${message}`);
49
+ }
50
+ },
51
+ warn(message, context) {
52
+ if (!shouldLog('warn'))
53
+ return;
54
+ if (context) {
55
+ console.warn(`[pmxt] ${message}`, context);
56
+ }
57
+ else {
58
+ console.warn(`[pmxt] ${message}`);
59
+ }
60
+ },
61
+ error(message, context) {
62
+ if (!shouldLog('error'))
63
+ return;
64
+ if (context) {
65
+ console.error(`[pmxt] ${message}`, context);
66
+ }
67
+ else {
68
+ console.error(`[pmxt] ${message}`);
69
+ }
70
+ },
71
+ setLevel(level) {
72
+ currentLevel = level;
73
+ },
74
+ getLevel() {
75
+ return currentLevel;
76
+ },
77
+ };
@@ -22,7 +22,7 @@ export interface MarketOutcome {
22
22
  /** 24-hour price change */
23
23
  priceChange24h?: number;
24
24
  /** Exchange-specific metadata */
25
- metadata?: Record<string, any>;
25
+ metadata?: Record<string, unknown>;
26
26
  /** Best bid price from the order book (when includePrices=True) */
27
27
  bestBid?: number;
28
28
  /** Best ask price from the order book (when includePrices=True) */
@@ -201,7 +201,7 @@ export interface Trade {
201
201
  side: "buy" | "sell" | "unknown";
202
202
  }
203
203
  /**
204
- * An order (open, filled, or cancelled).
204
+ * An order (open, filled, or canceled).
205
205
  */
206
206
  export interface Order {
207
207
  /** Order ID */
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.Router = void 0;
43
43
  const client_js_1 = require("./client.js");
44
+ const logger_js_1 = require("./logger.js");
44
45
  function convertMarket(raw) {
45
46
  const outcomes = (raw.outcomes || []).map((o) => ({
46
47
  outcomeId: o.outcomeId,
@@ -167,7 +168,7 @@ class Router extends client_js_1.Exchange {
167
168
  }
168
169
  }
169
170
  async fetchMatches(marketOrParams = {}) {
170
- console.warn('[pmxt] fetchMatches is deprecated, use fetchMarketMatches instead');
171
+ logger_js_1.logger.warn('fetchMatches is deprecated, use fetchMarketMatches instead');
171
172
  return this.fetchMarketMatches(marketOrParams);
172
173
  }
173
174
  async fetchEventMatches(eventOrParams = {}) {
@@ -224,6 +225,7 @@ class Router extends client_js_1.Exchange {
224
225
  method: 'POST',
225
226
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
226
227
  body: JSON.stringify({ args: [query], credentials: this.getCredentials() }),
228
+ signal: AbortSignal.timeout(30_000),
227
229
  });
228
230
  if (!response.ok) {
229
231
  const body = await response.json().catch(() => ({}));
@@ -121,7 +121,9 @@ class ServerManager {
121
121
  try {
122
122
  // Use native fetch to check health on the actual running port
123
123
  // This avoids issues where this.api is configured with the wrong port
124
- const response = await fetch(`http://localhost:${port}/health`);
124
+ const response = await fetch(`http://localhost:${port}/health`, {
125
+ signal: AbortSignal.timeout(5_000),
126
+ });
125
127
  if (response.ok) {
126
128
  const data = await response.json();
127
129
  return data.status === "ok";
@@ -142,7 +144,9 @@ class ServerManager {
142
144
  const info = this.getServerInfo();
143
145
  if (info) {
144
146
  try {
145
- const response = await fetch(`http://localhost:${info.port}/health`);
147
+ const response = await fetch(`http://localhost:${info.port}/health`, {
148
+ signal: AbortSignal.timeout(5_000),
149
+ });
146
150
  if (response.ok) {
147
151
  const data = await response.json();
148
152
  if (data.status === "ok")
@@ -104,8 +104,21 @@ class SidecarWsClient {
104
104
  const raw = typeof event.data === "string"
105
105
  ? event.data
106
106
  : event.data.toString();
107
- const msg = JSON.parse(raw);
108
- this.dispatch(msg);
107
+ let msg;
108
+ try {
109
+ msg = JSON.parse(raw);
110
+ }
111
+ catch {
112
+ // Non-JSON control frame -- ignore.
113
+ return;
114
+ }
115
+ try {
116
+ this.dispatch(msg);
117
+ }
118
+ catch (err) {
119
+ // Dispatch bug -- log and continue; don't kill the connection.
120
+ console.error('[SidecarWsClient] dispatch error:', err);
121
+ }
109
122
  };
110
123
  });
111
124
  }
@@ -191,6 +204,9 @@ class SidecarWsClient {
191
204
  if (credentials) {
192
205
  message.credentials = credentials;
193
206
  }
207
+ if (!this.ws) {
208
+ throw new errors_js_1.PmxtError('[ws-client] Cannot send: WebSocket not connected');
209
+ }
194
210
  this.ws.send(JSON.stringify(message));
195
211
  return this.waitForData(requestId, timeoutMs);
196
212
  }
@@ -216,6 +232,9 @@ class SidecarWsClient {
216
232
  if (credentials) {
217
233
  message.credentials = credentials;
218
234
  }
235
+ if (!this.ws) {
236
+ throw new errors_js_1.PmxtError('[ws-client] Cannot send: WebSocket not connected');
237
+ }
219
238
  this.ws.send(JSON.stringify(message));
220
239
  // Wait for first data event
221
240
  await this.waitForData(requestId, timeoutMs);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.43.19",
3
+ "version": "2.43.24",
4
4
  "description": "OpenAPI client for pmxtjs",
5
5
  "author": "OpenAPI-Generator",
6
6
  "repository": {
@@ -131,7 +131,7 @@ export const OrderStatusEnum = {
131
131
  Pending: 'pending',
132
132
  Open: 'open',
133
133
  Filled: 'filled',
134
- Cancelled: 'cancelled',
134
+ Canceled: 'canceled',
135
135
  Rejected: 'rejected'
136
136
  } as const;
137
137
  export type OrderStatusEnum = typeof OrderStatusEnum[keyof typeof OrderStatusEnum];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.43.19",
3
+ "version": "2.43.24",
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.43.19",
46
+ "pmxt-core": "2.43.24",
47
47
  "ws": "^8.18.0"
48
48
  },
49
49
  "devDependencies": {
package/pmxt/args.ts CHANGED
@@ -1,3 +1,3 @@
1
- export function buildArgsWithOptionalOptions(primary?: any): any[] {
1
+ export function buildArgsWithOptionalOptions<T>(primary?: T): T[] {
2
2
  return primary !== undefined ? [primary] : [];
3
3
  }
package/pmxt/client.ts CHANGED
@@ -392,7 +392,10 @@ export abstract class Exchange {
392
392
 
393
393
  for (let attempt = 0; attempt <= delays.length; attempt++) {
394
394
  try {
395
- return await fetch(input, init);
395
+ return await fetch(input, {
396
+ ...init,
397
+ signal: AbortSignal.timeout(30_000),
398
+ });
396
399
  } catch (error) {
397
400
  lastError = error;
398
401
  if (attempt >= delays.length) break;
package/pmxt/errors.ts CHANGED
@@ -49,29 +49,26 @@ export class PermissionDenied extends PmxtError {
49
49
  }
50
50
 
51
51
  export class NotFoundError extends PmxtError {
52
- constructor(message: string, exchange?: string) {
53
- super(message, "NOT_FOUND", false, exchange);
52
+ constructor(message: string, exchange?: string, code: string = "NOT_FOUND") {
53
+ super(message, code, false, exchange);
54
54
  }
55
55
  }
56
56
 
57
57
  export class OrderNotFound extends NotFoundError {
58
58
  constructor(orderId: string, exchange?: string) {
59
- super(`Order not found: ${orderId}`, exchange);
60
- (this as any).code = "ORDER_NOT_FOUND";
59
+ super(`Order not found: ${orderId}`, exchange, "ORDER_NOT_FOUND");
61
60
  }
62
61
  }
63
62
 
64
63
  export class MarketNotFound extends NotFoundError {
65
64
  constructor(marketId: string, exchange?: string) {
66
- super(`Market not found: ${marketId}`, exchange);
67
- (this as any).code = "MARKET_NOT_FOUND";
65
+ super(`Market not found: ${marketId}`, exchange, "MARKET_NOT_FOUND");
68
66
  }
69
67
  }
70
68
 
71
69
  export class EventNotFound extends NotFoundError {
72
70
  constructor(identifier: string, exchange?: string) {
73
- super(`Event not found: ${identifier}`, exchange);
74
- (this as any).code = "EVENT_NOT_FOUND";
71
+ super(`Event not found: ${identifier}`, exchange, "EVENT_NOT_FOUND");
75
72
  }
76
73
  }
77
74
 
@@ -137,23 +134,27 @@ const ERROR_CODE_MAP: Record<string, new (...args: any[]) => PmxtError> = {
137
134
  };
138
135
 
139
136
  /** Convert a server error response object into a typed PmxtError. */
140
- export function fromServerError(errorData: any): PmxtError {
137
+ export function fromServerError(errorData: unknown): PmxtError {
141
138
  if (typeof errorData === "string") {
142
139
  return new PmxtError(errorData);
143
140
  }
144
141
 
145
- const message = errorData.message || "Unknown error";
146
- const code = errorData.code || "UNKNOWN_ERROR";
147
- const retryable = errorData.retryable || false;
148
- const exchange = errorData.exchange;
142
+ const data = errorData as Record<string, unknown>;
143
+
144
+ const message = (typeof data.message === "string" ? data.message : undefined) || "Unknown error";
145
+ const code = (typeof data.code === "string" ? data.code : undefined) || "UNKNOWN_ERROR";
146
+ const retryable = typeof data.retryable === "boolean" ? data.retryable : false;
147
+ const exchange = typeof data.exchange === "string" ? data.exchange : undefined;
149
148
 
150
149
  const ErrorClass = ERROR_CODE_MAP[code];
151
150
 
152
151
  if (ErrorClass === RateLimitExceeded) {
153
- return new RateLimitExceeded(message, errorData.retryAfter, exchange);
152
+ const retryAfter = typeof data.retryAfter === "number" ? data.retryAfter : undefined;
153
+ return new RateLimitExceeded(message, retryAfter, exchange);
154
154
  }
155
155
  if (ErrorClass === ValidationError) {
156
- return new ValidationError(message, errorData.field, exchange);
156
+ const field = typeof data.field === "string" ? data.field : undefined;
157
+ return new ValidationError(message, field, exchange);
157
158
  }
158
159
  if (ErrorClass) {
159
160
  return new ErrorClass(message, exchange);
@@ -11,7 +11,7 @@ import { PmxtError } from "./errors.js";
11
11
 
12
12
  export interface Ticker {
13
13
  symbol: string;
14
- info: any;
14
+ info: Record<string, unknown>;
15
15
  timestamp: number | undefined;
16
16
  datetime: string | undefined;
17
17
  high: number | undefined;
@@ -44,7 +44,7 @@ export interface Market {
44
44
  quote: string;
45
45
  active: boolean;
46
46
  type: string;
47
- info: any;
47
+ info: Record<string, unknown>;
48
48
  }
49
49
 
50
50
  export interface OracleRound {
@@ -94,7 +94,7 @@ export class FeedClient {
94
94
  return this.get<Tickers>('fetchTickers', params);
95
95
  }
96
96
 
97
- async fetchOHLCV(symbol: string, timeframe?: string, since?: number, limit?: number): Promise<OHLCV[]> {
97
+ async fetchOHLCV(symbol: string, timeframe: string = '1h', since?: number, limit?: number): Promise<OHLCV[]> {
98
98
  return this.get<OHLCV[]>('fetchOHLCV', { symbol, timeframe, since, limit });
99
99
  }
100
100
 
@@ -125,7 +125,10 @@ export class FeedClient {
125
125
 
126
126
  const url = `${this.baseUrl}/api/feeds/${this.feedName}/${method}${qs ? '?' + qs : ''}`;
127
127
 
128
- const response = await fetch(url, { headers: this.headers });
128
+ const response = await fetch(url, {
129
+ headers: this.headers,
130
+ signal: AbortSignal.timeout(30_000),
131
+ });
129
132
 
130
133
  if (!response.ok) {
131
134
  const body = await response.json().catch(() => ({}));
package/pmxt/logger.ts ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Structured logger for pmxt TypeScript SDK.
3
+ *
4
+ * Thin abstraction over console that:
5
+ * - Attaches a `[pmxt]` prefix for easy filtering
6
+ * - Supports log levels (debug, info, warn, error)
7
+ * - Respects a configurable level threshold via PMXT_LOG_LEVEL
8
+ * - Can be swapped for a real transport later
9
+ */
10
+
11
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
12
+
13
+ const LEVEL_PRIORITY: Record<LogLevel, number> = {
14
+ debug: 0,
15
+ info: 1,
16
+ warn: 2,
17
+ error: 3,
18
+ silent: 4,
19
+ };
20
+
21
+ function getDefaultLevel(): LogLevel {
22
+ if (typeof process !== 'undefined' && process.env?.PMXT_LOG_LEVEL) {
23
+ return process.env.PMXT_LOG_LEVEL as LogLevel;
24
+ }
25
+ return 'info';
26
+ }
27
+
28
+ let currentLevel: LogLevel = getDefaultLevel();
29
+
30
+ function shouldLog(level: LogLevel): boolean {
31
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[currentLevel];
32
+ }
33
+
34
+ export const logger = {
35
+ debug(message: string, context?: Record<string, unknown>): void {
36
+ if (!shouldLog('debug')) return;
37
+ if (context) {
38
+ console.debug(`[pmxt] ${message}`, context);
39
+ } else {
40
+ console.debug(`[pmxt] ${message}`);
41
+ }
42
+ },
43
+
44
+ info(message: string, context?: Record<string, unknown>): void {
45
+ if (!shouldLog('info')) return;
46
+ if (context) {
47
+ console.info(`[pmxt] ${message}`, context);
48
+ } else {
49
+ console.info(`[pmxt] ${message}`);
50
+ }
51
+ },
52
+
53
+ warn(message: string, context?: Record<string, unknown>): void {
54
+ if (!shouldLog('warn')) return;
55
+ if (context) {
56
+ console.warn(`[pmxt] ${message}`, context);
57
+ } else {
58
+ console.warn(`[pmxt] ${message}`);
59
+ }
60
+ },
61
+
62
+ error(message: string, context?: Record<string, unknown>): void {
63
+ if (!shouldLog('error')) return;
64
+ if (context) {
65
+ console.error(`[pmxt] ${message}`, context);
66
+ } else {
67
+ console.error(`[pmxt] ${message}`);
68
+ }
69
+ },
70
+
71
+ setLevel(level: LogLevel): void {
72
+ currentLevel = level;
73
+ },
74
+
75
+ getLevel(): LogLevel {
76
+ return currentLevel;
77
+ },
78
+ };
package/pmxt/models.ts CHANGED
@@ -28,7 +28,7 @@ export interface MarketOutcome {
28
28
  priceChange24h?: number;
29
29
 
30
30
  /** Exchange-specific metadata */
31
- metadata?: Record<string, any>;
31
+ metadata?: Record<string, unknown>;
32
32
 
33
33
  /** Best bid price from the order book (when includePrices=True) */
34
34
  bestBid?: number;
@@ -271,7 +271,7 @@ export interface Trade {
271
271
  }
272
272
 
273
273
  /**
274
- * An order (open, filled, or cancelled).
274
+ * An order (open, filled, or canceled).
275
275
  */
276
276
  export interface Order {
277
277
  /** Order ID */
package/pmxt/router.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import { Exchange, ExchangeOptions } from "./client.js";
9
+ import { logger } from "./logger.js";
9
10
  import {
10
11
  MatchResult,
11
12
  MatchRelation,
@@ -204,7 +205,7 @@ export class Router extends Exchange {
204
205
  limit?: number;
205
206
  includePrices?: boolean;
206
207
  } = {}): Promise<MatchResult[]> {
207
- console.warn('[pmxt] fetchMatches is deprecated, use fetchMarketMatches instead');
208
+ logger.warn('fetchMatches is deprecated, use fetchMarketMatches instead');
208
209
  return this.fetchMarketMatches(marketOrParams as any);
209
210
  }
210
211
 
@@ -297,6 +298,7 @@ export class Router extends Exchange {
297
298
  method: 'POST',
298
299
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
299
300
  body: JSON.stringify({ args: [query], credentials: this.getCredentials() }),
301
+ signal: AbortSignal.timeout(30_000),
300
302
  });
301
303
  if (!response.ok) {
302
304
  const body = await response.json().catch(() => ({}));
@@ -108,7 +108,9 @@ export class ServerManager {
108
108
  try {
109
109
  // Use native fetch to check health on the actual running port
110
110
  // This avoids issues where this.api is configured with the wrong port
111
- const response = await fetch(`http://localhost:${port}/health`);
111
+ const response = await fetch(`http://localhost:${port}/health`, {
112
+ signal: AbortSignal.timeout(5_000),
113
+ });
112
114
  if (response.ok) {
113
115
  const data = await response.json();
114
116
  return (data as any).status === "ok";
@@ -129,7 +131,9 @@ export class ServerManager {
129
131
  const info = this.getServerInfo();
130
132
  if (info) {
131
133
  try {
132
- const response = await fetch(`http://localhost:${info.port}/health`);
134
+ const response = await fetch(`http://localhost:${info.port}/health`, {
135
+ signal: AbortSignal.timeout(5_000),
136
+ });
133
137
  if (response.ok) {
134
138
  const data = await response.json() as any;
135
139
  if (data.status === "ok") return;
package/pmxt/ws-client.ts CHANGED
@@ -129,8 +129,19 @@ export class SidecarWsClient {
129
129
  const raw = typeof event.data === "string"
130
130
  ? event.data
131
131
  : event.data.toString();
132
- const msg: WsMessage = JSON.parse(raw);
133
- this.dispatch(msg);
132
+ let msg: WsMessage;
133
+ try {
134
+ msg = JSON.parse(raw);
135
+ } catch {
136
+ // Non-JSON control frame -- ignore.
137
+ return;
138
+ }
139
+ try {
140
+ this.dispatch(msg);
141
+ } catch (err) {
142
+ // Dispatch bug -- log and continue; don't kill the connection.
143
+ console.error('[SidecarWsClient] dispatch error:', err);
144
+ }
134
145
  };
135
146
  });
136
147
  }
@@ -240,7 +251,10 @@ export class SidecarWsClient {
240
251
  message.credentials = credentials;
241
252
  }
242
253
 
243
- this.ws!.send(JSON.stringify(message));
254
+ if (!this.ws) {
255
+ throw new PmxtError('[ws-client] Cannot send: WebSocket not connected');
256
+ }
257
+ this.ws.send(JSON.stringify(message));
244
258
 
245
259
  return this.waitForData(requestId, timeoutMs);
246
260
  }
@@ -278,7 +292,10 @@ export class SidecarWsClient {
278
292
  message.credentials = credentials;
279
293
  }
280
294
 
281
- this.ws!.send(JSON.stringify(message));
295
+ if (!this.ws) {
296
+ throw new PmxtError('[ws-client] Cannot send: WebSocket not connected');
297
+ }
298
+ this.ws.send(JSON.stringify(message));
282
299
 
283
300
  // Wait for first data event
284
301
  await this.waitForData(requestId, timeoutMs);