@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 +38 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +38 -6
- 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/package.json +1 -1
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:
|
|
12457
|
-
secret:
|
|
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
|
-
//
|
|
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;
|