@adaptic/utils 0.0.905 → 0.0.906

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
@@ -12359,6 +12359,8 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12359
12359
  quotes: [],
12360
12360
  bars: [],
12361
12361
  };
12362
+ reconnectAttempts = {};
12363
+ reconnectTimers = {};
12362
12364
  setMode(mode = "production") {
12363
12365
  if (mode === "sandbox") {
12364
12366
  // sandbox mode
@@ -12397,7 +12399,7 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12397
12399
  // when env vars are not available. Features will be unavailable until
12398
12400
  // credentials are provided at runtime.
12399
12401
  const apiKey = process.env.ALPACA_API_KEY || "";
12400
- const apiSecret = process.env.ALPACA_SECRET_KEY || "";
12402
+ const apiSecret = process.env.ALPACA_API_SECRET || process.env.ALPACA_SECRET_KEY || "";
12401
12403
  this.credentialsValid = validateAlpacaCredentials({
12402
12404
  apiKey,
12403
12405
  apiSecret,
@@ -12439,6 +12441,12 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12439
12441
  else {
12440
12442
  url = this.cryptoStreamUrl;
12441
12443
  }
12444
+ const apiKey = process.env.ALPACA_API_KEY || "";
12445
+ const apiSecret = process.env.ALPACA_API_SECRET || process.env.ALPACA_SECRET_KEY || "";
12446
+ if (!apiKey || !apiSecret) {
12447
+ log$l(`Cannot connect ${streamType} stream: missing Alpaca credentials (ALPACA_API_KEY=${apiKey ? "set" : "MISSING"}, ALPACA_API_SECRET/ALPACA_SECRET_KEY=${apiSecret ? "set" : "MISSING"})`, { type: "error" });
12448
+ return;
12449
+ }
12442
12450
  const ws = new WebSocket(url);
12443
12451
  if (streamType === "stock") {
12444
12452
  this.stockWs = ws;
@@ -12453,8 +12461,8 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12453
12461
  log$l(`${streamType} stream connected`, { type: "info" });
12454
12462
  const authMessage = {
12455
12463
  action: "auth",
12456
- key: process.env.ALPACA_API_KEY,
12457
- secret: process.env.ALPACA_SECRET_KEY,
12464
+ key: apiKey,
12465
+ secret: apiSecret,
12458
12466
  };
12459
12467
  ws.send(JSON.stringify(authMessage));
12460
12468
  });
@@ -12471,6 +12479,7 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12471
12479
  for (const message of messages) {
12472
12480
  if (message.T === "success" && message.msg === "authenticated") {
12473
12481
  log$l(`${streamType} stream authenticated`, { type: "info" });
12482
+ this.reconnectAttempts[streamType] = 0;
12474
12483
  this.sendSubscription(streamType);
12475
12484
  }
12476
12485
  else if (message.T === "success" && message.msg === "connected") {
@@ -12493,8 +12502,8 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12493
12502
  }
12494
12503
  }
12495
12504
  });
12496
- ws.on("close", () => {
12497
- log$l(`${streamType} stream disconnected`, { type: "warn" });
12505
+ ws.on("close", (code) => {
12506
+ log$l(`${streamType} stream disconnected (code: ${code})`, { type: "warn" });
12498
12507
  if (streamType === "stock") {
12499
12508
  this.stockWs = null;
12500
12509
  }
@@ -12504,12 +12513,35 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
12504
12513
  else {
12505
12514
  this.cryptoWs = null;
12506
12515
  }
12507
- // Optional: implement reconnect logic
12516
+ // Reconnect with exponential backoff (unless intentionally closed with code 1000)
12517
+ if (code !== 1000) {
12518
+ this.scheduleReconnect(streamType);
12519
+ }
12508
12520
  });
12509
12521
  ws.on("error", (error) => {
12510
12522
  log$l(`${streamType} stream error: ${error.message}`, { type: "error" });
12511
12523
  });
12512
12524
  }
12525
+ scheduleReconnect(streamType) {
12526
+ const attempts = this.reconnectAttempts[streamType] ?? 0;
12527
+ const maxAttempts = 10;
12528
+ if (attempts >= maxAttempts) {
12529
+ log$l(`${streamType} stream: max reconnect attempts (${maxAttempts}) reached, giving up`, { type: "error" });
12530
+ return;
12531
+ }
12532
+ // Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s (capped)
12533
+ const delayMs = Math.min(1000 * Math.pow(2, attempts), 30000);
12534
+ this.reconnectAttempts[streamType] = attempts + 1;
12535
+ log$l(`${streamType} stream: scheduling reconnect attempt ${attempts + 1}/${maxAttempts} in ${delayMs}ms`, { type: "info" });
12536
+ // Clear any existing reconnect timer for this stream
12537
+ if (this.reconnectTimers[streamType]) {
12538
+ clearTimeout(this.reconnectTimers[streamType]);
12539
+ }
12540
+ this.reconnectTimers[streamType] = setTimeout(() => {
12541
+ log$l(`${streamType} stream: reconnecting (attempt ${attempts + 1}/${maxAttempts})`, { type: "info" });
12542
+ this.connect(streamType);
12543
+ }, delayMs);
12544
+ }
12513
12545
  sendSubscription(streamType) {
12514
12546
  let ws;
12515
12547
  let subscriptions;