@1delta/data-sdk 0.0.45 → 0.0.47

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.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './chains';
2
2
  export * from './lending';
3
+ export * from './remoteCache';
3
4
  export * from './tokens';
package/dist/index.js CHANGED
@@ -862,12 +862,143 @@ var parseFraxlendPairKey = (lender) => {
862
862
  return { chainId: m[1], pair: m[2].toLowerCase() };
863
863
  };
864
864
 
865
+ // src/remoteCache.ts
866
+ var FRESH_TTL_MS = 5 * 60 * 1e3;
867
+ var REMOTE_CACHE_STORE_TTL_S = 7 * 24 * 60 * 60;
868
+ var STATE_KEY = "__1delta_remote_cache__";
869
+ function getState() {
870
+ const g = globalThis;
871
+ if (!g[STATE_KEY]) g[STATE_KEY] = { memo: /* @__PURE__ */ new Map(), inflight: /* @__PURE__ */ new Map() };
872
+ return g[STATE_KEY];
873
+ }
874
+ function setRemoteCacheStore(next) {
875
+ getState().store = next;
876
+ }
877
+ function setRemoteCacheGithubToken(token) {
878
+ getState().githubToken = token;
879
+ }
880
+ function clearRemoteCache() {
881
+ const state = getState();
882
+ state.memo.clear();
883
+ state.inflight.clear();
884
+ }
885
+ var RAW_HOST = "https://raw.githubusercontent.com/";
886
+ function githubApiMirror(url) {
887
+ if (!url.startsWith(RAW_HOST)) return void 0;
888
+ const [owner, repo, ref, ...path] = url.slice(RAW_HOST.length).split("/");
889
+ if (!owner || !repo || !ref || path.length === 0) return void 0;
890
+ return `https://api.github.com/repos/${owner}/${repo}/contents/${path.join("/")}?ref=${ref}`;
891
+ }
892
+ var RemoteFetchError = class extends Error {
893
+ constructor(message, status) {
894
+ super(message);
895
+ this.status = status;
896
+ this.name = "RemoteFetchError";
897
+ }
898
+ /** 404/410 — re-fetching cannot change the answer. */
899
+ get isMissing() {
900
+ return this.status === 404 || this.status === 410;
901
+ }
902
+ };
903
+ async function fetchRemoteJson(url, label) {
904
+ const res = await fetch(url);
905
+ if (res.ok) return await res.json();
906
+ const mirror = githubApiMirror(url);
907
+ const worthRetrying = res.status === 429 || res.status >= 500;
908
+ if (!mirror || !worthRetrying) {
909
+ throw new RemoteFetchError(`${label} fetch failed: HTTP ${res.status} from ${new URL(url).host}`, res.status);
910
+ }
911
+ const headers = {
912
+ Accept: "application/vnd.github.raw",
913
+ // The GitHub API rejects a request that sends no User-Agent.
914
+ "User-Agent": "1delta-data-sdk"
915
+ };
916
+ const token = getState().githubToken;
917
+ if (token) headers.Authorization = `Bearer ${token}`;
918
+ const viaApi = await fetch(mirror, { headers });
919
+ if (!viaApi.ok) {
920
+ throw new RemoteFetchError(
921
+ `${label} fetch failed: HTTP ${res.status} from raw.githubusercontent.com, HTTP ${viaApi.status} from api.github.com`,
922
+ res.status
923
+ );
924
+ }
925
+ return await viaApi.json();
926
+ }
927
+ var storeKey = (key) => `remote-cache:v1:${key}`;
928
+ async function readStore(key, isValid) {
929
+ const { store } = getState();
930
+ if (!store) return void 0;
931
+ try {
932
+ const raw = await store.get(storeKey(key));
933
+ if (!raw) return void 0;
934
+ const parsed = JSON.parse(raw);
935
+ if (typeof parsed?.at !== "number" || !isValid(parsed.value)) return void 0;
936
+ return parsed;
937
+ } catch {
938
+ return void 0;
939
+ }
940
+ }
941
+ async function writeStore(key, entry) {
942
+ const { store } = getState();
943
+ if (!store) return;
944
+ try {
945
+ await store.put(storeKey(key), JSON.stringify(entry), REMOTE_CACHE_STORE_TTL_S);
946
+ } catch {
947
+ }
948
+ }
949
+ async function loadCached(key, load, isValid) {
950
+ const { memo, inflight } = getState();
951
+ const cached = memo.get(key);
952
+ if (cached && Date.now() - cached.at < FRESH_TTL_MS) return cached.value;
953
+ const pending = inflight.get(key);
954
+ if (pending) return pending;
955
+ const task = (async () => {
956
+ const stored = await readStore(key, isValid);
957
+ if (stored && Date.now() - stored.at < FRESH_TTL_MS) {
958
+ memo.set(key, stored);
959
+ return stored.value;
960
+ }
961
+ try {
962
+ const value = await load();
963
+ const entry = { at: Date.now(), value };
964
+ memo.set(key, entry);
965
+ await writeStore(key, entry);
966
+ return value;
967
+ } catch (error) {
968
+ const stale = memo.get(key) ?? stored;
969
+ if (!stale) throw error;
970
+ memo.set(key, stale);
971
+ return stale.value;
972
+ }
973
+ })().finally(() => {
974
+ inflight.delete(key);
975
+ });
976
+ inflight.set(key, task);
977
+ return task;
978
+ }
979
+ async function loadCachedJson(key, url, isValid, label = key) {
980
+ return loadCached(key, () => fetchRemoteJson(url, label), isValid);
981
+ }
982
+
865
983
  // src/tokens.ts
