@chainstream-io/sdk 0.1.21 → 0.1.22

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.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ## @chainstream-io/sdk@0.1.21
1
+ ## @chainstream-io/sdk@0.1.22
2
2
 
3
3
  This generator creates TypeScript/JavaScript client that utilizes [Fetch API](https://fetch.spec.whatwg.org/). The generated Node module can be used in the following environments:
4
4
 
@@ -320,12 +320,42 @@ interface Unsubscrible {
320
320
  declare class StreamApi {
321
321
  private realtimeClient;
322
322
  private listenersMap;
323
+ private context;
324
+ private initPromise;
323
325
  constructor(context: DexRequestContext);
326
+ /**
327
+ * Initialize Centrifuge client with current token
328
+ * This is called lazily when connect() is called
329
+ */
330
+ private initClient;
331
+ /**
332
+ * Wait for initialization to complete
333
+ * If not initialized, auto-connect first
334
+ */
335
+ private ensureInitialized;
336
+ /**
337
+ * Get token value from string or TokenProvider
338
+ */
339
+ private getTokenValue;
324
340
  /**
325
341
  * Build WebSocket URL with token as query parameter
326
342
  */
327
343
  private buildWsUrl;
344
+ /**
345
+ * Connect to the WebSocket server.
346
+ * This is automatically called when you use subscribe methods if not already connected.
347
+ * You can also call this method manually for explicit control.
348
+ */
328
349
  connect(): void;
350
+ /**
351
+ * Disconnect from the WebSocket server.
352
+ * All subscriptions will be automatically removed.
353
+ */
354
+ disconnect(): void;
355
+ /**
356
+ * Check if the WebSocket is currently connected.
357
+ */
358
+ isConnected(): boolean;
329
359
  /**
330
360
  * Start batching commands for efficient bulk operations
331
361
  * All subscription commands after this call will be batched until stopBatching is called
@@ -470,8 +500,16 @@ interface DexAggregatorOptions {
470
500
  debug?: boolean;
471
501
  serverUrl?: string;
472
502
  streamUrl?: string;
503
+ /**
504
+ * Whether to automatically connect to WebSocket on initialization.
505
+ * Default: false
506
+ *
507
+ * If set to true, WebSocket will connect automatically.
508
+ * If false or not set, you need to manually call `client.stream.connect()` when needed.
509
+ */
510
+ autoConnectWebSocket?: boolean;
473
511
  }
474
- declare const LIB_VERSION = "0.1.20";
512
+ declare const LIB_VERSION = "0.1.22";
475
513
  declare class DexClient {
476
514
  readonly requestCtx: DexRequestContext;
477
515
  readonly _configuration: Configuration;
@@ -320,12 +320,42 @@ interface Unsubscrible {
320
320
  declare class StreamApi {
321
321
  private realtimeClient;
322
322
  private listenersMap;
323
+ private context;
324
+ private initPromise;
323
325
  constructor(context: DexRequestContext);
326
+ /**
327
+ * Initialize Centrifuge client with current token
328
+ * This is called lazily when connect() is called
329
+ */
330
+ private initClient;
331
+ /**
332
+ * Wait for initialization to complete
333
+ * If not initialized, auto-connect first
334
+ */
335
+ private ensureInitialized;
336
+ /**
337
+ * Get token value from string or TokenProvider
338
+ */
339
+ private getTokenValue;
324
340
  /**
325
341
  * Build WebSocket URL with token as query parameter
326
342
  */
327
343
  private buildWsUrl;
344
+ /**
345
+ * Connect to the WebSocket server.
346
+ * This is automatically called when you use subscribe methods if not already connected.
347
+ * You can also call this method manually for explicit control.
348
+ */
328
349
  connect(): void;
350
+ /**
351
+ * Disconnect from the WebSocket server.
352
+ * All subscriptions will be automatically removed.
353
+ */
354
+ disconnect(): void;
355
+ /**
356
+ * Check if the WebSocket is currently connected.
357
+ */
358
+ isConnected(): boolean;
329
359
  /**
330
360
  * Start batching commands for efficient bulk operations
331
361
  * All subscription commands after this call will be batched until stopBatching is called
@@ -470,8 +500,16 @@ interface DexAggregatorOptions {
470
500
  debug?: boolean;
471
501
  serverUrl?: string;
472
502
  streamUrl?: string;
503
+ /**
504
+ * Whether to automatically connect to WebSocket on initialization.
505
+ * Default: false
506
+ *
507
+ * If set to true, WebSocket will connect automatically.
508
+ * If false or not set, you need to manually call `client.stream.connect()` when needed.
509
+ */
510
+ autoConnectWebSocket?: boolean;
473
511
  }
474
- declare const LIB_VERSION = "0.1.20";
512
+ declare const LIB_VERSION = "0.1.22";
475
513
  declare class DexClient {
476
514
  readonly requestCtx: DexRequestContext;
477
515
  readonly _configuration: Configuration;
package/dist/index.cjs CHANGED
@@ -289,10 +289,24 @@ var StreamApi = class {
289
289
  constructor(context) {
290
290
  __publicField(this, "realtimeClient");
291
291
  __publicField(this, "listenersMap");
292
- const realtimeEndpoint = this.buildWsUrl(context.streamUrl, context.accessToken);
292
+ __publicField(this, "context");
293
+ __publicField(this, "initPromise", null);
294
+ this.context = context;
295
+ this.listenersMap = /* @__PURE__ */ new Map();
296
+ }
297
+ /**
298
+ * Initialize Centrifuge client with current token
299
+ * This is called lazily when connect() is called
300
+ */
301
+ async initClient() {
302
+ if (this.realtimeClient) {
303
+ return;
304
+ }
305
+ const token = await this.getTokenValue();
306
+ const realtimeEndpoint = this.buildWsUrl(this.context.streamUrl, token);
293
307
  this.realtimeClient = new import_centrifuge.Centrifuge(realtimeEndpoint, {
294
308
  getToken: async (_ctx) => {
295
- return typeof context.accessToken === "string" ? context.accessToken : await context.accessToken.getToken();
309
+ return this.getTokenValue();
296
310
  }
297
311
  });
298
312
  this.realtimeClient.on("connected", () => {
@@ -302,34 +316,73 @@ var StreamApi = class {
302
316
  }).on("error", (err) => {
303
317
  console.error("[streaming] error: ", err);
304
318
  });
305
- this.listenersMap = /* @__PURE__ */ new Map();
319
+ }
320
+ /**
321
+ * Wait for initialization to complete
322
+ * If not initialized, auto-connect first
323
+ */
324
+ async ensureInitialized() {
325
+ if (!this.initPromise) {
326
+ this.connect();
327
+ }
328
+ await this.initPromise;
329
+ }
330
+ /**
331
+ * Get token value from string or TokenProvider
332
+ */
333
+ async getTokenValue() {
334
+ return typeof this.context.accessToken === "string" ? this.context.accessToken : await this.context.accessToken.getToken();
306
335
  }
307
336
  /**
308
337
  * Build WebSocket URL with token as query parameter
309
338
  */
310
- buildWsUrl(endpoint, accessToken) {
339
+ buildWsUrl(endpoint, token) {
311
340
  const url = new URL(endpoint);
312
- if (typeof accessToken === "string") {
313
- url.searchParams.set("token", accessToken);
314
- }
341
+ url.searchParams.set("token", token);
315
342
  return url.toString();
316
343
  }
344
+ /**
345
+ * Connect to the WebSocket server.
346
+ * This is automatically called when you use subscribe methods if not already connected.
347
+ * You can also call this method manually for explicit control.
348
+ */
317
349
  connect() {
318
- this.realtimeClient.connect();
350
+ this.initPromise = this.initClient().then(() => {
351
+ this.realtimeClient.connect();
352
+ });
353
+ }
354
+ /**
355
+ * Disconnect from the WebSocket server.
356
+ * All subscriptions will be automatically removed.
357
+ */
358
+ disconnect() {
359
+ if (this.realtimeClient) {
360
+ this.realtimeClient.disconnect();
361
+ }
362
+ }
363
+ /**
364
+ * Check if the WebSocket is currently connected.
365
+ */
366
+ isConnected() {
367
+ return this.realtimeClient?.state === "connected";
319
368
  }
320
369
  /**
321
370
  * Start batching commands for efficient bulk operations
322
371
  * All subscription commands after this call will be batched until stopBatching is called
323
372
  */
324
373
  startBatching() {
325
- this.realtimeClient.startBatching();
374
+ if (this.realtimeClient) {
375
+ this.realtimeClient.startBatching();
376
+ }
326
377
  }
327
378
  /**
328
379
  * Stop batching and flush all collected commands to the server
329
380
  * This will send all batched subscription commands in a single network request
330
381
  */
331
382
  stopBatching() {
332
- this.realtimeClient.stopBatching();
383
+ if (this.realtimeClient) {
384
+ this.realtimeClient.stopBatching();
385
+ }
333
386
  }
334
387
  /**
335
388
  * Batch subscribe method that accepts a function containing subscription calls
@@ -359,26 +412,31 @@ var StreamApi = class {
359
412
  });
360
413
  }
361
414
  subscribe(channel, fn, filter, methodName) {
362
- let sub = this.realtimeClient.getSubscription(channel);
363
415
  let listeners = this.listenersMap.get(channel);
364
- if (!sub) {
416
+ if (!listeners) {
365
417
  listeners = /* @__PURE__ */ new Set();
366
418
  this.listenersMap.set(channel, listeners);
367
- console.log("[xrealtime] create new sub: ", channel);
368
- const processedFilter = filter && methodName ? replaceFilterFields(filter, methodName) : filter;
369
- sub = this.realtimeClient.newSubscription(channel, {
370
- delta: "fossil",
371
- ...processedFilter && { filter: processedFilter }
372
- });
373
- sub.on("subscribed", () => {
374
- console.log("[xrealtime] subscribed", channel);
375
- }).on("unsubscribed", () => {
376
- console.log("[xrealtime] unsubscribed", channel);
377
- }).on("publication", (ctx) => {
378
- listeners?.forEach((it) => it(ctx.data));
379
- }).subscribe();
380
- }
381
- listeners?.add(fn);
419
+ }
420
+ listeners.add(fn);
421
+ this.ensureInitialized().then(() => {
422
+ let sub = this.realtimeClient.getSubscription(channel);
423
+ if (!sub) {
424
+ console.log("[xrealtime] create new sub: ", channel);
425
+ const processedFilter = filter && methodName ? replaceFilterFields(filter, methodName) : filter;
426
+ sub = this.realtimeClient.newSubscription(channel, {
427
+ delta: "fossil",
428
+ ...processedFilter && { filter: processedFilter }
429
+ });
430
+ sub.on("subscribed", () => {
431
+ console.log("[xrealtime] subscribed", channel);
432
+ }).on("unsubscribed", () => {
433
+ console.log("[xrealtime] unsubscribed", channel);
434
+ }).on("publication", (ctx) => {
435
+ const currentListeners = this.listenersMap.get(channel);
436
+ currentListeners?.forEach((it) => it(ctx.data));
437
+ }).subscribe();
438
+ }
439
+ });
382
440
  return new StreamUnsubscrible(this, channel, fn);
383
441
  }
384
442
  unsubscribe(channel, fn) {
@@ -390,12 +448,14 @@ var StreamApi = class {
390
448
  console.log("unsubscribe, remain listeners: ", listeners.size);
391
449
  if (listeners.size === 0) {
392
450
  console.log("unsubscribe channel: ", channel);
393
- const sub = this.realtimeClient.getSubscription(channel);
394
- if (sub) {
395
- sub.unsubscribe();
396
- this.realtimeClient.removeSubscription(sub);
397
- }
398
451
  this.listenersMap.delete(channel);
452
+ this.ensureInitialized().then(() => {
453
+ const sub = this.realtimeClient.getSubscription(channel);
454
+ if (sub) {
455
+ sub.unsubscribe();
456
+ this.realtimeClient.removeSubscription(sub);
457
+ }
458
+ });
399
459
  }
400
460
  }
401
461
  formatScientificNotation(value) {
@@ -8172,7 +8232,7 @@ var WatchlistApi = class extends BaseAPI {
8172
8232
 
8173
8233
  // src/index.ts
8174
8234
  var import_event_source_polyfill = require("event-source-polyfill");
8175
- var LIB_VERSION = "0.1.20";
8235
+ var LIB_VERSION = "0.1.22";
8176
8236
  var UserAgentMiddleware = class {
8177
8237
  async pre(context) {
8178
8238
  if (!context.init.headers) {
@@ -8210,9 +8270,6 @@ var DexClient = class {
8210
8270
  __publicField(this, "endpoint");
8211
8271
  const baseUrl = options.serverUrl ?? "https://api-dex.chainstream.io";
8212
8272
  const streamUrl = options.streamUrl ?? "wss://realtime-dex.chainstream.io/connection/websocket";
8213
- const tokenProvider = typeof accessToken === "string" ? {
8214
- getToken: () => accessToken
8215
- } : accessToken;
8216
8273
  this.requestCtx = { baseUrl, streamUrl, accessToken };
8217
8274
  const config = new Configuration({
8218
8275
  basePath: baseUrl,
@@ -8242,7 +8299,9 @@ var DexClient = class {
8242
8299
  this.jobs = new JobsApi(config);
8243
8300
  this.kyt = new KYTApi(config);
8244
8301
  this.endpoint = new EndpointApi(config);
8245
- this.stream.connect();
8302
+ if (options.autoConnectWebSocket === true) {
8303
+ this.stream.connect();
8304
+ }
8246
8305
  }
8247
8306
  async waitForJob(jobId, timeout = 6e4) {
8248
8307
  const accessToken = typeof this.requestCtx.accessToken === "string" ? this.requestCtx.accessToken : await this.requestCtx.accessToken.getToken();