@adaptic/utils 0.0.379 → 0.0.381

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/dist/index.cjs CHANGED
@@ -11478,22 +11478,28 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11478
11478
  v1beta1url;
11479
11479
  stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip'; // production values
11480
11480
  optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values
11481
+ cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // production values
11481
11482
  stockWs = null;
11482
11483
  optionWs = null;
11484
+ cryptoWs = null;
11483
11485
  stockSubscriptions = { trades: [], quotes: [], bars: [] };
11484
11486
  optionSubscriptions = { trades: [], quotes: [], bars: [] };
11487
+ cryptoSubscriptions = { trades: [], quotes: [], bars: [] };
11485
11488
  setMode(mode = 'production') {
11486
11489
  if (mode === 'sandbox') { // sandbox mode
11487
11490
  this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';
11488
11491
  this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';
11492
+ this.cryptoStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/crypto/us';
11489
11493
  }
11490
11494
  else if (mode === 'test') { // test mode, can only use ticker FAKEPACA
11491
11495
  this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';
11492
11496
  this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options
11497
+ this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // there's no test mode for crypto
11493
11498
  }
11494
11499
  else { // production
11495
11500
  this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';
11496
11501
  this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';
11502
+ this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us';
11497
11503
  }
11498
11504
  }
11499
11505
  getMode() {
@@ -11535,14 +11541,26 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11535
11541
  return super.emit(event, ...args);
11536
11542
  }
