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