@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/index.cjs
CHANGED
|
@@ -1317,7 +1317,7 @@ async function fetchWithRetry(url, options = {}, retries = 3, initialBackoff = 1
|
|
|
1317
1317
|
*/
|
|
1318
1318
|
async function validatePolygonApiKey(apiKey) {
|
|
1319
1319
|
try {
|
|
1320
|
-
const response = await fetch(`https://api.
|
|
1320
|
+
const response = await fetch(`https://api.massive.com/v1/meta/symbols?apikey=${apiKey}&limit=1`);
|
|
1321
1321
|
if (response.status === 401) {
|
|
1322
1322
|
throw new Error("Invalid or expired Polygon.io API key");
|
|
1323
1323
|
}
|
|
@@ -5189,7 +5189,7 @@ const fetchTickerInfo = async (symbol, options) => {
|
|
|
5189
5189
|
}
|
|
5190
5190
|
const apiKey = options?.apiKey || POLYGON_API_KEY;
|
|
5191
5191
|
validatePolygonApiKey$1(apiKey);
|
|
5192
|
-
const baseUrl = `https://api.
|
|
5192
|
+
const baseUrl = `https://api.massive.com/v3/reference/tickers/${encodeURIComponent(symbol)}`;
|
|
5193
5193
|
const params = new URLSearchParams({
|
|
5194
5194
|
apiKey,
|
|
5195
5195
|
});
|
|
@@ -5276,7 +5276,7 @@ const fetchLastTrade = async (symbol, options) => {
|
|
|
5276
5276
|
}
|
|
5277
5277
|
const apiKey = options?.apiKey || POLYGON_API_KEY;
|
|
5278
5278
|
validatePolygonApiKey$1(apiKey);
|
|
5279
|
-
const baseUrl = `https://api.
|
|
5279
|
+
const baseUrl = `https://api.massive.com/v2/last/trade/${encodeURIComponent(symbol)}`;
|
|
5280
5280
|
const params = new URLSearchParams({
|
|
5281
5281
|
apiKey,
|
|
5282
5282
|
});
|
|
@@ -5341,7 +5341,7 @@ const fetchPrices = async (params, options) => {
|
|
|
5341
5341
|
const apiKey = options?.apiKey || POLYGON_API_KEY;
|
|
5342
5342
|
validatePolygonApiKey$1(apiKey);
|
|
5343
5343
|
const { ticker, start, end = Date.now().valueOf(), multiplier, timespan, limit = 1000, } = params;
|
|
5344
|
-
const baseUrl = `https://api.
|
|
5344
|
+
const baseUrl = `https://api.massive.com/v2/aggs/ticker/${encodeURIComponent(ticker)}/range/${multiplier}/${timespan}/${start}/${end}`;
|
|
5345
5345
|
const urlParams = new URLSearchParams({
|
|
5346
5346
|
apiKey,
|
|
5347
5347
|
adjusted: "true",
|
|
@@ -5463,7 +5463,7 @@ const fetchGroupedDaily = async (date, options) => {
|
|
|
5463
5463
|
if (!options?.apiKey && !POLYGON_API_KEY) {
|
|
5464
5464
|
throw new Error("Polygon API key is missing");
|
|
5465
5465
|
}
|
|
5466
|
-
const baseUrl = `https://api.
|
|
5466
|
+
const baseUrl = `https://api.massive.com/v2/aggs/grouped/locale/us/market/stocks/${date}`;
|
|
5467
5467
|
const params = new URLSearchParams({
|
|
5468
5468
|
apiKey: options?.apiKey || POLYGON_API_KEY,
|
|
5469
5469
|
adjusted: options?.adjusted !== false ? "true" : "false",
|
|
@@ -5556,7 +5556,7 @@ symbol, date = new Date(), options) => {
|
|
|
5556
5556
|
throw new Error("Polygon API key is missing");
|
|
5557
5557
|
}
|
|
5558
5558
|
const formattedDate = date.toISOString().split("T")[0]; // Format as YYYY-MM-DD
|
|
5559
|
-
const baseUrl = `https://api.
|
|
5559
|
+
const baseUrl = `https://api.massive.com/v1/open-close/${encodeURIComponent(symbol)}/${formattedDate}`;
|
|
5560
5560
|
const params = new URLSearchParams({
|
|
5561
5561
|
apiKey: options?.apiKey || POLYGON_API_KEY,
|
|
5562
5562
|
adjusted: (options?.adjusted ?? true).toString(),
|
|
@@ -5606,7 +5606,7 @@ const fetchTrades = async (symbol, options) => {
|
|
|
5606
5606
|
if (!options?.apiKey && !POLYGON_API_KEY) {
|
|
5607
5607
|
throw new Error("Polygon API key is missing");
|
|
5608
5608
|
}
|
|
5609
|
-
const baseUrl = `https://api.
|
|
5609
|
+
const baseUrl = `https://api.massive.com/v3/trades/${encodeURIComponent(symbol)}`;
|
|
5610
5610
|
const params = new URLSearchParams({
|
|
5611
5611
|
apiKey: options?.apiKey || POLYGON_API_KEY,
|
|
5612
5612
|
});
|
|
@@ -5672,7 +5672,7 @@ const { ALPACA_INDICES_API_KEY } = process.env;
|
|
|
5672
5672
|
const POLYGON_INDICES_CONCURRENCY_LIMIT = 5;
|
|
5673
5673
|
const polygonIndicesLimit = pLimit(POLYGON_INDICES_CONCURRENCY_LIMIT);
|
|
5674
5674
|
// Base URL for Polygon API
|
|
5675
|
-
const POLYGON_API_BASE_URL = "https://api.
|
|
5675
|
+
const POLYGON_API_BASE_URL = "https://api.massive.com";
|
|
5676
5676
|
/**
|
|
5677
5677
|
* Validates that an API key is available
|
|
5678
5678
|
* @param {string | undefined} apiKey - Optional API key to use
|
|
@@ -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;
|
|
@@ -15204,7 +15236,7 @@ const rateLimiters = {
|
|
|
15204
15236
|
*
|
|
15205
15237
|
* Configured for 5 requests per second (basic plan).
|
|
15206
15238
|
* Adjust if you have a different subscription tier.
|
|
15207
|
-
* See: https://
|
|
15239
|
+
* See: https://massive.com/pricing
|
|
15208
15240
|
*/
|
|
15209
15241
|
polygon: new TokenBucketRateLimiter({
|
|
15210
15242
|
maxTokens: 5,
|