11537
11543
  connect(streamType) {
11538
- const url = streamType === 'stock' ? this.stockStreamUrl : this.optionStreamUrl;
11544
+ let url;
11545
+ if (streamType === 'stock') {
11546
+ url = this.stockStreamUrl;
11547
+ }
11548
+ else if (streamType === 'option') {
11549
+ url = this.optionStreamUrl;
11550
+ }
11551
+ else {
11552
+ url = this.cryptoStreamUrl;
11553
+ }
11539
11554
  const ws = new WebSocket(url);
11540
11555
  if (streamType === 'stock') {
11541
11556
  this.stockWs = ws;
11542
11557
  }
11543
- else {
11558
+ else if (streamType === 'option') {
11544
11559
  this.optionWs = ws;
11545
11560
  }
11561
+ else {
11562
+ this.cryptoWs = ws;
11563
+ }
11546
11564
  ws.on('open', () => {
11547
11565
  log(`${streamType} stream connected`, { type: 'info' });
11548
11566
  const authMessage = {
@@ -11553,20 +11571,36 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11553
11571
  ws.send(JSON.stringify(authMessage));
11554
11572
  });
11555
11573
  ws.on('message', (data) => {
11556
- //log(`RAW MESSASGE: ${data.toString()}`);
11557
- const messages = JSON.parse(data.toString());
11574
+ const rawData = data.toString();
11575
+ let messages;
11576
+ try {
11577
+ messages = JSON.parse(rawData);
11578
+ }
11579
+ catch (e) {
11580
+ log(`${streamType} stream received invalid JSON: ${rawData.substring(0, 200)}`, { type: 'error' });
11581
+ return;
11582
+ }
11558
11583
  for (const message of messages) {
11559
11584
  if (message.T === 'success' && message.msg === 'authenticated') {
11560
11585
  log(`${streamType} stream authenticated`, { type: 'info' });
11561
11586
  this.sendSubscription(streamType);
11562
11587
  }
11588
+ else if (message.T === 'success' && message.msg === 'connected') {
11589
+ log(`${streamType} stream connected message received`, { type: 'debug' });
11590
+ }
11591
+ else if (message.T === 'subscription') {
11592
+ log(`${streamType} subscription confirmed: trades=${message.trades?.length || 0}, quotes=${message.quotes?.length || 0}, bars=${message.bars?.length || 0}`, { type: 'info' });
11593
+ }
11563
11594
  else if (message.T === 'error') {
11564
- log(`${streamType} stream error: ${message.msg}`, { type: 'error' });
11595
+ log(`${streamType} stream error: ${message.msg} (code: ${message.code}, raw: ${JSON.stringify(message)})`, { type: 'error' });
11565
11596
  }
11566
11597
  else if (message.S) {
11567
11598
  super.emit(`${streamType}-${message.T}`, message);
11568
11599
  super.emit(`${streamType}-data`, message);
11569
11600
  }
11601
+ else {
11602
+ log(`${streamType} received unknown message type: ${JSON.stringify(message)}`, { type: 'debug' });
11603
+ }
11570
11604
  }
11571
11605
  });
11572
11606
  ws.on('close', () => {
@@ -11574,9 +11608,12 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11574
11608
  if (streamType === 'stock') {
11575
11609
  this.stockWs = null;
11576
11610
  }
11577
- else {
11611
+ else if (streamType === 'option') {
11578
11612
  this.optionWs = null;
11579
11613
  }
11614
+ else {
11615
+ this.cryptoWs = null;
11616
+ }
11580
11617
  // Optional: implement reconnect logic
11581
11618
  });
11582
11619
  ws.on('error', (error) => {
@@ -11584,8 +11621,23 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11584
11621
  });
11585
11622
  }
11586
11623
  sendSubscription(streamType) {
11587
- const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
11588
- const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
11624
+ let ws;
11625
+ let subscriptions;
11626
+ if (streamType === 'stock') {
11627
+ ws = this.stockWs;
11628
+ subscriptions = this.stockSubscriptions;
11629
+ }
11630
+ else if (streamType === 'option') {
11631
+ ws = this.optionWs;
11632
+ subscriptions = this.optionSubscriptions;
11633
+ }
11634
+ else {
11635
+ ws = this.cryptoWs;
11636
+ subscriptions = this.cryptoSubscriptions;
11637
+ }
11638
+ log(`sendSubscription called for ${streamType} (wsReady=${ws?.readyState === WebSocket.OPEN}, trades=${subscriptions.trades?.length || 0}, quotes=${subscriptions.quotes?.length || 0}, bars=${subscriptions.bars?.length || 0})`, {
11639
+ type: 'debug',
11640
+ });
11589
11641
  if (ws && ws.readyState === WebSocket.OPEN) {
11590
11642
  const subMessagePayload = {};
11591
11643
  if (subscriptions.trades.length > 0) {
@@ -11602,8 +11654,16 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11602
11654
  action: 'subscribe',
11603
11655
  ...subMessagePayload,
11604
11656
  };
11605
- ws.send(JSON.stringify(subMessage));
11657
+ const messageJson = JSON.stringify(subMessage);
11658
+ log(`Sending ${streamType} subscription: ${messageJson}`, { type: 'info' });
11659
+ ws.send(messageJson);
11606
11660
  }
11661
+ else {
11662
+ log(`No ${streamType} subscriptions to send (all arrays empty)`, { type: 'debug' });
11663
+ }
11664
+ }
11665
+ else {
11666
+ log(`Cannot send ${streamType} subscription: WebSocket not ready`, { type: 'warn' });
11607
11667
  }
11608
11668
  }
11609
11669
  connectStockStream() {
@@ -11616,6 +11676,11 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11616
11676
  this.connect('option');
11617
11677
  }
11618
11678
  }
11679
+ connectCryptoStream() {
11680
+ if (!this.cryptoWs) {
11681
+ this.connect('crypto');
11682
+ }
11683
+ }
11619
11684
  disconnectStockStream() {
11620
11685
  if (this.stockWs) {
11621
11686
  this.stockWs.close();
@@ -11626,8 +11691,38 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11626
11691
  this.optionWs.close();
11627
11692
  }
11628
11693
  }
11694
+ disconnectCryptoStream() {
11695
+ if (this.cryptoWs) {
11696
+ this.cryptoWs.close();
11697
+ }
11698
+ }
11699
+ /**
11700
+ * Check if a specific stream is connected
11701
+ * @param streamType - The type of stream to check
11702
+ * @returns True if the stream is connected
11703
+ */
11704
+ isStreamConnected(streamType) {
11705
+ if (streamType === 'stock') {
11706
+ return this.stockWs !== null && this.stockWs.readyState === WebSocket.OPEN;
11707
+ }
11708
+ else if (streamType === 'option') {
11709
+ return this.optionWs !== null && this.optionWs.readyState === WebSocket.OPEN;
11710
+ }
11711
+ else {
11712
+ return this.cryptoWs !== null && this.cryptoWs.readyState === WebSocket.OPEN;
11713
+ }
11714
+ }
11629
11715
  subscribe(streamType, subscriptions) {
11630
- const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
11716
+ let currentSubscriptions;
11717
+ if (streamType === 'stock') {
11718
+ currentSubscriptions = this.stockSubscriptions;
11719
+ }
11720
+ else if (streamType === 'option') {
11721
+ currentSubscriptions = this.optionSubscriptions;
11722
+ }
11723
+ else {
11724
+ currentSubscriptions = this.cryptoSubscriptions;
11725
+ }
11631
11726
  Object.entries(subscriptions).forEach(([key, value]) => {
11632
11727
  if (value) {
11633
11728
  currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];
@@ -11636,7 +11731,16 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11636
11731
  this.sendSubscription(streamType);
11637
11732
  }
11638
11733
  unsubscribe(streamType, subscriptions) {
11639
- const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
11734
+ let currentSubscriptions;
11735
+ if (streamType === 'stock') {
11736
+ currentSubscriptions = this.stockSubscriptions;
11737
+ }
11738
+ else if (streamType === 'option') {
11739
+ currentSubscriptions = this.optionSubscriptions;
11740
+ }
11741
+ else {
11742
+ currentSubscriptions = this.cryptoSubscriptions;
11743
+ }
11640
11744
  Object.entries(subscriptions).forEach(([key, value]) => {
11641
11745
  if (value) {
11642
11746
  currentSubscriptions[key] = (currentSubscriptions[key] || []).filter(s => !value.includes(s));
@@ -11646,7 +11750,16 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
11646
11750
  action: 'unsubscribe',
11647
11751
  ...subscriptions,
11648
11752
  };
11649
- const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
11753
+ let ws;
11754
+ if (streamType === 'stock') {
11755
+ ws = this.stockWs;
11756
+ }
11757
+ else if (streamType === 'option') {
11758
+ ws = this.optionWs;
11759
+ }
11760
+ else {
11761
+ ws = this.cryptoWs;
11762
+ }
11650
11763
  if (ws && ws.readyState === WebSocket.OPEN) {
11651
11764
  ws.send(JSON.stringify(unsubMessage));
11652
11765
  }