pmxtjs 2.46.3 → 2.46.4

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.
@@ -384,6 +384,7 @@ export class Exchange {
384
384
  }
385
385
  internals.activeSubs.delete(subKey);
386
386
  internals.subscriptions.delete(requestId);
387
+ internals.dataQueues.delete(requestId);
387
388
  internals.dataStore.delete(requestId);
388
389
  const firstArg = args[0] ?? "";
389
390
  const symbols = Array.isArray(firstArg)
@@ -18,7 +18,9 @@ export declare class SidecarWsClient {
18
18
  private accessToken;
19
19
  private authParamName;
20
20
  private closed;
21
- /** requestId -> latest data payload */
21
+ /** requestId -> queued data payloads for single-event watch methods */
22
+ private dataQueues;
23
+ /** requestId[:symbol] -> latest data payload for batch snapshots */
22
24
  private dataStore;
23
25
  /** requestId -> subscription metadata */
24
26
  private subscriptions;
@@ -30,6 +32,7 @@ export declare class SidecarWsClient {
30
32
  private connect;
31
33
  private getWebSocketConstructor;
32
34
  private dispatch;
35
+ private deliverOrQueue;
33
36
  subscribe(exchange: string, method: string, args: any[], credentials?: Record<string, any>, timeoutMs?: number): Promise<any>;
34
37
  subscribeBatch(exchange: string, method: string, args: any[], credentials?: Record<string, any>, timeoutMs?: number): Promise<Record<string, any>>;
35
38
  close(): void;
@@ -7,6 +7,7 @@
7
7
  * does not support the /ws endpoint.
8
8
  */
9
9
  import { PmxtError } from "./errors.js";
10
+ const MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION = 100_000;
10
11
  /**
11
12
  * Multiplexed WebSocket client for the pmxt sidecar.
12
13
  *
@@ -19,7 +20,9 @@ export class SidecarWsClient {
19
20
  accessToken;
20
21
  authParamName;
21
22
  closed = false;
22
- /** requestId -> latest data payload */
23
+ /** requestId -> queued data payloads for single-event watch methods */
24
+ dataQueues = new Map();
25
+ /** requestId[:symbol] -> latest data payload for batch snapshots */
23
26
  dataStore = new Map();
24
27
  /** requestId -> subscription metadata */
25
28
  subscriptions = new Map();
@@ -154,16 +157,27 @@ export class SidecarWsClient {
154
157
  if (eventType === "data" && requestId) {
155
158
  const symbol = msg.symbol || "";
156
159
  const data = msg.data || {};
157
- // Store by (requestId:symbol) for batch methods
160
+ // Store by (requestId:symbol) for batch methods.
158
161
  this.dataStore.set(`${requestId}:${symbol}`, data);
159
- // Store by requestId alone for single-symbol methods
160
- this.dataStore.set(requestId, data);
161
- const sub = this.subscriptions.get(requestId);
162
- if (sub?.resolve) {
163
- sub.resolve(data);
164
- sub.resolve = null;
165
- sub.reject = null;
166
- }
162
+ this.deliverOrQueue(requestId, data);
163
+ }
164
+ }
165
+ deliverOrQueue(requestId, data) {
166
+ const sub = this.subscriptions.get(requestId);
167
+ if (sub?.resolve) {
168
+ sub.resolve(data);
169
+ sub.resolve = null;
170
+ sub.reject = null;
171
+ return;
172
+ }
173
+ let queue = this.dataQueues.get(requestId);
174
+ if (!queue) {
175
+ queue = [];
176
+ this.dataQueues.set(requestId, queue);
177
+ }
178
+ queue.push(data);
179
+ if (queue.length > MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION) {
180
+ queue.splice(0, queue.length - MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION);
167
181
  }
168
182
  }
169
183
  // ------------------------------------------------------------------
@@ -233,8 +247,8 @@ export class SidecarWsClient {
233
247
  throw new PmxtError('[ws-client] Cannot send: WebSocket not connected');
234
248
  }
235
249
  this.ws.send(JSON.stringify(message));
236
- // Wait for first data event
237
- await this.waitForData(requestId, timeoutMs);
250
+ // Wait for first data event.
251
+ const firstData = await this.waitForData(requestId, timeoutMs);
238
252
  // Collect per-symbol data
239
253
  const result = {};
240
254
  for (const symbol of symbols) {
@@ -246,9 +260,8 @@ export class SidecarWsClient {
246
260
  }
247
261
  // If no per-symbol data, return the single data event as-is
248
262
  if (Object.keys(result).length === 0) {
249
- const data = this.dataStore.get(requestId);
250
- if (data && typeof data === "object") {
251
- return data;
263
+ if (firstData && typeof firstData === "object") {
264
+ return firstData;
252
265
  }
253
266
  }
254
267
  return result;
@@ -264,6 +277,8 @@ export class SidecarWsClient {
264
277
  }
265
278
  this.ws = null;
266
279
  }
280
+ this.dataQueues.clear();
281
+ this.dataStore.clear();
267
282
  }
268
283
  get connected() {
269
284
  return this.ws !== null && !this.closed;
@@ -272,11 +287,14 @@ export class SidecarWsClient {
272
287
  // Internal
273
288
  // ------------------------------------------------------------------
274
289
  waitForData(requestId, timeoutMs) {
275
- // Check if data is already available
276
- const existing = this.dataStore.get(requestId);
277
- if (existing !== undefined) {
278
- this.dataStore.delete(requestId);
279
- return Promise.resolve(existing);
290
+ // Check if queued data is already available.
291
+ const queue = this.dataQueues.get(requestId);
292
+ if (queue && queue.length > 0) {
293
+ const next = queue.shift();
294
+ if (queue.length === 0) {
295
+ this.dataQueues.delete(requestId);
296
+ }
297
+ return Promise.resolve(next);
280
298
  }
281
299
  return new Promise((resolve, reject) => {
282
300
  const sub = this.subscriptions.get(requestId);
@@ -387,6 +387,7 @@ class Exchange {
387
387
  }
388
388
  internals.activeSubs.delete(subKey);
389
389
  internals.subscriptions.delete(requestId);
390
+ internals.dataQueues.delete(requestId);
390
391
  internals.dataStore.delete(requestId);
391
392
  const firstArg = args[0] ?? "";
392
393
  const symbols = Array.isArray(firstArg)
@@ -18,7 +18,9 @@ export declare class SidecarWsClient {
18
18
  private accessToken;
19
19
  private authParamName;
20
20
  private closed;
21
- /** requestId -> latest data payload */
21
+ /** requestId -> queued data payloads for single-event watch methods */
22
+ private dataQueues;
23
+ /** requestId[:symbol] -> latest data payload for batch snapshots */
22
24
  private dataStore;
23
25
  /** requestId -> subscription metadata */
24
26
  private subscriptions;
@@ -30,6 +32,7 @@ export declare class SidecarWsClient {
30
32
  private connect;
31
33
  private getWebSocketConstructor;
32
34
  private dispatch;
35
+ private deliverOrQueue;
33
36
  subscribe(exchange: string, method: string, args: any[], credentials?: Record<string, any>, timeoutMs?: number): Promise<any>;
34
37
  subscribeBatch(exchange: string, method: string, args: any[], credentials?: Record<string, any>, timeoutMs?: number): Promise<Record<string, any>>;
35
38
  close(): void;
@@ -10,6 +10,7 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.SidecarWsClient = void 0;
12
12
  const errors_js_1 = require("./errors.js");
13
+ const MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION = 100_000;
13
14
  /**
14
15
  * Multiplexed WebSocket client for the pmxt sidecar.
15
16
  *
@@ -22,7 +23,9 @@ class SidecarWsClient {
22
23
  accessToken;
23
24
  authParamName;
24
25
  closed = false;
25
- /** requestId -> latest data payload */
26
+ /** requestId -> queued data payloads for single-event watch methods */
27
+ dataQueues = new Map();
28
+ /** requestId[:symbol] -> latest data payload for batch snapshots */
26
29
  dataStore = new Map();
27
30
  /** requestId -> subscription metadata */
28
31
  subscriptions = new Map();
@@ -157,16 +160,27 @@ class SidecarWsClient {
157
160
  if (eventType === "data" && requestId) {
158
161
  const symbol = msg.symbol || "";
159
162
  const data = msg.data || {};
160
- // Store by (requestId:symbol) for batch methods
163
+ // Store by (requestId:symbol) for batch methods.
161
164
  this.dataStore.set(`${requestId}:${symbol}`, data);
162
- // Store by requestId alone for single-symbol methods
163
- this.dataStore.set(requestId, data);
164
- const sub = this.subscriptions.get(requestId);
165
- if (sub?.resolve) {
166
- sub.resolve(data);
167
- sub.resolve = null;
168
- sub.reject = null;
169
- }
165
+ this.deliverOrQueue(requestId, data);
166
+ }
167
+ }
168
+ deliverOrQueue(requestId, data) {
169
+ const sub = this.subscriptions.get(requestId);
170
+ if (sub?.resolve) {
171
+ sub.resolve(data);
172
+ sub.resolve = null;
173
+ sub.reject = null;
174
+ return;
175
+ }
176
+ let queue = this.dataQueues.get(requestId);
177
+ if (!queue) {
178
+ queue = [];
179
+ this.dataQueues.set(requestId, queue);
180
+ }
181
+ queue.push(data);
182
+ if (queue.length > MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION) {
183
+ queue.splice(0, queue.length - MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION);
170
184
  }
171
185
  }
172
186
  // ------------------------------------------------------------------
@@ -236,8 +250,8 @@ class SidecarWsClient {
236
250
  throw new errors_js_1.PmxtError('[ws-client] Cannot send: WebSocket not connected');
237
251
  }
238
252
  this.ws.send(JSON.stringify(message));
239
- // Wait for first data event
240
- await this.waitForData(requestId, timeoutMs);
253
+ // Wait for first data event.
254
+ const firstData = await this.waitForData(requestId, timeoutMs);
241
255
  // Collect per-symbol data
242
256
  const result = {};
243
257
  for (const symbol of symbols) {
@@ -249,9 +263,8 @@ class SidecarWsClient {
249
263
  }
250
264
  // If no per-symbol data, return the single data event as-is
251
265
  if (Object.keys(result).length === 0) {
252
- const data = this.dataStore.get(requestId);
253
- if (data && typeof data === "object") {
254
- return data;
266
+ if (firstData && typeof firstData === "object") {
267
+ return firstData;
255
268
  }
256
269
  }
257
270
  return result;
@@ -267,6 +280,8 @@ class SidecarWsClient {
267
280
  }
268
281
  this.ws = null;
269
282
  }
283
+ this.dataQueues.clear();
284
+ this.dataStore.clear();
270
285
  }
271
286
  get connected() {
272
287
  return this.ws !== null && !this.closed;
@@ -275,11 +290,14 @@ class SidecarWsClient {
275
290
  // Internal
276
291
  // ------------------------------------------------------------------
277
292
  waitForData(requestId, timeoutMs) {
278
- // Check if data is already available
279
- const existing = this.dataStore.get(requestId);
280
- if (existing !== undefined) {
281
- this.dataStore.delete(requestId);
282
- return Promise.resolve(existing);
293
+ // Check if queued data is already available.
294
+ const queue = this.dataQueues.get(requestId);
295
+ if (queue && queue.length > 0) {
296
+ const next = queue.shift();
297
+ if (queue.length === 0) {
298
+ this.dataQueues.delete(requestId);
299
+ }
300
+ return Promise.resolve(next);
283
301
  }
284
302
  return new Promise((resolve, reject) => {
285
303
  const sub = this.subscriptions.get(requestId);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.46.3",
3
+ "version": "2.46.4",
4
4
  "description": "OpenAPI client for pmxtjs",
5
5
  "author": "OpenAPI-Generator",
6
6
  "repository": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.46.3",
3
+ "version": "2.46.4",
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.46.3",
46
+ "pmxt-core": "2.46.4",
47
47
  "ws": "^8.18.0"
48
48
  },
49
49
  "devDependencies": {
package/pmxt/client.ts CHANGED
@@ -61,6 +61,7 @@ interface SidecarWsClientInternals {
61
61
  ws: RawWebSocketLike | null;
62
62
  activeSubs: Map<string, string>;
63
63
  subscriptions: Map<string, { reject: ((error: Error) => void) | null }>;
64
+ dataQueues: Map<string, any[]>;
64
65
  dataStore: Map<string, any>;
65
66
  }
66
67
 
@@ -538,6 +539,7 @@ export abstract class Exchange {
538
539
 
539
540
  internals.activeSubs.delete(subKey);
540
541
  internals.subscriptions.delete(requestId);
542
+ internals.dataQueues.delete(requestId);
541
543
  internals.dataStore.delete(requestId);
542
544
 
543
545
  const firstArg = args[0] ?? "";
package/pmxt/ws-client.ts CHANGED
@@ -9,6 +9,8 @@
9
9
 
10
10
  import { PmxtError } from "./errors.js";
11
11
 
12
+ const MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION = 100_000;
13
+
12
14
  interface WsSubscription {
13
15
  readonly requestId: string;
14
16
  readonly method: string;
@@ -39,7 +41,9 @@ export class SidecarWsClient {
39
41
  private authParamName: string;
40
42
  private closed = false;
41
43
 
42
- /** requestId -> latest data payload */
44
+ /** requestId -> queued data payloads for single-event watch methods */
45
+ private dataQueues: Map<string, any[]> = new Map();
46
+ /** requestId[:symbol] -> latest data payload for batch snapshots */
43
47
  private dataStore: Map<string, any> = new Map();
44
48
  /** requestId -> subscription metadata */
45
49
  private subscriptions: Map<string, WsSubscription> = new Map();
@@ -189,17 +193,30 @@ export class SidecarWsClient {
189
193
  const symbol = msg.symbol || "";
190
194
  const data = msg.data || {};
191
195
 
192
- // Store by (requestId:symbol) for batch methods
196
+ // Store by (requestId:symbol) for batch methods.
193
197
  this.dataStore.set(`${requestId}:${symbol}`, data);
194
- // Store by requestId alone for single-symbol methods
195
- this.dataStore.set(requestId, data);
198
+ this.deliverOrQueue(requestId, data);
199
+ }
200
+ }
196
201
 
197
- const sub = this.subscriptions.get(requestId);
198
- if (sub?.resolve) {
199
- sub.resolve(data);
200
- sub.resolve = null;
201
- sub.reject = null;
202
- }
202
+ private deliverOrQueue(requestId: string, data: any): void {
203
+ const sub = this.subscriptions.get(requestId);
204
+ if (sub?.resolve) {
205
+ sub.resolve(data);
206
+ sub.resolve = null;
207
+ sub.reject = null;
208
+ return;
209
+ }
210
+
211
+ let queue = this.dataQueues.get(requestId);
212
+ if (!queue) {
213
+ queue = [];
214
+ this.dataQueues.set(requestId, queue);
215
+ }
216
+ queue.push(data);
217
+
218
+ if (queue.length > MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION) {
219
+ queue.splice(0, queue.length - MAX_QUEUED_MESSAGES_PER_SUBSCRIPTION);
203
220
  }
204
221
  }
205
222
 
@@ -297,8 +314,8 @@ export class SidecarWsClient {
297
314
  }
298
315
  this.ws.send(JSON.stringify(message));
299
316
 
300
- // Wait for first data event
301
- await this.waitForData(requestId, timeoutMs);
317
+ // Wait for first data event.
318
+ const firstData = await this.waitForData(requestId, timeoutMs);
302
319
 
303
320
  // Collect per-symbol data
304
321
  const result: Record<string, any> = {};
@@ -312,9 +329,8 @@ export class SidecarWsClient {
312
329
 
313
330
  // If no per-symbol data, return the single data event as-is
314
331
  if (Object.keys(result).length === 0) {
315
- const data = this.dataStore.get(requestId);
316
- if (data && typeof data === "object") {
317
- return data;
332
+ if (firstData && typeof firstData === "object") {
333
+ return firstData;
318
334
  }
319
335
  }
320
336
 
@@ -331,6 +347,8 @@ export class SidecarWsClient {
331
347
  }
332
348
  this.ws = null;
333
349
  }
350
+ this.dataQueues.clear();
351
+ this.dataStore.clear();
334
352
  }
335
353
 
336
354
  get connected(): boolean {
@@ -342,11 +360,14 @@ export class SidecarWsClient {
342
360
  // ------------------------------------------------------------------
343
361
 
344
362
  private waitForData(requestId: string, timeoutMs: number): Promise<any> {
345
- // Check if data is already available
346
- const existing = this.dataStore.get(requestId);
347
- if (existing !== undefined) {
348
- this.dataStore.delete(requestId);
349
- return Promise.resolve(existing);
363
+ // Check if queued data is already available.
364
+ const queue = this.dataQueues.get(requestId);
365
+ if (queue && queue.length > 0) {
366
+ const next = queue.shift();
367
+ if (queue.length === 0) {
368
+ this.dataQueues.delete(requestId);
369
+ }
370
+ return Promise.resolve(next);
350
371
  }
351
372
 
352
373
  return new Promise<any>((resolve, reject) => {