@exodus/market-history 10.7.0 → 10.7.1
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/CHANGELOG.md +4 -0
- package/lib/atoms/index.d.ts +1 -1
- package/lib/constants.d.ts +3 -0
- package/lib/constants.js +3 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -3
- package/lib/module/fetch-and-process-tickers.d.ts +1 -1
- package/lib/module/fetch-historical-prices.d.ts +1 -1
- package/lib/module/get-limit-to-fetch.d.ts +1 -1
- package/lib/module/get-limit-to-fetch.js +6 -7
- package/lib/module/index.js +16 -13
- package/lib/module/prepare-fetch-instructions.d.ts +1 -1
- package/lib/module/process-api-response.d.ts +1 -1
- package/lib/plugin/index.d.ts +1 -1
- package/lib/types.d.ts +1 -1
- package/package.json +8 -3
- package/redux.js +2 -0
- package/lib/module/constants.d.ts +0 -2
- package/lib/module/constants.js +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.7.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/market-history@10.7.0...@exodus/market-history@10.7.1) (2026-05-04)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @exodus/market-history
|
|
9
|
+
|
|
6
10
|
## [10.7.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/market-history@10.6.3...@exodus/market-history@10.7.0) (2026-05-01)
|
|
7
11
|
|
|
8
12
|
### Features
|
package/lib/atoms/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { MarketHistoryState } from '../types.js';
|
|
|
3
3
|
export declare const marketHistoryAtomDefinition: {
|
|
4
4
|
readonly id: "marketHistoryAtom";
|
|
5
5
|
readonly type: "atom";
|
|
6
|
-
readonly factory: () => import("@exodus/atoms").Atom<MarketHistoryState>;
|
|
6
|
+
readonly factory: () => import("@exodus/atoms").Atom<MarketHistoryState | undefined>;
|
|
7
7
|
readonly dependencies: readonly [];
|
|
8
8
|
readonly public: true;
|
|
9
9
|
};
|
package/lib/constants.js
ADDED
package/lib/index.d.ts
CHANGED
|
@@ -105,7 +105,7 @@ declare const marketHistory: ({ clearHistoryCacheDefaultValue, remoteConfigClear
|
|
|
105
105
|
stop: () => void;
|
|
106
106
|
hydrate: () => Promise<void>;
|
|
107
107
|
};
|
|
108
|
-
marketHistoryAtom: import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState>;
|
|
108
|
+
marketHistoryAtom: import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState | undefined>;
|
|
109
109
|
appProcessAtom?: import("@exodus/atoms").ReadonlyAtom<{
|
|
110
110
|
mode: string;
|
|
111
111
|
}>;
|
|
@@ -126,7 +126,7 @@ declare const marketHistory: ({ clearHistoryCacheDefaultValue, remoteConfigClear
|
|
|
126
126
|
definition: {
|
|
127
127
|
readonly id: "marketHistoryAtom";
|
|
128
128
|
readonly type: "atom";
|
|
129
|
-
readonly factory: () => import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState>;
|
|
129
|
+
readonly factory: () => import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState | undefined>;
|
|
130
130
|
readonly dependencies: readonly [];
|
|
131
131
|
readonly public: true;
|
|
132
132
|
};
|
package/lib/index.js
CHANGED
|
@@ -3,11 +3,9 @@ import { marketHistoryAtomDefinition, marketHistoryClearCacheAtomDefinition, mar
|
|
|
3
3
|
import marketHistoryMonitorDefinition from './module/index.js';
|
|
4
4
|
import marketHistoryPluginDefinition from './plugin/index.js';
|
|
5
5
|
import marketHistoryApiDefinition from './api/index.js';
|
|
6
|
+
import { DEFAULT_DAILY_REQUEST_LIMIT, DEFAULT_HOURLY_REQUEST_LIMIT, DEFAULT_MINUTELY_REQUEST_LIMIT, } from './constants.js';
|
|
6
7
|
const CLEAR_MARKET_HISTORY_VERSION = 'infrastructure.marketHistory.clearVersion';
|
|
7
8
|
const REFRESH_INTERVAL_ATOM_PATH = 'infrastructure.marketHistory.refreshInterval';
|
|
8
|
-
const DEFAULT_DAILY_REQUEST_LIMIT = 366;
|
|
9
|
-
const DEFAULT_HOURLY_REQUEST_LIMIT = 7 * 24;
|
|
10
|
-
const DEFAULT_MINUTELY_REQUEST_LIMIT = 2 * 60;
|
|
11
9
|
const marketHistory = ({ clearHistoryCacheDefaultValue = null, remoteConfigClearHistoryCachePath = CLEAR_MARKET_HISTORY_VERSION, remoteConfigClearHistoryCacheDefaultValue = null, marketHistoryRefreshIntervalPath = REFRESH_INTERVAL_ATOM_PATH, marketHistoryRefreshIntervalDefaultValue = null, dailyRequestLimit = DEFAULT_DAILY_REQUEST_LIMIT, hourlyRequestLimit = DEFAULT_HOURLY_REQUEST_LIMIT, minutelyRequestLimit = DEFAULT_MINUTELY_REQUEST_LIMIT, } = Object.create(null)) => {
|
|
12
10
|
return {
|
|
13
11
|
id: safeString `marketHistory`,
|
|
@@ -14,6 +14,6 @@ export default function fetchAndProcessTickers({ assetTickersToFetch, api, fiatT
|
|
|
14
14
|
historicalPricesMap: Map<string, Map<number, PriceData>>;
|
|
15
15
|
fetchedPricesMap: Map<string, Map<number, PriceData>>;
|
|
16
16
|
specificTimestamp?: number | null;
|
|
17
|
-
requestLimit
|
|
17
|
+
requestLimit: number;
|
|
18
18
|
}): Promise<void>;
|
|
19
19
|
export {};
|
|
@@ -5,7 +5,7 @@ export default function fetchHistoricalPrices({ api, assetTickers, fiatTicker, g
|
|
|
5
5
|
fiatTicker: string;
|
|
6
6
|
granularity?: Granularity;
|
|
7
7
|
getCacheFromStorage: (ticker: string) => Promise<CacheEntry[] | string | undefined>;
|
|
8
|
-
requestLimit
|
|
8
|
+
requestLimit: number;
|
|
9
9
|
timestamp?: number;
|
|
10
10
|
getCurrentTime?: () => number;
|
|
11
11
|
ignoreInvalidSymbols?: boolean;
|
|
@@ -3,7 +3,7 @@ declare const getLimit: ({ granularity, history, requestLimit, requestTimestamp,
|
|
|
3
3
|
granularity: Granularity;
|
|
4
4
|
history: Map<number, PriceData>;
|
|
5
5
|
requestTimestamp: number;
|
|
6
|
-
requestLimit
|
|
6
|
+
requestLimit: number;
|
|
7
7
|
specificTimestamp?: number | null;
|
|
8
8
|
}) => number;
|
|
9
9
|
export default getLimit;
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { LIMIT, START_TIME } from './constants.js';
|
|
2
1
|
import lastTimestampFromPricesMap from './last-timestamp-from-prices-map.js';
|
|
3
2
|
import { timeToDays, timeToHours, timeToMinutes } from './utils.js';
|
|
3
|
+
const START_TIME = new Date('2015-12-09').getTime();
|
|
4
4
|
const getLimit = ({ granularity, history, requestLimit, requestTimestamp, specificTimestamp, }) => {
|
|
5
5
|
if (specificTimestamp)
|
|
6
6
|
return 1;
|
|
7
7
|
const lastCachedTime = lastTimestampFromPricesMap(history);
|
|
8
|
-
const limitFromOptions = requestLimit || LIMIT[granularity];
|
|
9
8
|
if (granularity === 'minute') {
|
|
10
9
|
if (!lastCachedTime)
|
|
11
|
-
return
|
|
12
|
-
return Math.ceil(Math.min(
|
|
10
|
+
return requestLimit;
|
|
11
|
+
return Math.ceil(Math.min(requestLimit, timeToMinutes(requestTimestamp - lastCachedTime)));
|
|
13
12
|
}
|
|
14
13
|
if (granularity === 'hour') {
|
|
15
14
|
if (!lastCachedTime)
|
|
16
|
-
return
|
|
17
|
-
return Math.min(
|
|
15
|
+
return requestLimit;
|
|
16
|
+
return Math.min(requestLimit, timeToHours(requestTimestamp - lastCachedTime));
|
|
18
17
|
}
|
|
19
|
-
return Math.min(
|
|
18
|
+
return Math.min(requestLimit, timeToDays(requestTimestamp - (lastCachedTime || START_TIME)));
|
|
20
19
|
};
|
|
21
20
|
export default getLimit;
|
package/lib/module/index.js
CHANGED
|
@@ -109,7 +109,7 @@ class MarketHistoryMonitorImpl {
|
|
|
109
109
|
#runtimeCache = new Map();
|
|
110
110
|
#marketHistoryAtom;
|
|
111
111
|
#enabledAssetsAtom;
|
|
112
|
-
#granularityRequestLimits
|
|
112
|
+
#granularityRequestLimits;
|
|
113
113
|
#logger;
|
|
114
114
|
#abortController = new AbortController();
|
|
115
115
|
#synchronizedTime;
|
|
@@ -138,6 +138,9 @@ class MarketHistoryMonitorImpl {
|
|
|
138
138
|
this.#synchronizedTime = synchronizedTime;
|
|
139
139
|
}
|
|
140
140
|
#isActive = false;
|
|
141
|
+
#stillActive() {
|
|
142
|
+
return this.#isActive;
|
|
143
|
+
}
|
|
141
144
|
#setCache = async ({ currency, granularity, pricesByAssetName, }) => {
|
|
142
145
|
const assetNamesWithChanges = [];
|
|
143
146
|
const changes = Object.create(null);
|
|
@@ -186,7 +189,7 @@ class MarketHistoryMonitorImpl {
|
|
|
186
189
|
granularity,
|
|
187
190
|
assetName: getAssetFromTicker(this.assetsModule.getAssets(), assetTicker).name,
|
|
188
191
|
});
|
|
189
|
-
#fetch = async ({ currency, granularity, assetNames,
|
|
192
|
+
#fetch = async ({ currency, granularity, assetNames, }) => {
|
|
190
193
|
const assets = this.assetsModule.getAssets();
|
|
191
194
|
const assetTickers = assetNames
|
|
192
195
|
.filter((assetName) => !assets[assetName].isCombined)
|
|
@@ -219,7 +222,7 @@ class MarketHistoryMonitorImpl {
|
|
|
219
222
|
ignoreCache,
|
|
220
223
|
runtimeCache: this.#runtimeCache,
|
|
221
224
|
getRuntimeCacheKey: ({ fiatTicker, granularity, assetTicker, }) => this.#getRuntimeCacheKey({ fiatTicker, granularity, assetTicker }),
|
|
222
|
-
requestLimit:
|
|
225
|
+
requestLimit: this.#granularityRequestLimits[granularity],
|
|
223
226
|
});
|
|
224
227
|
if (fetchedPricesMap.size > 0) {
|
|
225
228
|
const pricesByAssetNameForCache = mapPricesForCache(fetchedPricesMap, assetNames, assets);
|
|
@@ -307,7 +310,7 @@ class MarketHistoryMonitorImpl {
|
|
|
307
310
|
const currency = this.#currency;
|
|
308
311
|
const promises = granularities.map((granularity) => this.#fetchPricesByGranularity({ granularity, assetNames, currency }));
|
|
309
312
|
const results = await Promise.all(promises);
|
|
310
|
-
if (!this.#
|
|
313
|
+
if (!this.#stillActive()) {
|
|
311
314
|
return;
|
|
312
315
|
}
|
|
313
316
|
await this.#marketHistoryAtom.set((current) => {
|
|
@@ -330,7 +333,7 @@ class MarketHistoryMonitorImpl {
|
|
|
330
333
|
daily: Object.create(null),
|
|
331
334
|
hourly: Object.create(null),
|
|
332
335
|
minutely: Object.create(null),
|
|
333
|
-
...current?.data
|
|
336
|
+
...current?.data[currency],
|
|
334
337
|
},
|
|
335
338
|
};
|
|
336
339
|
granularities.forEach((granularity, index) => {
|
|
@@ -502,7 +505,7 @@ class MarketHistoryMonitorImpl {
|
|
|
502
505
|
if (hydratedCount === 0)
|
|
503
506
|
return;
|
|
504
507
|
await this.#marketHistoryAtom.set((current) => {
|
|
505
|
-
if (current?.data
|
|
508
|
+
if (current?.data[currency])
|
|
506
509
|
return current;
|
|
507
510
|
return {
|
|
508
511
|
data: {
|
|
@@ -522,28 +525,28 @@ class MarketHistoryMonitorImpl {
|
|
|
522
525
|
await this.hydrate().catch((error) => {
|
|
523
526
|
this.#logger.error('market history hydrate failed', error);
|
|
524
527
|
});
|
|
525
|
-
if (!this.#
|
|
528
|
+
if (!this.#stillActive()) {
|
|
526
529
|
return;
|
|
527
530
|
}
|
|
528
531
|
const remoteConfigClearCacheVersion = await this.#remoteConfigClearCacheAtom.get();
|
|
529
532
|
await this.#invalidateStorage({ remoteConfigClearCacheVersion });
|
|
530
|
-
if (!this.#
|
|
533
|
+
if (!this.#stillActive()) {
|
|
531
534
|
return;
|
|
532
535
|
}
|
|
533
536
|
this.#currency = await this.#currencyAtom.get();
|
|
534
537
|
this.#previouslyEnabledAssets = await this.#enabledAssetsAtom.get();
|
|
535
|
-
if (!this.#
|
|
538
|
+
if (!this.#stillActive()) {
|
|
536
539
|
return;
|
|
537
540
|
}
|
|
538
541
|
await this.#initMarketHistoryAtom();
|
|
539
|
-
if (!this.#
|
|
542
|
+
if (!this.#stillActive()) {
|
|
540
543
|
return;
|
|
541
544
|
}
|
|
542
545
|
this.#setupTimers();
|
|
543
546
|
this.#listenRemoteConfigClearCacheVersionChanges();
|
|
544
547
|
this.#listenCurrencyChanges();
|
|
545
548
|
this.#listenEnabledAssetsChanges();
|
|
546
|
-
if (!this.#
|
|
549
|
+
if (!this.#stillActive()) {
|
|
547
550
|
return;
|
|
548
551
|
}
|
|
549
552
|
await this.updateAll();
|
|
@@ -616,9 +619,9 @@ class MarketHistoryMonitorImpl {
|
|
|
616
619
|
return {
|
|
617
620
|
data: {
|
|
618
621
|
[currency]: {
|
|
619
|
-
...current?.data
|
|
622
|
+
...current?.data[currency],
|
|
620
623
|
[parsedGranularity]: {
|
|
621
|
-
...current?.data
|
|
624
|
+
...current?.data[currency]?.[parsedGranularity],
|
|
622
625
|
[assetName]: transformedPrices,
|
|
623
626
|
},
|
|
624
627
|
},
|
|
@@ -4,7 +4,7 @@ export default function prepareFetchInstructions({ tickerSymbol, fiatTicker, gra
|
|
|
4
4
|
fiatTicker: string;
|
|
5
5
|
granularity: Granularity;
|
|
6
6
|
getCacheFromStorage: (ticker: string) => Promise<CacheEntry[] | string | undefined>;
|
|
7
|
-
requestLimit
|
|
7
|
+
requestLimit: number;
|
|
8
8
|
specificTimestamp?: number | null;
|
|
9
9
|
ignoreCache: boolean;
|
|
10
10
|
runtimeCache: Map<string, CacheEntry[]>;
|
|
@@ -8,5 +8,5 @@ export default function processApiResponse({ assetTicker, fiatTicker, fetchedPri
|
|
|
8
8
|
historicalPricesMap: Map<string, Map<number, PriceData>>;
|
|
9
9
|
granularity: Granularity;
|
|
10
10
|
specificTimestamp?: number | null;
|
|
11
|
-
requestLimit
|
|
11
|
+
requestLimit: number;
|
|
12
12
|
}): Map<number, PriceData> | null;
|
package/lib/plugin/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ type MarketHistoryMonitor = {
|
|
|
7
7
|
};
|
|
8
8
|
type Dependencies = {
|
|
9
9
|
marketHistoryMonitor: MarketHistoryMonitor;
|
|
10
|
-
marketHistoryAtom: Atom<MarketHistoryState>;
|
|
10
|
+
marketHistoryAtom: Atom<MarketHistoryState | undefined>;
|
|
11
11
|
appProcessAtom?: ReadonlyAtom<{
|
|
12
12
|
mode: string;
|
|
13
13
|
}>;
|
package/lib/types.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export type MarketHistoryMonitorDependencies = {
|
|
|
77
77
|
clearCacheAtom?: Atom<string | null>;
|
|
78
78
|
remoteConfigClearCacheAtom?: Atom<string | null>;
|
|
79
79
|
enabledAssetsAtom: ReadonlyAtom<Record<string, Asset>>;
|
|
80
|
-
marketHistoryAtom: Atom<MarketHistoryState>;
|
|
80
|
+
marketHistoryAtom: Atom<MarketHistoryState | undefined>;
|
|
81
81
|
logger: Logger;
|
|
82
82
|
config?: {
|
|
83
83
|
granularityRequestLimits?: Record<Granularity, number>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/market-history",
|
|
3
|
-
"version": "10.7.
|
|
3
|
+
"version": "10.7.1",
|
|
4
4
|
"description": "Fetches historical prices for assets",
|
|
5
5
|
"author": "Exodus Movement, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
"main": "lib/index.js",
|
|
18
18
|
"types": "lib/index.d.ts",
|
|
19
19
|
"typings": "lib/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./lib/index.js",
|
|
22
|
+
"./redux": "./lib/redux/index.js"
|
|
23
|
+
},
|
|
20
24
|
"files": [
|
|
21
25
|
"lib",
|
|
26
|
+
"redux.js",
|
|
22
27
|
"CHANGELOG.md",
|
|
23
28
|
"README.md"
|
|
24
29
|
],
|
|
@@ -44,7 +49,7 @@
|
|
|
44
49
|
"@exodus/locale": "^2.7.0",
|
|
45
50
|
"@exodus/logger": "^1.2.3",
|
|
46
51
|
"@exodus/rates-monitor": "^4.14.8",
|
|
47
|
-
"@exodus/redux-dependency-injection": "^4.
|
|
52
|
+
"@exodus/redux-dependency-injection": "^4.5.0",
|
|
48
53
|
"@exodus/storage-memory": "^2.4.0",
|
|
49
54
|
"events": "^3.3.0",
|
|
50
55
|
"redux": "^4.0.0"
|
|
@@ -61,5 +66,5 @@
|
|
|
61
66
|
"access": "public",
|
|
62
67
|
"provenance": false
|
|
63
68
|
},
|
|
64
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "ef035f3c387767ab37076ad2d2dfb8be62f19ea6"
|
|
65
70
|
}
|
package/redux.js
ADDED
package/lib/module/constants.js
DELETED