866
984
  var getListUrl = (chainId) => `https://raw.githubusercontent.com/1delta-DAO/token-lists/main/${chainId}.json`;
985
+ var MAIN_TOKENS_URL = "https://raw.githubusercontent.com/1delta-DAO/token-lists/main/main-tokens.json";
986
+ var isTokenListFile = (value) => !!value?.list && typeof value.list === "object";
987
+ async function loadTokenListFile(chainId) {
988
+ return loadCached(
989
+ `token-list:${chainId}`,
990
+ async () => {
991
+ const json = await fetchRemoteJson(getListUrl(chainId), `Token list for chain ${chainId}`);
992
+ return {
993
+ list: json.list,
994
+ mainTokens: json.mainTokens ?? []
995
+ };
996
+ },
997
+ isTokenListFile
998
+ );
999
+ }
867
1000
  async function fetchTokenList(chainId) {
868
- const data = await fetch(getListUrl(chainId));
869
- if (!data.ok) throw new Error(`HTTP error! status: ${data.status}`);
870
- return (await data.json()).list;
1001
+ return (await loadTokenListFile(chainId)).list;
871
1002
  }
872
1003
  async function fetchTokenLists(chainIds) {
873
1004
  const promises = chainIds.map(async (chainId) => {
@@ -878,25 +1009,27 @@ async function fetchTokenLists(chainIds) {
878
1009
  return Object.fromEntries(results);
879
1010
  }
880
1011
  async function fetchTokenListFile(chainId) {
881
- const data = await fetch(getListUrl(chainId));
882
- if (!data.ok) throw new Error(`HTTP error! status: ${data.status}`);
883
- const json = await data.json();
884
- return {
885
- list: json.list,
886
- mainTokens: json.mainTokens ?? []
887
- };
1012
+ const file = await loadTokenListFile(chainId);
1013
+ return { list: file.list, mainTokens: file.mainTokens };
888
1014
  }
889
- var MAIN_TOKENS_URL = "https://raw.githubusercontent.com/1delta-DAO/token-lists/main/main-tokens.json";
890
1015
  async function fetchMainTokensMap() {
891
- const data = await fetch(MAIN_TOKENS_URL);
892
- if (!data.ok) return void 0;
893
- return await data.json();
1016
+ try {
1017
+ return await loadCached(
1018
+ "main-tokens",
1019
+ () => fetchRemoteJson(MAIN_TOKENS_URL, "main-tokens"),
1020
+ (value) => !!value && typeof value === "object"
1021
+ );
1022
+ } catch {
1023
+ return void 0;
1024
+ }
894
1025
  }
895
1026
 
896
1027
  exports.CURVANCE_MONAD_CONFIG = CURVANCE_MONAD_CONFIG;
897
1028
  exports.FRAXLEND_ETHEREUM_CONFIG = FRAXLEND_ETHEREUM_CONFIG;
898
1029
  exports.GEARBOX_ACCOUNT_COMPRESSOR_V310 = GEARBOX_ACCOUNT_COMPRESSOR_V310;
1030
+ exports.REMOTE_CACHE_STORE_TTL_S = REMOTE_CACHE_STORE_TTL_S;
899
1031
  exports.RESUPPLY_ETHEREUM_CONFIG = RESUPPLY_ETHEREUM_CONFIG;
1032
+ exports.RemoteFetchError = RemoteFetchError;
900
1033
  exports.aaveOracles = aaveOracles;
901
1034
  exports.aaveOraclesConfig = aaveOraclesConfig;
902
1035
  exports.aavePools = aavePools;
@@ -909,6 +1042,7 @@ exports.aaveV4Spokes = aaveV4Spokes;
909
1042
  exports.aaveWethGateway = aaveWethGateway;
910
1043
  exports.chainLogoURI = chainLogoURI;
911
1044
  exports.chains = chains;
1045
+ exports.clearRemoteCache = clearRemoteCache;
912
1046
  exports.compoundV2Oracles = compoundV2Oracles;
913
1047
  exports.compoundV2OraclesConfig = compoundV2OraclesConfig;
914
1048
  exports.compoundV2Pools = compoundV2Pools;
@@ -942,6 +1076,7 @@ exports.exactlyMarketByAsset = exactlyMarketByAsset;
942
1076
  exports.exactlyMarkets = exactlyMarkets;
943
1077
  exports.exactlyMarketsByChain = exactlyMarketsByChain;
944
1078
  exports.fetchMainTokensMap = fetchMainTokensMap;
1079
+ exports.fetchRemoteJson = fetchRemoteJson;
945
1080
  exports.fetchTokenList = fetchTokenList;
946
1081
  exports.fetchTokenListFile = fetchTokenListFile;
947
1082
  exports.fetchTokenLists = fetchTokenLists;
@@ -1011,6 +1146,8 @@ exports.llamaLendMarketByVault = llamaLendMarketByVault;
1011
1146
  exports.llamaLendMarkets = llamaLendMarkets;
1012
1147
  exports.llamaLendSupportsDelegation = llamaLendSupportsDelegation;
1013
1148
  exports.llamaLendSupportsLeverage = llamaLendSupportsLeverage;
1149
+ exports.loadCached = loadCached;
1150
+ exports.loadCachedJson = loadCachedJson;
1014
1151
  exports.midnightApiBaseOverride = midnightApiBaseOverride;
1015
1152
  exports.midnightConfig = midnightConfig;
1016
1153
  exports.midnightMarketById = midnightMarketById;
@@ -1041,6 +1178,8 @@ exports.riverLendersByChain = riverLendersByChain;
1041
1178
  exports.riverMarketByIndex = riverMarketByIndex;
1042
1179
  exports.riverMarkets = riverMarkets;
1043
1180
  exports.setMidnightApiBase = setMidnightApiBase;
1181
+ exports.setRemoteCacheGithubToken = setRemoteCacheGithubToken;
1182
+ exports.setRemoteCacheStore = setRemoteCacheStore;
1044
1183
  exports.setTermApiBase = setTermApiBase;
1045
1184
  exports.siloMarkets = siloMarkets;
1046
1185
  exports.siloMarketsV3 = siloMarketsV3;
package/dist/index.mjs CHANGED
@@ -860,12 +860,143 @@ var parseFraxlendPairKey = (lender) => {
860
860
  return { chainId: m[1], pair: m[2].toLowerCase() };
861
861
  };
862
862
 
863
+ // src/remoteCache.ts
864
+ var FRESH_TTL_MS = 5 * 60 * 1e3;
865
+ var REMOTE_CACHE_STORE_TTL_S = 7 * 24 * 60 * 60;
866
+ var STATE_KEY = "__1delta_remote_cache__";
867
+ function getState() {
868
+ const g = globalThis;
869
+ if (!g[STATE_KEY]) g[STATE_KEY] = { memo: /* @__PURE__ */ new Map(), inflight: /* @__PURE__ */ new Map() };
870
+ return g[STATE_KEY];
871
+ }
872
+ function setRemoteCacheStore(next) {
873
+ getState().store = next;
874
+ }
875
+ function setRemoteCacheGithubToken(token) {
876
+ getState().githubToken = token;
877
+ }
878
+ function clearRemoteCache() {
879
+ const state = getState();
880
+ state.memo.clear();
881
+ state.inflight.clear();
882
+ }
883
+ var RAW_HOST = "https://raw.githubusercontent.com/";
884
+ function githubApiMirror(url) {
885
+ if (!url.startsWith(RAW_HOST)) return void 0;
886
+ const [owner, repo, ref, ...path] = url.slice(RAW_HOST.length).split("/");
887
+ if (!owner || !repo || !ref || path.length === 0) return void 0;
888
+ return `https://api.github.com/repos/${owner}/${repo}/contents/${path.join("/")}?ref=${ref}`;
889
+ }
890
+ var RemoteFetchError = class extends Error {
891
+ constructor(message, status) {
892
+ super(message);
893
+ this.status = status;
894
+ this.name = "RemoteFetchError";
895
+ }
896
+ /** 404/410 — re-fetching cannot change the answer. */
897
+ get isMissing() {
898
+ return this.status === 404 || this.status === 410;
899
+ }
900
+ };
901
+ async function fetchRemoteJson(url, label) {
902
+ const res = await fetch(url);
903
+ if (res.ok) return await res.json();
904
+ const mirror = githubApiMirror(url);
905
+ const worthRetrying = res.status === 429 || res.status >= 500;
906
+ if (!mirror || !worthRetrying) {
907
+ throw new RemoteFetchError(`${label} fetch failed: HTTP ${res.status} from ${new URL(url).host}`, res.status);
908
+ }
909
+ const headers = {
910
+ Accept: "application/vnd.github.raw",
911
+ // The GitHub API rejects a request that sends no User-Agent.
912
+ "User-Agent": "1delta-data-sdk"
913
+ };
914
+ const token = getState().githubToken;
915
+ if (token) headers.Authorization = `Bearer ${token}`;
916
+ const viaApi = await fetch(mirror, { headers });
917
+ if (!viaApi.ok) {
918
+ throw new RemoteFetchError(
919
+ `${label} fetch failed: HTTP ${res.status} from raw.githubusercontent.com, HTTP ${viaApi.status} from api.github.com`,
920
+ res.status
921
+ );
922
+ }
923
+ return await viaApi.json();
924
+ }
925
+ var storeKey = (key) => `remote-cache:v1:${key}`;
926
+ async function readStore(key, isValid) {
927
+ const { store } = getState();
928
+ if (!store) return void 0;
929
+ try {
930
+ const raw = await store.get(storeKey(key));
931
+ if (!raw) return void 0;
932
+ const parsed = JSON.parse(raw);
933
+ if (typeof parsed?.at !== "number" || !isValid(parsed.value)) return void 0;
934
+ return parsed;
935
+ } catch {
936
+ return void 0;
937
+ }
938
+ }
939
+ async function writeStore(key, entry) {
940
+ const { store } = getState();
941
+ if (!store) return;
942
+ try {
943
+ await store.put(storeKey(key), JSON.stringify(entry), REMOTE_CACHE_STORE_TTL_S);
944
+ } catch {
945
+ }
946
+ }
947
+ async function loadCached(key, load, isValid) {
948
+ const { memo, inflight } = getState();
949
+ const cached = memo.get(key);
950
+ if (cached && Date.now() - cached.at < FRESH_TTL_MS) return cached.value;
951
+ const pending = inflight.get(key);
952
+ if (pending) return pending;
953
+ const task = (async () => {
954
+ const stored = await readStore(key, isValid);
955
+ if (stored && Date.now() - stored.at < FRESH_TTL_MS) {
956
+ memo.set(key, stored);
957
+ return stored.value;
958
+ }
959
+ try {
960
+ const value = await load();
961
+ const entry = { at: Date.now(), value };
962
+ memo.set(key, entry);
963
+ await writeStore(key, entry);
964
+ return value;
965
+ } catch (error) {
966
+ const stale = memo.get(key) ?? stored;
967
+ if (!stale) throw error;
968
+ memo.set(key, stale);
969
+ return stale.value;
970
+ }
971
+ })().finally(() => {
972
+ inflight.delete(key);
973
+ });
974
+ inflight.set(key, task);
975
+ return task;
976
+ }
977
+ async function loadCachedJson(key, url, isValid, label = key) {
978
+ return loadCached(key, () => fetchRemoteJson(url, label), isValid);
979
+ }
980
+
863
981
  // src/tokens.ts
864
982
  var getListUrl = (chainId) => `https://raw.githubusercontent.com/1delta-DAO/token-lists/main/${chainId}.json`;
983
+ var MAIN_TOKENS_URL = "https://raw.githubusercontent.com/1delta-DAO/token-lists/main/main-tokens.json";
984
+ var isTokenListFile = (value) => !!value?.list && typeof value.list === "object";
985
+ async function loadTokenListFile(chainId) {
986
+ return loadCached(
987
+ `token-list:${chainId}`,
988
+ async () => {
989
+ const json = await fetchRemoteJson(getListUrl(chainId), `Token list for chain ${chainId}`);
990
+ return {
991
+ list: json.list,
992
+ mainTokens: json.mainTokens ?? []
993
+ };
994
+ },
995
+ isTokenListFile
996
+ );
997
+ }
865
998
  async function fetchTokenList(chainId) {
866
- const data = await fetch(getListUrl(chainId));
867
- if (!data.ok) throw new Error(`HTTP error! status: ${data.status}`);
868
- return (await data.json()).list;
999
+ return (await loadTokenListFile(chainId)).list;
869
1000
  }
870
1001
  async function fetchTokenLists(chainIds) {
871
1002
  const promises = chainIds.map(async (chainId) => {
@@ -876,19 +1007,19 @@ async function fetchTokenLists(chainIds) {
876
1007
  return Object.fromEntries(results);
877
1008
  }
878
1009
  async function fetchTokenListFile(chainId) {
879
- const data = await fetch(getListUrl(chainId));
880
- if (!data.ok) throw new Error(`HTTP error! status: ${data.status}`);
881
- const json = await data.json();
882
- return {
883
- list: json.list,
884
- mainTokens: json.mainTokens ?? []
885
- };
1010
+ const file = await loadTokenListFile(chainId);
1011
+ return { list: file.list, mainTokens: file.mainTokens };
886
1012
  }
887
- var MAIN_TOKENS_URL = "https://raw.githubusercontent.com/1delta-DAO/token-lists/main/main-tokens.json";
888
1013
  async function fetchMainTokensMap() {
889
- const data = await fetch(MAIN_TOKENS_URL);
890
- if (!data.ok) return void 0;
891
- return await data.json();
1014
+ try {
1015
+ return await loadCached(
1016
+ "main-tokens",
1017
+ () => fetchRemoteJson(MAIN_TOKENS_URL, "main-tokens"),
1018
+ (value) => !!value && typeof value === "object"
1019
+ );
1020
+ } catch {
1021
+ return void 0;
1022
+ }
892
1023
  }
893
1024
 
894
- export { CURVANCE_MONAD_CONFIG, FRAXLEND_ETHEREUM_CONFIG, GEARBOX_ACCOUNT_COMPRESSOR_V310, RESUPPLY_ETHEREUM_CONFIG, aaveOracles, aaveOraclesConfig, aavePools, aaveReserves, aaveTokens, aaveV4Oracles, aaveV4Peripherals, aaveV4SpokeLenderKey, aaveV4Spokes, aaveWethGateway, chainLogoURI, chains, compoundV2Oracles, compoundV2OraclesConfig, compoundV2Pools, compoundV2Reserves, compoundV2TokenArray, compoundV2Tokens, compoundV3BaseData, compoundV3Bulker, compoundV3OraclesData, compoundV3Pools, compoundV3Reserves, curvanceConfig, curvanceConfigFor, curvanceLendersByChain, curvancePositionManager, curvancePositionManagersFor, dolomiteChains, dolomiteConfigs, dolomiteEmode, dolomiteMarketIdByToken, dssChainData, dssConfigFor, dssDebtJoin, dssDebtToken, dssMarketByIlk, eulerConfigs, eulerVaults, exactlyConfig, exactlyMarketByAddress, exactlyMarketByAsset, exactlyMarkets, exactlyMarketsByChain, fetchMainTokensMap, fetchTokenList, fetchTokenListFile, fetchTokenLists, findAaveV4PositionManager, fluidChains, fluidResolvers, fluidVaultEntries, fluidVaults, frankencoinChainData, frankencoinConfig, frankencoinConfigFor, frankencoinLendersByChain, frankencoinMarketByPosition, frankencoinMarkets, fraxlendConfig, fraxlendConfigFor, fraxlendLendersByChain, fraxlendPairKey, fraxlendPairsFor, gearboxAccountCompressor, gearboxAddressProviderV310, gearboxBotListV3, gearboxChains, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxResolvers, gearboxV3LenderKey, getAaveV4GatewayAddresses, getAaveV4PositionManagers, getAaveV4SpokeAccess, getAaveV4SpokeEntry, getAaveV4SpokePeripherals, getChainEntries, getSiloV2MarketEntry, getSiloV3MarketEntry, initConfig, initializeChainData, initializeLenderData, inverseChainData, inverseConfig, inverseConfigFor, inverseLendersByChain, inverseMarketByAddress, inverseMarkets, isAaveV4OperationRestricted, isListaSmartLpAsset, liquityBranchByIndex, liquityBranchByTroveManager, liquityBranchesByChain, liquityConfig, liquityConfigFor, liquityLendersByChain, liquityMarkets, listaCollateralProvider, listaCollateralProviders, listaNativeProvider, listaSmartLpByCollateral, llamaLendApiBaseUrl, llamaLendChainData, llamaLendConfig, llamaLendConfigFor, llamaLendLenderKey, llamaLendLendersByChain, llamaLendLeverageZap, llamaLendMarketByController, llamaLendMarketByVault, llamaLendMarkets, llamaLendSupportsDelegation, llamaLendSupportsLeverage, midnightApiBaseOverride, midnightConfig, midnightMarketById, midnightMarkets, midnightMarketsByChain, morphoBundler3, morphoOracles, morphoPools, morphoTypeMarkets, morphoTypeOracles, morphoTypeVaults, parseAaveV4SpokeLenderKey, parseFraxlendPairKey, parseGearboxV3LenderKey, parseLlamaLendLenderKey, parseSiloV2LenderKey, parseSiloV3LenderKey, parseTermMaxLenderKey, resolveMidnightApiBase, resolveTermApiBase, resupplyConfig, resupplyConfigFor, resupplyLendersByChain, riverChainData, riverConfig, riverConfigFor, riverLendersByChain, riverMarketByIndex, riverMarkets, setMidnightApiBase, setTermApiBase, siloMarkets, siloMarketsV3, siloPeripherals, siloPeripheralsV3, siloV2LenderKey, siloV3LenderKey, skyChainData, skyConfig, skyConfigFor, skyLendersByChain, skyMarkets, tellerConfig, tellerConfigByChain, tellerPoolByAddress, tellerPools, tellerPoolsByChain, termApiBaseOverride, termConfig, termMarketById, termMarkets, termMarketsByChain, termMaxApiBaseUrl, termMaxChainIds, termMaxConfig, termMaxConfigByChain, termMaxLenderKey, usddChainData, usddConfig, usddConfigFor, usddLendersByChain, usddMarketByIlk, usddMarkets };
1025
+ export { CURVANCE_MONAD_CONFIG, FRAXLEND_ETHEREUM_CONFIG, GEARBOX_ACCOUNT_COMPRESSOR_V310, REMOTE_CACHE_STORE_TTL_S, RESUPPLY_ETHEREUM_CONFIG, RemoteFetchError, aaveOracles, aaveOraclesConfig, aavePools, aaveReserves, aaveTokens, aaveV4Oracles, aaveV4Peripherals, aaveV4SpokeLenderKey, aaveV4Spokes, aaveWethGateway, chainLogoURI, chains, clearRemoteCache, compoundV2Oracles, compoundV2OraclesConfig, compoundV2Pools, compoundV2Reserves, compoundV2TokenArray, compoundV2Tokens, compoundV3BaseData, compoundV3Bulker, compoundV3OraclesData, compoundV3Pools, compoundV3Reserves, curvanceConfig, curvanceConfigFor, curvanceLendersByChain, curvancePositionManager, curvancePositionManagersFor, dolomiteChains, dolomiteConfigs, dolomiteEmode, dolomiteMarketIdByToken, dssChainData, dssConfigFor, dssDebtJoin, dssDebtToken, dssMarketByIlk, eulerConfigs, eulerVaults, exactlyConfig, exactlyMarketByAddress, exactlyMarketByAsset, exactlyMarkets, exactlyMarketsByChain, fetchMainTokensMap, fetchRemoteJson, fetchTokenList, fetchTokenListFile, fetchTokenLists, findAaveV4PositionManager, fluidChains, fluidResolvers, fluidVaultEntries, fluidVaults, frankencoinChainData, frankencoinConfig, frankencoinConfigFor, frankencoinLendersByChain, frankencoinMarketByPosition, frankencoinMarkets, fraxlendConfig, fraxlendConfigFor, fraxlendLendersByChain, fraxlendPairKey, fraxlendPairsFor, gearboxAccountCompressor, gearboxAddressProviderV310, gearboxBotListV3, gearboxChains, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxResolvers, gearboxV3LenderKey, getAaveV4GatewayAddresses, getAaveV4PositionManagers, getAaveV4SpokeAccess, getAaveV4SpokeEntry, getAaveV4SpokePeripherals, getChainEntries, getSiloV2MarketEntry, getSiloV3MarketEntry, initConfig, initializeChainData, initializeLenderData, inverseChainData, inverseConfig, inverseConfigFor, inverseLendersByChain, inverseMarketByAddress, inverseMarkets, isAaveV4OperationRestricted, isListaSmartLpAsset, liquityBranchByIndex, liquityBranchByTroveManager, liquityBranchesByChain, liquityConfig, liquityConfigFor, liquityLendersByChain, liquityMarkets, listaCollateralProvider, listaCollateralProviders, listaNativeProvider, listaSmartLpByCollateral, llamaLendApiBaseUrl, llamaLendChainData, llamaLendConfig, llamaLendConfigFor, llamaLendLenderKey, llamaLendLendersByChain, llamaLendLeverageZap, llamaLendMarketByController, llamaLendMarketByVault, llamaLendMarkets, llamaLendSupportsDelegation, llamaLendSupportsLeverage, loadCached, loadCachedJson, midnightApiBaseOverride, midnightConfig, midnightMarketById, midnightMarkets, midnightMarketsByChain, morphoBundler3, morphoOracles, morphoPools, morphoTypeMarkets, morphoTypeOracles, morphoTypeVaults, parseAaveV4SpokeLenderKey, parseFraxlendPairKey, parseGearboxV3LenderKey, parseLlamaLendLenderKey, parseSiloV2LenderKey, parseSiloV3LenderKey, parseTermMaxLenderKey, resolveMidnightApiBase, resolveTermApiBase, resupplyConfig, resupplyConfigFor, resupplyLendersByChain, riverChainData, riverConfig, riverConfigFor, riverLendersByChain, riverMarketByIndex, riverMarkets, setMidnightApiBase, setRemoteCacheGithubToken, setRemoteCacheStore, setTermApiBase, siloMarkets, siloMarketsV3, siloPeripherals, siloPeripheralsV3, siloV2LenderKey, siloV3LenderKey, skyChainData, skyConfig, skyConfigFor, skyLendersByChain, skyMarkets, tellerConfig, tellerConfigByChain, tellerPoolByAddress, tellerPools, tellerPoolsByChain, termApiBaseOverride, termConfig, termMarketById, termMarkets, termMarketsByChain, termMaxApiBaseUrl, termMaxChainIds, termMaxConfig, termMaxConfigByChain, termMaxLenderKey, usddChainData, usddConfig, usddConfigFor, usddLendersByChain, usddMarketByIlk, usddMarkets };
@@ -16,6 +16,20 @@ export type CompoundV2TokenArrayType = {
16
16
  [chainId: string]: {
17
17
  cToken: string;
18
18
  underlying: string;
19
+ /**
20
+ * Pause state for forks whose Comptroller exposes NO
21
+ * `mintGuardianPaused` / `borrowGuardianPaused` getter (WePiggy is the
22
+ * known case: the setters and the pause guardian exist, the mappings are
23
+ * not public). The generator resolves it off-chain by simulating the
24
+ * Comptroller's own `mintAllowed` / `borrowAllowed` and decoding the
25
+ * revert reason, so the fetcher pays nothing at runtime.
26
+ *
27
+ * ONLY a fallback: wherever the live guardian read succeeds it wins, so
28
+ * these are absent for every fork that can be read directly. Absent =
29
+ * unknown, never "not paused".
30
+ */
31
+ mintPaused?: boolean;
32
+ borrowPaused?: boolean;
19
33
  }[];
20
34
  };
21
35
  };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Cache for the static JSON this SDK reads from GitHub (token lists, the chain
3
+ * registry).
4
+ *
5
+ * raw.githubusercontent.com rate-limits per EGRESS IP, and Cloudflare Workers
6
+ * share theirs — so an uncached fetch per request 429s in bursts. Before this
7
+ * existed that surfaced as a hard `INTERNAL_ERROR` 500 on every route needing a
8
+ * token list, and as a silently EMPTY chain registry (every chain rendered as
9
+ * "Chain 8453") that a 10-minute init cache then pinned in place.
10
+ *
11
+ * These files change on the order of days, so serving a stale copy is strictly
12
+ * better than failing — hence the stale-on-error fallback, which is the part
13
+ * that actually survives an outage.
14
+ */
15
+ /** How long a persisted copy is kept around purely as the stale fallback. */
16
+ export declare const REMOTE_CACHE_STORE_TTL_S: number;
17
+ /**
18
+ * Durable backing store — a Cloudflare KV namespace in the workers, absent
19
+ * everywhere else. Without one the cache is per-process, which still collapses
20
+ * N requests into one upstream fetch but cannot help a cold start; with one, a
21
+ * fresh isolate never touches GitHub at all.
22
+ */
23
+ export interface RemoteCacheStore {
24
+ get(key: string): Promise<string | null>;
25
+ put(key: string, value: string, ttlSeconds: number): Promise<void>;
26
+ }
27
+ /** Installs (or with `undefined`, removes) the durable store. */
28
+ export declare function setRemoteCacheStore(next: RemoteCacheStore | undefined): void;
29
+ /**
30
+ * Optional GitHub token for the API mirror below. Unauthenticated it allows 60
31
+ * requests/hour per IP, which is thin for a shared Worker egress; a token
32
+ * raises that to 5,000. Only ever used on the fallback path.
33
+ */
34
+ export declare function setRemoteCacheGithubToken(token: string | undefined): void;
35
+ /** Drops every cached value. Intended for tests. */
36
+ export declare function clearRemoteCache(): void;
37
+ /**
38
+ * A non-2xx from the remote. Carries the ORIGIN status so a caller can tell a
39
+ * settled answer (404/410 — the file is not published) from a transient one
40
+ * (429/5xx — the same URL may work a second later). Callers that collapse the
41
+ * two re-fetch known-missing files forever, or treat a rate limit as proof that
42
+ * a lender has no config.
43
+ */
44
+ export declare class RemoteFetchError extends Error {
45
+ /** Status from the ORIGIN host, not from the mirror. */
46
+ readonly status: number;
47
+ constructor(message: string,
48
+ /** Status from the ORIGIN host, not from the mirror. */
49
+ status: number);
50
+ /** 404/410 — re-fetching cannot change the answer. */
51
+ get isMissing(): boolean;
52
+ }
53
+ /** Fetches JSON from `url`, retrying via the GitHub API when raw rate-limits. */
54
+ export declare function fetchRemoteJson<T>(url: string, label: string): Promise<T>;
55
+ /**
56
+ * Serves `key` from memory, then the durable store, then `load()` — and on a
57
+ * failed `load()` falls back to whatever stale copy either layer holds, only
58
+ * rethrowing when there is nothing to fall back to.
59
+ *
60
+ * Concurrent callers for the same key share one in-flight load.
61
+ *
62
+ * `isValid` guards the durable layer: a truncated or shape-changed entry is
63
+ * treated as absent rather than served, since a bad token list silently
64
+ * mis-decimals every balance built from it.
65
+ */
66
+ export declare function loadCached<T>(key: string, load: () => Promise<T>, isValid: (value: any) => boolean): Promise<T>;
67
+ /** `loadCached` over a JSON URL, failing on any non-2xx so stale can take over. */
68
+ export declare function loadCachedJson<T>(key: string, url: string, isValid: (value: any) => boolean, label?: string): Promise<T>;
package/dist/tokens.d.ts CHANGED
@@ -13,10 +13,6 @@ export interface TokenListEntry {
13
13
  type TokenList = {
14
14
  [addr: string]: TokenListEntry;
15
15
  };
16
- export declare function fetchTokenList(chainId: string): Promise<TokenList>;
17
- export declare function fetchTokenLists(chainIds: string[]): Promise<{
18
- [chainId: string]: TokenList;
19
- }>;
20
16
  export interface TokenListFileData {
21
17
  list: TokenList;
22
18
  /**
@@ -26,7 +22,18 @@ export interface TokenListFileData {
26
22
  */
27
23
  mainTokens: string[];
28
24
  }
29
- /** Like {@link fetchTokenList} but keeps the `mainTokens` curation. */
25
+ /**
26
+ * NOTE: cached — the returned `list` is a SHARED object. Treat it as read-only;
27
+ * mutating it corrupts the copy every other caller sees.
28
+ */
29
+ export declare function fetchTokenList(chainId: string): Promise<TokenList>;
30
+ export declare function fetchTokenLists(chainIds: string[]): Promise<{
31
+ [chainId: string]: TokenList;
32
+ }>;
33
+ /**
34
+ * Like {@link fetchTokenList} but keeps the `mainTokens` curation. Same
35
+ * read-only caveat on `list`.
36
+ */
30
37
  export declare function fetchTokenListFile(chainId: string): Promise<TokenListFileData>;
31
38
  /**
32
39
  * Aggregated chainId → mainTokens map (one small file for all chains, so
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.0.45",
7
+ "version": "0.0.47",
8
8
  "description": "Hold and initialize lending protocol data across a stack",
9
9
  "files": [
10
10
  "dist"