@adaptic/utils 0.0.1029 → 0.0.1030
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 +93 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +93 -47
- package/dist/index.mjs.map +1 -1
- package/dist/test.js +7 -3
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca/legacy/account.d.ts.map +1 -1
- package/dist/types/alpaca/market-data/news.d.ts.map +1 -1
- package/dist/types/alpaca/streams/base-stream.d.ts +12 -0
- package/dist/types/alpaca/streams/base-stream.d.ts.map +1 -1
- package/dist/types/alpaca/streams/stream-manager.d.ts.map +1 -1
- package/dist/types/alpaca/streams/trading-stream.d.ts.map +1 -1
- package/dist/types/alphavantage.d.ts.map +1 -1
- package/dist/types/crypto.d.ts.map +1 -1
- package/dist/types/display-manager.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/massive-indices.d.ts.map +1 -1
- package/dist/types/massive.d.ts.map +1 -1
- package/dist/types/schemas/massive-schemas.d.ts +11 -11
- package/dist/types/types/massive-indices-types.d.ts +6 -0
- package/dist/types/types/massive-indices-types.d.ts.map +1 -1
- package/dist/types/types/massive-types.d.ts +66 -0
- package/dist/types/types/massive-types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -819,11 +819,15 @@ let fs;
|
|
|
819
819
|
let path;
|
|
820
820
|
if (isNode) {
|
|
821
821
|
try {
|
|
822
|
-
|
|
822
|
+
// Referenced inside the guard: in a browser bundle `require` is not defined,
|
|
823
|
+
// and touching the identifier at module scope would throw before the catch
|
|
824
|
+
// below could degrade the module to no-ops.
|
|
825
|
+
const loadNodeBuiltin = require;
|
|
826
|
+
const readline = loadNodeBuiltin("readline");
|
|
823
827
|
clearLine = readline.clearLine;
|
|
824
828
|
cursorTo = readline.cursorTo;
|
|
825
|
-
fs =
|
|
826
|
-
path =
|
|
829
|
+
fs = loadNodeBuiltin("fs");
|
|
830
|
+
path = loadNodeBuiltin("path");
|
|
827
831
|
}
|
|
828
832
|
catch {
|
|
829
833
|
// Silently degrade — all operations will be no-ops.
|
|
@@ -7008,7 +7012,7 @@ async function makeRequest(auth, params) {
|
|
|
7008
7012
|
});
|
|
7009
7013
|
// Handle 207 Multi-Status responses (used by closeAll positions)
|
|
7010
7014
|
if (response.status === 207 || response.ok) {
|
|
7011
|
-
return await response.json();
|
|
7015
|
+
return (await response.json());
|
|
7012
7016
|
}
|
|
7013
7017
|
const errorText = await response.text();
|
|
7014
7018
|
getLogger().error(`Alpaca API error (${response.status}): ${errorText}`, {
|
|
@@ -8643,8 +8647,7 @@ async function fetchAccountDetails({ accountId, client, alpacaAccount, auth, })
|
|
|
8643
8647
|
if (!response.ok) {
|
|
8644
8648
|
throw new Error(`Failed to fetch account details: ${response.statusText}`);
|
|
8645
8649
|
}
|
|
8646
|
-
|
|
8647
|
-
return data;
|
|
8650
|
+
return (await response.json());
|
|
8648
8651
|
}
|
|
8649
8652
|
catch (error) {
|
|
8650
8653
|
getLogger().error("Error in fetchAccountDetails:", error);
|
|
@@ -8711,8 +8714,7 @@ async function fetchPortfolioHistory({ params, accountId, client, alpacaAccount,
|
|
|
8711
8714
|
const errorText = await response.text();
|
|
8712
8715
|
throw new Error(`Failed to fetch portfolio history: ${response.status} ${response.statusText} ${errorText}`);
|
|
8713
8716
|
}
|
|
8714
|
-
|
|
8715
|
-
return data;
|
|
8717
|
+
return (await response.json());
|
|
8716
8718
|
}
|
|
8717
8719
|
catch (error) {
|
|
8718
8720
|
getLogger().error("[fetchPortfolioHistory] Error fetching portfolio history call to Alpaca:", error);
|
|
@@ -9267,8 +9269,7 @@ const fetchQuote = async (ticker, options) => {
|
|
|
9267
9269
|
if (!response.ok) {
|
|
9268
9270
|
throw new Error(`Failed to fetch quote for ${ticker}: ${response.status}`);
|
|
9269
9271
|
}
|
|
9270
|
-
|
|
9271
|
-
return data;
|
|
9272
|
+
return (await response.json());
|
|
9272
9273
|
}, API_RETRY_CONFIGS.ALPHA_VANTAGE, `AlphaVantage.fetchQuote(${ticker})`);
|
|
9273
9274
|
});
|
|
9274
9275
|
};
|
|
@@ -9500,7 +9501,7 @@ async function fetchBars(params) {
|
|
|
9500
9501
|
const errorText = await response.text();
|
|
9501
9502
|
throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
|
|
9502
9503
|
}
|
|
9503
|
-
const data = await response.json();
|
|
9504
|
+
const data = (await response.json());
|
|
9504
9505
|
// Convert timestamp strings to Date objects and merge bars
|
|
9505
9506
|
Object.entries(data.bars).forEach(([symbol, bars]) => {
|
|
9506
9507
|
if (allBars[symbol]) {
|
|
@@ -9578,7 +9579,7 @@ async function fetchNews(params, auth) {
|
|
|
9578
9579
|
const errorText = await response.text();
|
|
9579
9580
|
throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
|
|
9580
9581
|
}
|
|
9581
|
-
const data = await response.json();
|
|
9582
|
+
const data = (await response.json());
|
|
9582
9583
|
const pageArticles = (data.news ?? []).map((article) => ({
|
|
9583
9584
|
id: article.id,
|
|
9584
9585
|
author: article.author,
|
|
@@ -9647,7 +9648,7 @@ async function fetchLatestTrades(params, auth) {
|
|
|
9647
9648
|
const errorText = await response.text();
|
|
9648
9649
|
throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
|
|
9649
9650
|
}
|
|
9650
|
-
const data = await response.json();
|
|
9651
|
+
const data = (await response.json());
|
|
9651
9652
|
logIfDebug(`Received latest trades for ${Object.keys(data.trades).length} symbols`);
|
|
9652
9653
|
return data;
|
|
9653
9654
|
}, API_RETRY_CONFIGS.CRYPTO, `Crypto.fetchLatestTrades(${symbolsParam})`);
|
|
@@ -9690,7 +9691,7 @@ async function fetchLatestQuotes(params, auth) {
|
|
|
9690
9691
|
const errorText = await response.text();
|
|
9691
9692
|
throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
|
|
9692
9693
|
}
|
|
9693
|
-
const data = await response.json();
|
|
9694
|
+
const data = (await response.json());
|
|
9694
9695
|
logIfDebug(`Received latest quotes for ${Object.keys(data.quotes).length} symbols`);
|
|
9695
9696
|
return data;
|
|
9696
9697
|
}, API_RETRY_CONFIGS.CRYPTO, `Crypto.fetchLatestQuotes(${symbolsParam})`);
|
|
@@ -9900,6 +9901,39 @@ function normalizeMassiveSymbol(symbol) {
|
|
|
9900
9901
|
}
|
|
9901
9902
|
return `X:${base.toUpperCase()}-${quote.toUpperCase()}`;
|
|
9902
9903
|
}
|
|
9904
|
+
/**
|
|
9905
|
+
* Fields of {@link MassiveTickerInfo} that carry no sensible default and whose
|
|
9906
|
+
* absence therefore makes a ticker-details response unusable rather than
|
|
9907
|
+
* merely sparse.
|
|
9908
|
+
*/
|
|
9909
|
+
const REQUIRED_TICKER_FIELDS = [
|
|
9910
|
+
"active",
|
|
9911
|
+
"currency_name",
|
|
9912
|
+
"locale",
|
|
9913
|
+
"market",
|
|
9914
|
+
"name",
|
|
9915
|
+
"primary_exchange",
|
|
9916
|
+
"ticker",
|
|
9917
|
+
"type",
|
|
9918
|
+
];
|
|
9919
|
+
/**
|
|
9920
|
+
* Rejects a ticker payload that is missing a field {@link MassiveTickerInfo}
|
|
9921
|
+
* declares as required, naming the first field found absent.
|
|
9922
|
+
*
|
|
9923
|
+
* The vendor answers 200 for a partially-populated ticker, so without this
|
|
9924
|
+
* check an absent field would be published to consumers as a value typed
|
|
9925
|
+
* `string` that holds `undefined` — an unknown masquerading as a reading.
|
|
9926
|
+
*
|
|
9927
|
+
* @param results - The ticker payload as received from the vendor.
|
|
9928
|
+
* @throws When any required field is absent.
|
|
9929
|
+
*/
|
|
9930
|
+
function assertRequiredTickerFields(results) {
|
|
9931
|
+
for (const field of REQUIRED_TICKER_FIELDS) {
|
|
9932
|
+
if (results[field] === undefined) {
|
|
9933
|
+
throw new Error(`Missing required field in Massive API response: ${field}`);
|
|
9934
|
+
}
|
|
9935
|
+
}
|
|
9936
|
+
}
|
|
9903
9937
|
// Use to update general information about stocks
|
|
9904
9938
|
/**
|
|
9905
9939
|
* Fetches general information about a stock ticker.
|
|
@@ -9922,7 +9956,7 @@ const fetchTickerInfo = async (symbol, options) => {
|
|
|
9922
9956
|
await rateLimiters$1.massive.acquire();
|
|
9923
9957
|
try {
|
|
9924
9958
|
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
9925
|
-
const data = await response.json();
|
|
9959
|
+
const data = (await response.json());
|
|
9926
9960
|
// Check for "NOT_FOUND" status and return null
|
|
9927
9961
|
if (data.status === "NOT_FOUND") {
|
|
9928
9962
|
getLogger().warn(`Ticker not found: ${symbol}`);
|
|
@@ -9934,21 +9968,7 @@ const fetchTickerInfo = async (symbol, options) => {
|
|
|
9934
9968
|
throw new Error("No results in Massive API response");
|
|
9935
9969
|
}
|
|
9936
9970
|
// Validate required fields
|
|
9937
|
-
|
|
9938
|
-
"active",
|
|
9939
|
-
"currency_name",
|
|
9940
|
-
"locale",
|
|
9941
|
-
"market",
|
|
9942
|
-
"name",
|
|
9943
|
-
"primary_exchange",
|
|
9944
|
-
"ticker",
|
|
9945
|
-
"type",
|
|
9946
|
-
];
|
|
9947
|
-
for (const field of requiredFields) {
|
|
9948
|
-
if (results[field] === undefined) {
|
|
9949
|
-
throw new Error(`Missing required field in Massive API response: ${field}`);
|
|
9950
|
-
}
|
|
9951
|
-
}
|
|
9971
|
+
assertRequiredTickerFields(results);
|
|
9952
9972
|
// Handle optional share_class_shares_outstanding field
|
|
9953
9973
|
if (results.share_class_shares_outstanding === undefined) {
|
|
9954
9974
|
results.share_class_shares_outstanding = null;
|
|
@@ -10194,7 +10214,7 @@ const fetchPrices = async (params, options) => {
|
|
|
10194
10214
|
//getLogger().info(`Debug: Fetching ${nextUrl}`);
|
|
10195
10215
|
await rateLimiters$1.massive.acquire();
|
|
10196
10216
|
const response = await fetchWithRetry(nextUrl, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
10197
|
-
const data = await response.json();
|
|
10217
|
+
const data = (await response.json());
|
|
10198
10218
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
10199
10219
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
10200
10220
|
}
|
|
@@ -10221,7 +10241,7 @@ const fetchPrices = async (params, options) => {
|
|
|
10221
10241
|
receivedAt: new Date(),
|
|
10222
10242
|
...(aggregatedStatus === "DELAYED" ? { delayedSince: null } : {}),
|
|
10223
10243
|
};
|
|
10224
|
-
|
|
10244
|
+
const bars = allResults.map((entry) => ({
|
|
10225
10245
|
date: new Date(entry.t).toLocaleString("en-US", {
|
|
10226
10246
|
year: "numeric",
|
|
10227
10247
|
month: "short",
|
|
@@ -10243,6 +10263,12 @@ const fetchPrices = async (params, options) => {
|
|
|
10243
10263
|
trades: entry.n,
|
|
10244
10264
|
_freshness: freshness,
|
|
10245
10265
|
}));
|
|
10266
|
+
// The aggregates endpoint names the ticker once on the envelope rather
|
|
10267
|
+
// than on each bar, and this mapping does not copy it down, so the bars
|
|
10268
|
+
// carry every field of `MassivePriceData` except `symbol`. The assertion
|
|
10269
|
+
// records that divergence at the single point where it arises instead of
|
|
10270
|
+
// leaving it implicit in an untyped payload.
|
|
10271
|
+
return bars;
|
|
10246
10272
|
}
|
|
10247
10273
|
catch (error) {
|
|
10248
10274
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -10382,7 +10408,7 @@ const fetchGroupedDaily = async (date, options) => {
|
|
|
10382
10408
|
await rateLimiters$1.massive.acquire();
|
|
10383
10409
|
try {
|
|
10384
10410
|
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
10385
|
-
const data = await response.json();
|
|
10411
|
+
const data = (await response.json());
|
|
10386
10412
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
10387
10413
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
10388
10414
|
}
|
|
@@ -10404,6 +10430,10 @@ const fetchGroupedDaily = async (date, options) => {
|
|
|
10404
10430
|
trades: result.n,
|
|
10405
10431
|
})),
|
|
10406
10432
|
};
|
|
10433
|
+
// Grouped daily bars are keyed by timestamp only; this mapping does not
|
|
10434
|
+
// derive the human-readable `date` string that `MassivePriceData` also
|
|
10435
|
+
// declares, so the reshaped bars carry every field except that one. The
|
|
10436
|
+
// assertion records that divergence at its single point of origin.
|
|
10407
10437
|
return groupedDaily;
|
|
10408
10438
|
}
|
|
10409
10439
|
catch (error) {
|
|
@@ -10476,7 +10506,7 @@ symbol, date = new Date(), options) => {
|
|
|
10476
10506
|
await rateLimiters$1.massive.acquire();
|
|
10477
10507
|
try {
|
|
10478
10508
|
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
10479
|
-
const data = await response.json();
|
|
10509
|
+
const data = (await response.json());
|
|
10480
10510
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
10481
10511
|
throw new Error(`Failed to fetch daily open/close data for ${symbol}: ${data.status}`);
|
|
10482
10512
|
}
|
|
@@ -10608,6 +10638,19 @@ const validateApiKey = (apiKey) => {
|
|
|
10608
10638
|
}
|
|
10609
10639
|
return key;
|
|
10610
10640
|
};
|
|
10641
|
+
/**
|
|
10642
|
+
* Narrows a decoded Massive Indices body to its error form.
|
|
10643
|
+
*
|
|
10644
|
+
* The API reports failures in band: the transport answers 200 and the `status`
|
|
10645
|
+
* word carries the outcome, so the body has to be classified before any of its
|
|
10646
|
+
* success fields can be read. Expressing that classification as a type guard is
|
|
10647
|
+
* what lets each fetcher return its payload directly rather than asserting a
|
|
10648
|
+
* success shape over a body that may be an error.
|
|
10649
|
+
*
|
|
10650
|
+
* @param body - A decoded Massive Indices response body.
|
|
10651
|
+
* @returns True when the body reports an error rather than a payload.
|
|
10652
|
+
*/
|
|
10653
|
+
const isIndicesErrorResponse = (body) => body.status === "ERROR";
|
|
10611
10654
|
/**
|
|
10612
10655
|
* Fetches aggregate bars for an index over a given date range in custom time window sizes.
|
|
10613
10656
|
*
|
|
@@ -10633,8 +10676,8 @@ const fetchIndicesAggregates = async (params, options) => {
|
|
|
10633
10676
|
await rateLimiters$1.massive.acquire();
|
|
10634
10677
|
try {
|
|
10635
10678
|
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
10636
|
-
const data = await response.json();
|
|
10637
|
-
if (data
|
|
10679
|
+
const data = (await response.json());
|
|
10680
|
+
if (isIndicesErrorResponse(data)) {
|
|
10638
10681
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
10639
10682
|
}
|
|
10640
10683
|
return data;
|
|
@@ -10663,8 +10706,8 @@ const fetchIndicesPreviousClose = async (indicesTicker, options) => {
|
|
|
10663
10706
|
await rateLimiters$1.massive.acquire();
|
|
10664
10707
|
try {
|
|
10665
10708
|
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
10666
|
-
const data = await response.json();
|
|
10667
|
-
if (data
|
|
10709
|
+
const data = (await response.json());
|
|
10710
|
+
if (isIndicesErrorResponse(data)) {
|
|
10668
10711
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
10669
10712
|
}
|
|
10670
10713
|
return data;
|
|
@@ -10694,8 +10737,8 @@ const fetchIndicesDailyOpenClose = async (indicesTicker, date, options) => {
|
|
|
10694
10737
|
await rateLimiters$1.massive.acquire();
|
|
10695
10738
|
try {
|
|
10696
10739
|
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
10697
|
-
const data = await response.json();
|
|
10698
|
-
if (data
|
|
10740
|
+
const data = (await response.json());
|
|
10741
|
+
if (isIndicesErrorResponse(data)) {
|
|
10699
10742
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
10700
10743
|
}
|
|
10701
10744
|
return data;
|
|
@@ -10736,8 +10779,8 @@ const fetchIndicesSnapshot = async (params, options) => {
|
|
|
10736
10779
|
await rateLimiters$1.massive.acquire();
|
|
10737
10780
|
try {
|
|
10738
10781
|
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
10739
|
-
const data = await response.json();
|
|
10740
|
-
if (data
|
|
10782
|
+
const data = (await response.json());
|
|
10783
|
+
if (isIndicesErrorResponse(data)) {
|
|
10741
10784
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
10742
10785
|
}
|
|
10743
10786
|
return data;
|
|
@@ -10785,8 +10828,8 @@ const fetchUniversalSnapshot = async (tickers, options) => {
|
|
|
10785
10828
|
await rateLimiters$1.massive.acquire();
|
|
10786
10829
|
try {
|
|
10787
10830
|
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
10788
|
-
const data = await response.json();
|
|
10789
|
-
if (data
|
|
10831
|
+
const data = (await response.json());
|
|
10832
|
+
if (isIndicesErrorResponse(data)) {
|
|
10790
10833
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
10791
10834
|
}
|
|
10792
10835
|
return data;
|
|
@@ -56543,9 +56586,12 @@ function stripHtml(html) {
|
|
|
56543
56586
|
.replace(/”/g, '"')
|
|
56544
56587
|
.replace(/‘/g, "'")
|
|
56545
56588
|
.replace(/’/g, "'");
|
|
56546
|
-
// Decode numeric HTML entities
|
|
56547
|
-
|
|
56548
|
-
|
|
56589
|
+
// Decode numeric HTML entities. The replacer's capture arguments are declared
|
|
56590
|
+
// by `String.prototype.replace` as `...args: any[]`, since their count depends
|
|
56591
|
+
// on the pattern; each pattern here has exactly one capture group, and a
|
|
56592
|
+
// matched group is always a string, so the parameters are named accordingly.
|
|
56593
|
+
text = text.replace(/&#(\d+);/g, (_match, code) => String.fromCharCode(parseInt(code, 10)));
|
|
56594
|
+
text = text.replace(/&#x([0-9a-fA-F]+);/g, (_match, code) => String.fromCharCode(parseInt(code, 16)));
|
|
56549
56595
|
// Normalize whitespace
|
|
56550
56596
|
text = text.replace(/\s+/g, " ").trim();
|
|
56551
56597
|
return text;
|