@discomedia/utils 1.0.53 → 1.0.55

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.mjs CHANGED
@@ -2517,7 +2517,7 @@ const safeJSON = (text) => {
2517
2517
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2518
2518
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2519
2519
 
2520
- const VERSION = '6.15.0'; // x-release-please-version
2520
+ const VERSION = '6.16.0'; // x-release-please-version
2521
2521
 
2522
2522
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2523
2523
  const isRunningInBrowser = () => {
@@ -16901,6 +16901,11 @@ class AlpacaMarketDataAPI extends EventEmitter {
16901
16901
  optionWs = null;
16902
16902
  stockSubscriptions = { trades: [], quotes: [], bars: [] };
16903
16903
  optionSubscriptions = { trades: [], quotes: [], bars: [] };
16904
+ autoReconnect = true;
16905
+ stockReconnectAttempts = 0;
16906
+ optionReconnectAttempts = 0;
16907
+ stockReconnectTimeout = null;
16908
+ optionReconnectTimeout = null;
16904
16909
  setMode(mode = 'production') {
16905
16910
  if (mode === 'sandbox') {
16906
16911
  // sandbox mode
@@ -16929,6 +16934,13 @@ class AlpacaMarketDataAPI extends EventEmitter {
16929
16934
  return 'production';
16930
16935
  }
16931
16936
  }
16937
+ setAutoReconnect(enabled) {
16938
+ this.autoReconnect = enabled;
16939
+ log(`Auto-reconnect ${enabled ? 'enabled' : 'disabled'}`);
16940
+ }
16941
+ getAutoReconnect() {
16942
+ return this.autoReconnect;
16943
+ }
16932
16944
  constructor() {
16933
16945
  super();
16934
16946
  this.dataURL = 'https://data.alpaca.markets/v2';
@@ -16951,6 +16963,36 @@ class AlpacaMarketDataAPI extends EventEmitter {
16951
16963
  }
16952
16964
  return AlpacaMarketDataAPI.instance;
16953
16965
  }
16966
+ getReconnectDelay(attempt) {
16967
+ // 0: instant (0ms), 1: 5s, 2: 10s, 3: 15s, 4+: 60s
16968
+ const delays = [0, 5000, 10000, 15000, 60000];
16969
+ return attempt < delays.length ? delays[attempt] : 60000;
16970
+ }
16971
+ scheduleReconnect(streamType) {
16972
+ if (!this.autoReconnect) {
16973
+ log(`Auto-reconnect disabled, not reconnecting ${streamType} stream`);
16974
+ return;
16975
+ }
16976
+ const attempts = streamType === 'stock' ? this.stockReconnectAttempts : this.optionReconnectAttempts;
16977
+ const delay = this.getReconnectDelay(attempts);
16978
+ log(`Scheduling ${streamType} stream reconnect (attempt ${attempts + 1}) in ${delay}ms`);
16979
+ const timeout = setTimeout(() => {
16980
+ log(`Attempting to reconnect ${streamType} stream (attempt ${attempts + 1})`);
16981
+ if (streamType === 'stock') {
16982
+ this.stockReconnectAttempts++;
16983
+ }
16984
+ else {
16985
+ this.optionReconnectAttempts++;
16986
+ }
16987
+ this.connect(streamType);
16988
+ }, delay);
16989
+ if (streamType === 'stock') {
16990
+ this.stockReconnectTimeout = timeout;
16991
+ }
16992
+ else {
16993
+ this.optionReconnectTimeout = timeout;
16994
+ }
16995
+ }
16954
16996
  on(event, listener) {
16955
16997
  return super.on(event, listener);
16956
16998
  }
@@ -16968,6 +17010,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
16968
17010
  }
16969
17011
  ws.on('open', () => {
16970
17012
  log(`${streamType} stream connected`);
17013
+ // Reset reconnect attempts on successful connection
17014
+ if (streamType === 'stock') {
17015
+ this.stockReconnectAttempts = 0;
17016
+ if (this.stockReconnectTimeout) {
17017
+ clearTimeout(this.stockReconnectTimeout);
17018
+ this.stockReconnectTimeout = null;
17019
+ }
17020
+ }
17021
+ else {
17022
+ this.optionReconnectAttempts = 0;
17023
+ if (this.optionReconnectTimeout) {
17024
+ clearTimeout(this.optionReconnectTimeout);
17025
+ this.optionReconnectTimeout = null;
17026
+ }
17027
+ }
16971
17028
  const authMessage = {
16972
17029
  action: 'auth',
16973
17030
  key: process.env.ALPACA_API_KEY,
@@ -16992,20 +17049,42 @@ class AlpacaMarketDataAPI extends EventEmitter {
16992
17049
  }
16993
17050
  }
16994
17051
  });
16995
- ws.on('close', () => {
16996
- log(`${streamType} stream disconnected`, { type: 'warn' });
17052
+ ws.on('close', (code, reason) => {
17053
+ const reasonStr = reason.toString() || 'No reason provided';
17054
+ const codeDesc = this.getCloseCodeDescription(code);
17055
+ log(`${streamType} stream disconnected - Code: ${code} (${codeDesc}), Reason: ${reasonStr}`, { type: 'warn' });
16997
17056
  if (streamType === 'stock') {
16998
17057
  this.stockWs = null;
16999
17058
  }
17000
17059
  else {
17001
17060
  this.optionWs = null;
17002
17061
  }
17003
- // Optional: implement reconnect logic
17062
+ this.scheduleReconnect(streamType);
17004
17063
  });
17005
17064
  ws.on('error', (error) => {
17006
17065
  log(`${streamType} stream error: ${error.message}`, { type: 'error' });
17007
17066
  });
17008
17067
  }
17068
+ getCloseCodeDescription(code) {
17069
+ const codes = {
17070
+ 1000: 'Normal Closure',
17071
+ 1001: 'Going Away',
17072
+ 1002: 'Protocol Error',
17073
+ 1003: 'Unsupported Data',
17074
+ 1005: 'No Status Received',
17075
+ 1006: 'Abnormal Closure',
17076
+ 1007: 'Invalid Frame Payload Data',
17077
+ 1008: 'Policy Violation',
17078
+ 1009: 'Message Too Big',
17079
+ 1010: 'Mandatory Extension',
17080
+ 1011: 'Internal Server Error',
17081
+ 1012: 'Service Restart',
17082
+ 1013: 'Try Again Later',
17083
+ 1014: 'Bad Gateway',
17084
+ 1015: 'TLS Handshake',
17085
+ };
17086
+ return codes[code] || 'Unknown';
17087
+ }
17009
17088
  sendSubscription(streamType) {
17010
17089
  const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
17011
17090
  const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
@@ -17040,11 +17119,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
17040
17119
  }
17041
17120
  }
17042
17121
  disconnectStockStream() {
17122
+ if (this.stockReconnectTimeout) {
17123
+ clearTimeout(this.stockReconnectTimeout);
17124
+ this.stockReconnectTimeout = null;
17125
+ }
17126
+ this.stockReconnectAttempts = 0;
17043
17127
  if (this.stockWs) {
17044
17128
  this.stockWs.close();
17045
17129
  }
17046
17130
  }
17047
17131
  disconnectOptionStream() {
17132
+ if (this.optionReconnectTimeout) {
17133
+ clearTimeout(this.optionReconnectTimeout);
17134
+ this.optionReconnectTimeout = null;
17135
+ }
17136
+ this.optionReconnectAttempts = 0;
17048
17137
  if (this.optionWs) {
17049
17138
  this.optionWs.close();
17050
17139
  }
@@ -18139,7 +18228,7 @@ class AlpacaTradingAPI {
18139
18228
  }
18140
18229
  handleTradeUpdate(data) {
18141
18230
  if (this.tradeUpdateCallback) {
18142
- this.log(`Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares, type ${data.order.type}`, {
18231
+ this.log(`Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares${data.event === 'partial_fill' ? ` (filled shares: ${data.order.filled_qty})` : ''}, type ${data.order.type}`, {
18143
18232
  symbol: data.order.symbol,
18144
18233
  type: 'debug',
18145
18234
  });
@@ -18257,7 +18346,9 @@ class AlpacaTradingAPI {
18257
18346
  try {
18258
18347
  this.ws.terminate();
18259
18348
  }
18260
- catch { /* no-op */ }
18349
+ catch {
18350
+ /* no-op */
18351
+ }
18261
18352
  }
18262
18353
  this.ws = null;
18263
18354
  }
@@ -18897,7 +18988,7 @@ class AlpacaTradingAPI {
18897
18988
  const hourlyParams = { timeframe: '1Min', period: '1D' };
18898
18989
  const [dailyHistory, hourlyHistory] = await Promise.all([
18899
18990
  this.getPortfolioHistory(dailyParams),
18900
- this.getPortfolioHistory(hourlyParams)
18991
+ this.getPortfolioHistory(hourlyParams),
18901
18992
  ]);
18902
18993
  // If no hourly history, return daily as-is
18903
18994
  if (!hourlyHistory.timestamp || hourlyHistory.timestamp.length === 0) {