@adaptic/utils 0.0.905 → 0.0.907
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 +47 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +47 -15
- package/dist/index.mjs.map +1 -1
- package/dist/test.js +38 -6
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca-market-data-api.d.ts +3 -0
- package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/rate-limiter.d.ts +1 -1
- package/package.json +1 -1
package/dist/test.js
CHANGED
|
@@ -6482,6 +6482,8 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6482
6482
|
quotes: [],
|
|
6483
6483
|
bars: [],
|
|
6484
6484
|
};
|
|
6485
|
+
reconnectAttempts = {};
|
|
6486
|
+
reconnectTimers = {};
|
|
6485
6487
|
setMode(mode = "production") {
|
|
6486
6488
|
if (mode === "sandbox") {
|
|
6487
6489
|
// sandbox mode
|
|
@@ -6520,7 +6522,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6520
6522
|
// when env vars are not available. Features will be unavailable until
|
|
6521
6523
|
// credentials are provided at runtime.
|
|
6522
6524
|
const apiKey = process.env.ALPACA_API_KEY || "";
|
|
6523
|
-
const apiSecret = process.env.ALPACA_SECRET_KEY || "";
|
|
6525
|
+
const apiSecret = process.env.ALPACA_API_SECRET || process.env.ALPACA_SECRET_KEY || "";
|
|
6524
6526
|
this.credentialsValid = validateAlpacaCredentials({
|
|
6525
6527
|
apiKey,
|
|
6526
6528
|
apiSecret,
|
|
@@ -6562,6 +6564,12 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6562
6564
|
else {
|
|
6563
6565
|
url = this.cryptoStreamUrl;
|
|
6564
6566
|
}
|
|
6567
|
+
const apiKey = process.env.ALPACA_API_KEY || "";
|
|
6568
|
+
const apiSecret = process.env.ALPACA_API_SECRET || process.env.ALPACA_SECRET_KEY || "";
|
|
6569
|
+
if (!apiKey || !apiSecret) {
|
|
6570
|
+
log$1(`Cannot connect ${streamType} stream: missing Alpaca credentials (ALPACA_API_KEY=${apiKey ? "set" : "MISSING"}, ALPACA_API_SECRET/ALPACA_SECRET_KEY=${apiSecret ? "set" : "MISSING"})`, { type: "error" });
|
|
6571
|
+
return;
|
|
6572
|
+
}
|
|
6565
6573
|
const ws = new WebSocket(url);
|
|
6566
6574
|
if (streamType === "stock") {
|
|
6567
6575
|
this.stockWs = ws;
|
|
@@ -6576,8 +6584,8 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6576
6584
|
log$1(`${streamType} stream connected`, { type: "info" });
|
|
6577
6585
|
const authMessage = {
|
|
6578
6586
|
action: "auth",
|
|
6579
|
-
key:
|
|
6580
|
-
secret:
|
|
6587
|
+
key: apiKey,
|
|
6588
|
+
secret: apiSecret,
|
|
6581
6589
|
};
|
|
6582
6590
|
ws.send(JSON.stringify(authMessage));
|
|
6583
6591
|
});
|
|
@@ -6594,6 +6602,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6594
6602
|
for (const message of messages) {
|
|
6595
6603
|
if (message.T === "success" && message.msg === "authenticated") {
|
|
6596
6604
|
log$1(`${streamType} stream authenticated`, { type: "info" });
|
|
6605
|
+
this.reconnectAttempts[streamType] = 0;
|
|
6597
6606
|
this.sendSubscription(streamType);
|
|
6598
6607
|
}
|
|
6599
6608
|
else if (message.T === "success" && message.msg === "connected") {
|
|
@@ -6616,8 +6625,8 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6616
6625
|
}
|
|
6617
6626
|
}
|
|
6618
6627
|
});
|
|
6619
|
-
ws.on("close", () => {
|
|
6620
|
-
log$1(`${streamType} stream disconnected`, { type: "warn" });
|
|
6628
|
+
ws.on("close", (code) => {
|
|
6629
|
+
log$1(`${streamType} stream disconnected (code: ${code})`, { type: "warn" });
|
|
6621
6630
|
if (streamType === "stock") {
|
|
6622
6631
|
this.stockWs = null;
|
|
6623
6632
|
}
|
|
@@ -6627,12 +6636,35 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
6627
6636
|
else {
|
|
6628
6637
|
this.cryptoWs = null;
|
|
6629
6638
|
}
|
|
6630
|
-
//
|
|
6639
|
+
// Reconnect with exponential backoff (unless intentionally closed with code 1000)
|
|
6640
|
+
if (code !== 1000) {
|
|
6641
|
+
this.scheduleReconnect(streamType);
|
|
6642
|
+
}
|
|
6631
6643
|
});
|
|
6632
6644
|
ws.on("error", (error) => {
|
|
6633
6645
|
log$1(`${streamType} stream error: ${error.message}`, { type: "error" });
|
|
6634
6646
|
});
|
|
6635
6647
|
}
|
|
6648
|
+
scheduleReconnect(streamType) {
|
|
6649
|
+
const attempts = this.reconnectAttempts[streamType] ?? 0;
|
|
6650
|
+
const maxAttempts = 10;
|
|
6651
|
+
if (attempts >= maxAttempts) {
|
|
6652
|
+
log$1(`${streamType} stream: max reconnect attempts (${maxAttempts}) reached, giving up`, { type: "error" });
|
|
6653
|
+
return;
|
|
6654
|
+
}
|
|
6655
|
+
// Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s (capped)
|
|
6656
|
+
const delayMs = Math.min(1000 * Math.pow(2, attempts), 30000);
|
|
6657
|
+
this.reconnectAttempts[streamType] = attempts + 1;
|
|
6658
|
+
log$1(`${streamType} stream: scheduling reconnect attempt ${attempts + 1}/${maxAttempts} in ${delayMs}ms`, { type: "info" });
|
|
6659
|
+
// Clear any existing reconnect timer for this stream
|
|
6660
|
+
if (this.reconnectTimers[streamType]) {
|
|
6661
|
+
clearTimeout(this.reconnectTimers[streamType]);
|
|
6662
|
+
}
|
|
6663
|
+
this.reconnectTimers[streamType] = setTimeout(() => {
|
|
6664
|
+
log$1(`${streamType} stream: reconnecting (attempt ${attempts + 1}/${maxAttempts})`, { type: "info" });
|
|
6665
|
+
this.connect(streamType);
|
|
6666
|
+
}, delayMs);
|
|
6667
|
+
}
|
|
6636
6668
|
sendSubscription(streamType) {
|
|
6637
6669
|
let ws;
|
|
6638
6670
|
let subscriptions;
|