@chainstream-io/sdk 0.1.20 → 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.20
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,9 +320,42 @@ interface Unsubscrible {
320
320
  declare class StreamApi {
321
321
  private realtimeClient;
322
322
  private listenersMap;
323
- private getTokenValue;
323
+ private context;
324
+ private initPromise;
324
325
  constructor(context: DexRequestContext);
325
- connect(): Promise<void>;
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;
340
+ /**
341
+ * Build WebSocket URL with token as query parameter
342
+ */
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
+ */
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;
326
359
  /**
327
360
  * Start batching commands for efficient bulk operations
328
361
  * All subscription commands after this call will be batched until stopBatching is called
@@ -467,8 +500,16 @@ interface DexAggregatorOptions {
467
500
  debug?: boolean;
468
501
  serverUrl?: string;
469
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;
470
511
  }
471
- declare const LIB_VERSION = "0.1.20";
512
+ declare const LIB_VERSION = "0.1.22";
472
513
  declare class DexClient {
473
514
  readonly requestCtx: DexRequestContext;
474
515
  readonly _configuration: Configuration;
@@ -320,9 +320,42 @@ interface Unsubscrible {
320
320
  declare class StreamApi {
321
321
  private realtimeClient;
322
322
  private listenersMap;
323
- private getTokenValue;
323
+ private context;
324
+ private initPromise;
324
325
  constructor(context: DexRequestContext);
325
- connect(): Promise<void>;
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;
340
+ /**
341
+ * Build WebSocket URL with token as query parameter
342
+ */
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
+ */
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;
326
359
  /**
327
360
  * Start batching commands for efficient bulk operations
328
361
  * All subscription commands after this call will be batched until stopBatching is called
@@ -467,8 +500,16 @@ interface DexAggregatorOptions {
467
500
  debug?: boolean;
468
501
  serverUrl?: string;
469
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;
470
511
  }
471
- declare const LIB_VERSION = "0.1.20";
512
+ declare const LIB_VERSION = "0.1.22";
472
513
  declare class DexClient {
473
514
  readonly requestCtx: DexRequestContext;
474
515
  readonly _configuration: Configuration;
package/dist/index.cjs CHANGED
@@ -29,7 +29,6 @@ module.exports = __toCommonJS(index_exports);
29
29
 
30
30
  // src/stream/stream.ts
31
31
  var import_centrifuge = require("@chainstream-io/centrifuge");
32
- var import_module = require("module");
33
32
 
34
33
  // src/stream/stream.fields.ts
35
34
  var CEL_FIELD_MAPPINGS = {
@@ -286,67 +285,104 @@ function replaceFilterFields(filter, methodName) {
286
285
  }
287
286
 
288
287
  // src/stream/stream.ts
289
- var import_meta = {};
290
288
  var StreamApi = class {
291
289
  constructor(context) {
292
290
  __publicField(this, "realtimeClient");
293
291
  __publicField(this, "listenersMap");
294
- __publicField(this, "getTokenValue");
295
- const realtimeEndpoint = context.streamUrl;
296
- this.getTokenValue = async () => {
297
- return typeof context.accessToken === "string" ? context.accessToken : await context.accessToken.getToken();
298
- };
299
- let wsImpl = void 0;
300
- if (typeof process !== "undefined" && process.versions?.node) {
301
- try {
302
- const require2 = (0, import_module.createRequire)(import_meta.url);
303
- wsImpl = require2("ws");
304
- } catch {
305
- }
306
- }
307
- if (!wsImpl && typeof WebSocket !== "undefined") {
308
- wsImpl = WebSocket;
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;
309
304
  }
305
+ const token = await this.getTokenValue();
306
+ const realtimeEndpoint = this.buildWsUrl(this.context.streamUrl, token);
310
307
  this.realtimeClient = new import_centrifuge.Centrifuge(realtimeEndpoint, {
311
- ...wsImpl && { websocket: wsImpl },
312
308
  getToken: async (_ctx) => {
313
- const token = await this.getTokenValue();
314
- this.realtimeClient.setHttpHeaders({
315
- Authorization: `Bearer ${token}`,
316
- "User-Agent": `chainstream-io/sdk/javascript`
317
- });
318
- return token;
309
+ return this.getTokenValue();
319
310
  }
320
311
  });
321
312
  this.realtimeClient.on("connected", () => {
322
313
  console.log("[streaming] connected");
323
- }).on("disconnected", (err) => {
324
- console.warn("[streaming] disconnected", err);
314
+ }).on("disconnected", (ctx) => {
315
+ console.warn("[streaming] disconnected", ctx);
325
316
  }).on("error", (err) => {
326
317
  console.error("[streaming] error: ", err);
327
318
  });
328
- this.listenersMap = /* @__PURE__ */ new Map();
329
319
  }
330
- async connect() {
331
- const token = await this.getTokenValue();
332
- this.realtimeClient.setHttpHeaders({
333
- Authorization: `Bearer ${token}`
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();
335
+ }
336
+ /**
337
+ * Build WebSocket URL with token as query parameter
338
+ */
339
+ buildWsUrl(endpoint, token) {
340
+ const url = new URL(endpoint);
341
+ url.searchParams.set("token", token);
342
+ return url.toString();
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
+ */
349
+ connect() {
350
+ this.initPromise = this.initClient().then(() => {
351
+ this.realtimeClient.connect();
334
352
  });
335
- this.realtimeClient.connect();
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";
336
368
  }
337
369
  /**
338
370
  * Start batching commands for efficient bulk operations
339
371
  * All subscription commands after this call will be batched until stopBatching is called
340
372
  */
341
373
  startBatching() {
342
- this.realtimeClient.startBatching();
374
+ if (this.realtimeClient) {
375
+ this.realtimeClient.startBatching();
376
+ }
343
377
  }
344
378
  /**
345
379
  * Stop batching and flush all collected commands to the server
346
380
  * This will send all batched subscription commands in a single network request
347
381
  */
348
382
  stopBatching() {
349
- this.realtimeClient.stopBatching();
383
+ if (this.realtimeClient) {
384
+ this.realtimeClient.stopBatching();
385
+ }
350
386
  }
351
387
  /**
352
388
  * Batch subscribe method that accepts a function containing subscription calls
@@ -376,26 +412,31 @@ var StreamApi = class {
376
412
  });
377
413
  }
378
414
  subscribe(channel, fn, filter, methodName) {
379
- let sub = this.realtimeClient.getSubscription(channel);
380
415
  let listeners = this.listenersMap.get(channel);
381
- if (!sub) {
416
+ if (!listeners) {
382
417
  listeners = /* @__PURE__ */ new Set();
383
418
  this.listenersMap.set(channel, listeners);
384
- console.log("[xrealtime] create new sub: ", channel);
385
- const processedFilter = filter && methodName ? replaceFilterFields(filter, methodName) : filter;
386
- sub = this.realtimeClient.newSubscription(channel, {
387
- delta: "fossil",
388
- ...processedFilter && { filter: processedFilter }
389
- });
390
- sub.on("subscribed", () => {
391
- console.log("[xrealtime] subscribed", channel);
392
- }).on("unsubscribed", () => {
393
- console.log("[xrealtime] unsubscribed", channel);
394
- }).on("publication", (ctx) => {
395
- listeners?.forEach((it) => it(ctx.data));
396
- }).subscribe();
397
- }
398
- 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
+ });
399
440
  return new StreamUnsubscrible(this, channel, fn);
400
441
  }
