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