401
442
  unsubscribe(channel, fn) {
@@ -407,12 +448,14 @@ var StreamApi = class {
407
448
  console.log("unsubscribe, remain listeners: ", listeners.size);
408
449
  if (listeners.size === 0) {
409
450
  console.log("unsubscribe channel: ", channel);
410
- const sub = this.realtimeClient.getSubscription(channel);
411
- if (sub) {
412
- sub.unsubscribe();
413
- this.realtimeClient.removeSubscription(sub);
414
- }
415
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
+ });
416
459
  }
417
460
  }
418
461
  formatScientificNotation(value) {
@@ -8189,7 +8232,7 @@ var WatchlistApi = class extends BaseAPI {
8189
8232
 
8190
8233
  // src/index.ts
8191
8234
  var import_event_source_polyfill = require("event-source-polyfill");
8192
- var LIB_VERSION = "0.1.20";
8235
+ var LIB_VERSION = "0.1.22";
8193
8236
  var UserAgentMiddleware = class {
8194
8237
  async pre(context) {
8195
8238
  if (!context.init.headers) {
@@ -8227,9 +8270,6 @@ var DexClient = class {
8227
8270
  __publicField(this, "endpoint");
8228
8271
  const baseUrl = options.serverUrl ?? "https://api-dex.chainstream.io";
8229
8272
  const streamUrl = options.streamUrl ?? "wss://realtime-dex.chainstream.io/connection/websocket";
8230
- const tokenProvider = typeof accessToken === "string" ? {
8231
- getToken: () => accessToken
8232
- } : accessToken;
8233
8273
  this.requestCtx = { baseUrl, streamUrl, accessToken };
8234
8274
  const config = new Configuration({
8235
8275
  basePath: baseUrl,
@@ -8259,7 +8299,9 @@ var DexClient = class {
8259
8299
  this.jobs = new JobsApi(config);
8260
8300
  this.kyt = new KYTApi(config);
8261
8301
  this.endpoint = new EndpointApi(config);
8262
- this.stream.connect();
8302
+ if (options.autoConnectWebSocket === true) {
8303
+ this.stream.connect();
8304
+ }
8263
8305
  }
8264
8306
  async waitForJob(jobId, timeout = 6e4) {
8265
8307
  const accessToken = typeof this.requestCtx.accessToken === "string" ? this.requestCtx.accessToken : await this.requestCtx.accessToken.getToken();