@fileverse-dev/formulajs 4.4.11-mod-77 → 4.4.11-mod-78

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/lib/esm/index.mjs CHANGED
@@ -13130,6 +13130,7 @@ const UTILITY = {
13130
13130
  };
13131
13131
  const MAX_PAGE_LIMIT = 250;
13132
13132
 
13133
+ // if data block need API key
13133
13134
  const SERVICES_API_KEY = {
13134
13135
  Etherscan: 'Etherscan',
13135
13136
  Coingecko: 'Coingecko',
@@ -13142,27 +13143,6 @@ const SERVICES_API_KEY = {
13142
13143
  Defillama: 'Defillama'
13143
13144
  };
13144
13145
 
13145
- const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
13146
- if(!timestamp || !chain || !apiKey) return
13147
- const chainId = CHAIN_ID_MAP[chain];
13148
- const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime&timestamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
13149
- const res = await fetch(url);
13150
- const json = await res.json();
13151
- return parseInt(json.result);
13152
-
13153
- };
13154
-
13155
- var fromTimestampToBlock = {
13156
- fromTimeStampToBlock
13157
- };
13158
-
13159
- function toTimestamp(dateStr) {
13160
- // Expecting format: "DD/MM/YYYY"
13161
- const [day, month, year] = dateStr.split("/").map(Number);
13162
- const date = new Date(year, month - 1, day);
13163
- return Math.floor(date.getTime() / 1000); // Unix timestamp in seconds
13164
- }
13165
-
13166
13146
  class ValidationError extends Error {
13167
13147
  constructor(message) {
13168
13148
  super(message);
@@ -13207,6 +13187,138 @@ class InvalidApiKeyError extends Error {
13207
13187
  }
13208
13188
  }
13209
13189
 
13190
+ const fileverseProxyUrl = `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`;
13191
+ // Proxy map configuration
13192
+ const PROXY_MAP = {
13193
+ Etherscan: {
13194
+ url: fileverseProxyUrl,
13195
+ removeParams: ['apikey']
13196
+ },
13197
+ Basescan: {
13198
+ url: fileverseProxyUrl,
13199
+ removeParams: ['apikey']
13200
+ },
13201
+ Gnosisscan: {
13202
+ url: fileverseProxyUrl,
13203
+ removeParams: ['apikey']
13204
+ },
13205
+ Coingecko: {
13206
+ url: fileverseProxyUrl,
13207
+ removeParams: ['apikey']
13208
+ },
13209
+ Firefly: {
13210
+ url: fileverseProxyUrl,
13211
+ removeParams: ['apikey']
13212
+ },
13213
+ Neynar: {
13214
+ url: fileverseProxyUrl,
13215
+ removeParams: ['api_key']
13216
+ },
13217
+ Safe: {
13218
+ url: fileverseProxyUrl,
13219
+ removeParams: ['api_key']
13220
+ },
13221
+ Defillama: {
13222
+ url: fileverseProxyUrl,
13223
+ removeParams: ['api_key']
13224
+ },
13225
+ GnosisPay: {
13226
+ url: fileverseProxyUrl,
13227
+ removeParams: ['api_key']
13228
+ },
13229
+ // Add more services as needed. It can be direct url instead of ENV variable
13230
+ // ANOTHER_SERVICE: "https://another-proxy-url.com"
13231
+ };
13232
+
13233
+ /**
13234
+ * Removes specified parameters from a URL
13235
+ * @param {string} url - The original URL
13236
+ * @param {string[]} paramsToRemove - Array of parameter names to remove
13237
+ * @returns {string} URL with specified parameters removed
13238
+ */
13239
+ function removeUrlParams(url, paramsToRemove) {
13240
+ if (!paramsToRemove || paramsToRemove.length === 0) {
13241
+ return url;
13242
+ }
13243
+
13244
+ const urlObj = new URL(url);
13245
+
13246
+ paramsToRemove.forEach(param => {
13247
+ if (urlObj.searchParams.has(param)) {
13248
+ urlObj.searchParams.delete(param);
13249
+ }
13250
+ });
13251
+
13252
+ return urlObj.toString();
13253
+ }
13254
+
13255
+ /**
13256
+ * Handles URL routing through proxy or direct API calls
13257
+ * @param {string} url - The original API URL
13258
+ * @param {string} serviceName - [OPTIONAL] The name of the service (e.g., 'EOA')
13259
+ * @param {object} headers - [OPTIONAL] The name of the service (e.g., 'EOA')
13260
+ * @returns {Object} Object containing URL and HEADERS for the fetch request
13261
+ */
13262
+ function getUrlAndHeaders({ url, serviceName, headers = {} }) {
13263
+ // Check if proxy is enabled in localStorage
13264
+ const apiKeyLS = window.localStorage.getItem(SERVICES_API_KEY[serviceName]);
13265
+ const isProxyModeEnabledValue = apiKeyLS === 'DEFAULT_PROXY_MODE';
13266
+
13267
+ // Check if proxy URL exists for this service
13268
+ const proxyConfig = PROXY_MAP[serviceName];
13269
+
13270
+ if (!proxyConfig && SERVICES_API_KEY[serviceName] && (!apiKeyLS || apiKeyLS === '')) {
13271
+ throw new MissingApiKeyError(SERVICES_API_KEY[serviceName])
13272
+ }
13273
+
13274
+ // If proxy mode is enabled AND proxy URL exists for this service
13275
+ if ((isProxyModeEnabledValue || !apiKeyLS || apiKeyLS === '') && proxyConfig) {
13276
+ // Remove specified parameters from the target URL
13277
+ const cleanedUrl = removeUrlParams(url, proxyConfig.removeParams);
13278
+
13279
+ return {
13280
+ URL: proxyConfig.url,
13281
+ HEADERS: {
13282
+ 'target-url': cleanedUrl,
13283
+ method: 'GET',
13284
+ 'Content-Type': 'application/json'
13285
+ }
13286
+ };
13287
+ }
13288
+
13289
+ return {
13290
+ URL: url,
13291
+ HEADERS: {
13292
+ ...headers,
13293
+ }
13294
+ };
13295
+ }
13296
+
13297
+ const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
13298
+ if (!timestamp || !chain) return
13299
+ const chainId = CHAIN_ID_MAP[chain];
13300
+ const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime&timestamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
13301
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
13302
+ const res = await fetch(finalUrl, {
13303
+ method: 'GET',
13304
+ headers: HEADERS,
13305
+ });
13306
+ const json = await res.json();
13307
+ return parseInt(json.result);
13308
+
13309
+ };
13310
+
13311
+ var fromTimestampToBlock = {
13312
+ fromTimeStampToBlock
13313
+ };
13314
+
13315
+ function toTimestamp(dateStr) {
13316
+ // Expecting format: "DD/MM/YYYY"
13317
+ const [day, month, year] = dateStr.split("/").map(Number);
13318
+ const date = new Date(year, month - 1, day);
13319
+ return Math.floor(date.getTime() / 1000); // Unix timestamp in seconds
13320
+ }
13321
+
13210
13322
  const isAddress = (input) => {
13211
13323
  return (/^0x[a-fA-F0-9]{40}$/.test(input))
13212
13324
  };
@@ -13311,7 +13423,11 @@ async function handleScanRequest({
13311
13423
  }
13312
13424
  url += `&page=${page}&offset=${offset}`;
13313
13425
  }
13314
- const res = await fetch(url);
13426
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({url, serviceName: apiInfo.apiKeyName, headers: {}});
13427
+ const res = await fetch(finalUrl, {
13428
+ method: 'GET',
13429
+ headers: HEADERS,
13430
+ });
13315
13431
  if (!res.ok) {
13316
13432
  throw new NetworkError(apiInfo.apiKeyName, res.status)
13317
13433
  }
@@ -13330,14 +13446,19 @@ async function handleScanRequest({
13330
13446
  }
13331
13447
 
13332
13448
  const fromUsernameToFid = async (username, apiKey) => {
13333
- if(!username) return null
13449
+ if (!username) return null
13334
13450
  const url = `https://api.neynar.com/v2/farcaster/user/search/?q=${username}&limit=5`;
13335
- const res = await fetch(url, {
13336
- headers: {
13451
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
13452
+ url, serviceName: 'Neynar', headers: {
13337
13453
  'x-api-key': apiKey,
13338
13454
  'x-neynar-experimental': 'false'
13339
13455
  }
13340
13456
  });
13457
+
13458
+ const res = await fetch(finalUrl, {
13459
+ method: 'GET',
13460
+ headers: HEADERS,
13461
+ });
13341
13462
  const json = await res.json();
13342
13463
  const users = json.result ? json.result.users : [];
13343
13464
  const user = users.find(user => user.username === username);
@@ -17577,9 +17698,9 @@ const aaveParamsSchema = objectType({
17577
17698
 
17578
17699
  async function FIREFLY() {
17579
17700
  try {
17580
- const [platform, contentType, identifier, start = 0, end = 10] = argsToArray(arguments);
17701
+ const [platform, contentType, identifier, start = 0, end = 10] = argsToArray(arguments);
17581
17702
 
17582
- validateParams(fireflyParamsSchema, {
17703
+ validateParams(fireflyParamsSchema, {
17583
17704
  platform,
17584
17705
  contentType,
17585
17706
  identifier,
@@ -17588,9 +17709,6 @@ validateParams(fireflyParamsSchema, {
17588
17709
  });
17589
17710
 
17590
17711
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Firefly);
17591
- if (!apiKey) {
17592
- throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17593
- }
17594
17712
 
17595
17713
  const url = new URL('https://openapi.firefly.land/v1/fileverse/fetch');
17596
17714
  url.searchParams
@@ -17601,12 +17719,14 @@ validateParams(fireflyParamsSchema, {
17601
17719
  .filter(Boolean)
17602
17720
  .join(',')
17603
17721
  );
17604
- url.searchParams.set('type', fireFlyPlaformType[platform][contentType]);
17605
- url.searchParams.set('start', String(start));
17606
- url.searchParams.set('end', String(end));
17722
+ url.searchParams.set('type', fireFlyPlaformType[platform][contentType]);
17723
+ url.searchParams.set('start', String(start));
17724
+ url.searchParams.set('end', String(end));
17607
17725
 
17608
- const response = await fetch(url.toString(), {
17609
- headers: { 'x-api-key': apiKey }
17726
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17727
+ const response = await fetch(finalUrl, {
17728
+ method: 'GET',
17729
+ headers: HEADERS,
17610
17730
  });
17611
17731
  if (!response.ok) {
17612
17732
  throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
@@ -17648,9 +17768,6 @@ async function LENS() {
17648
17768
  const apiKey = window.localStorage.getItem(
17649
17769
  SERVICES_API_KEY.Firefly
17650
17770
  );
17651
- if (!apiKey) {
17652
- throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17653
- }
17654
17771
 
17655
17772
  const url = new URL(
17656
17773
  'https://openapi.firefly.land/v1/fileverse/fetch'
@@ -17664,15 +17781,18 @@ async function LENS() {
17664
17781
  .join(',')
17665
17782
  );
17666
17783
  const typeMap = {
17667
- posts: 'lensid',
17784
+ posts: 'lensid',
17668
17785
  replies: 'lenspostid',
17669
17786
  };
17670
17787
  url.searchParams.set('type', typeMap[contentType]);
17671
17788
  url.searchParams.set('start', String(start));
17672
- url.searchParams.set('end', String(end));
17789
+ url.searchParams.set('end', String(end));
17790
+
17791
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17673
17792
 
17674
- const response = await fetch(url.toString(), {
17675
- headers: { 'x-api-key': apiKey },
17793
+ const response = await fetch(finalUrl, {
17794
+ method: 'GET',
17795
+ headers: HEADERS,
17676
17796
  });
17677
17797
  if (!response.ok) {
17678
17798
  throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
@@ -17699,7 +17819,7 @@ async function FARCASTER() {
17699
17819
  try {
17700
17820
  const [contentType, identifier, start = 0, end = 10] =
17701
17821
  argsToArray(arguments);
17702
- validateParams(farcasterParamsSchema, {
17822
+ validateParams(farcasterParamsSchema, {
17703
17823
  contentType,
17704
17824
  identifier,
17705
17825
  start,
@@ -17709,9 +17829,6 @@ validateParams(farcasterParamsSchema, {
17709
17829
  const apiKey = window.localStorage.getItem(
17710
17830
  SERVICES_API_KEY.Firefly
17711
17831
  );
17712
- if (!apiKey) {
17713
- throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17714
- }
17715
17832
 
17716
17833
  const url = new URL(
17717
17834
  'https://openapi.firefly.land/v1/fileverse/fetch'
@@ -17725,16 +17842,19 @@ validateParams(farcasterParamsSchema, {
17725
17842
  .join(',')
17726
17843
  );
17727
17844
  const typeMap = {
17728
- posts: 'farcasterid',
17729
- replies: 'farcasterpostid',
17730
- channels: 'farcasterchannels',
17731
- };
17845
+ posts: 'farcasterid',
17846
+ replies: 'farcasterpostid',
17847
+ channels: 'farcasterchannels',
17848
+ };
17732
17849
  url.searchParams.set('type', typeMap[contentType]);
17733
17850
  url.searchParams.set('start', String(start));
17734
- url.searchParams.set('end', String(end));
17851
+ url.searchParams.set('end', String(end));
17735
17852
 
17736
- const response = await fetch(url.toString(), {
17737
- headers: { 'x-api-key': apiKey },
17853
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17854
+
17855
+ const response = await fetch(finalUrl, {
17856
+ method: 'GET',
17857
+ headers: HEADERS,
17738
17858
  });
17739
17859
  if (!response.ok) {
17740
17860
  throw new NetworkError(
@@ -17836,12 +17956,11 @@ async function BLOCKSCOUT() {
17836
17956
  }
17837
17957
 
17838
17958
  async function BASE() {
17839
- try {
17959
+ try {
17840
17960
  const [type, address, startDate, endDate, page, limit] = argsToArray(arguments);
17841
- validateParams(baseParamsSchema, { type, address, startDate, endDate, page, limit });
17961
+ validateParams(baseParamsSchema, { type, address, startDate, endDate, page, limit });
17842
17962
  const API_KEY = window.localStorage.getItem(SERVICES_API_KEY.Basescan);
17843
- if (!API_KEY) throw new MissingApiKeyError(SERVICES_API_KEY.Basescan)
17844
-
17963
+
17845
17964
  return await handleScanRequest({
17846
17965
  type,
17847
17966
  address,
@@ -17854,9 +17973,9 @@ try {
17854
17973
  chainId: CHAIN_ID_MAP.base,
17855
17974
  network: 'base'
17856
17975
  })
17857
- } catch (error) {
17858
- return errorMessageHandler(error, 'BASE')
17859
- }
17976
+ } catch (error) {
17977
+ return errorMessageHandler(error, 'BASE')
17978
+ }
17860
17979
  }
17861
17980
  async function GNOSIS() {
17862
17981
  try {
@@ -17876,7 +17995,6 @@ async function GNOSIS() {
17876
17995
  const apiKey = window.localStorage.getItem(
17877
17996
  SERVICES_API_KEY.Gnosisscan
17878
17997
  );
17879
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Gnosisscan)
17880
17998
 
17881
17999
  return await handleScanRequest({
17882
18000
  type,
@@ -17897,27 +18015,33 @@ async function GNOSIS() {
17897
18015
 
17898
18016
  async function NEYNAR() {
17899
18017
  try {
17900
- const neynarParamsSchema = objectType({
17901
- username: stringType().nonempty()
17902
- });
18018
+ const neynarParamsSchema = objectType({
18019
+ username: stringType().nonempty()
18020
+ });
17903
18021
 
17904
18022
  const [username] = argsToArray(arguments);
17905
18023
 
17906
18024
  validateParams(neynarParamsSchema, { username });
17907
18025
 
17908
18026
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Neynar);
17909
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Neynar)
17910
18027
 
17911
18028
  const fid = await fromUsernameToFid$1.fromUsernameToFid(username, apiKey);
17912
18029
  if (!fid) throw new ValidationError(`Invalid username: ${username}`)
17913
18030
 
17914
18031
  const url = `https://api.neynar.com/v2/farcaster/followers?fid=${fid}`;
17915
18032
 
17916
- const response = await fetch(url, {
17917
- headers: {
17918
- 'x-api-key': apiKey,
17919
- 'x-neynar-experimental': 'false',
17920
- }
18033
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
18034
+ url: url.toString(), serviceName: 'Neynar',
18035
+ headers: {
18036
+ 'x-api-key': apiKey,
18037
+ 'x-neynar-experimental': 'false'
18038
+ }
18039
+
18040
+ });
18041
+
18042
+ const response = await fetch(finalUrl, {
18043
+ method: 'GET',
18044
+ headers: HEADERS,
17921
18045
  });
17922
18046
  if (!response.ok) {
17923
18047
  throw new NetworkError(SERVICES_API_KEY.Neynar, response.status)
@@ -18012,7 +18136,6 @@ async function ETHERSCAN() {
18012
18136
  if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
18013
18137
 
18014
18138
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
18015
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Etherscan)
18016
18139
 
18017
18140
  return await handleScanRequest({
18018
18141
  type,
@@ -18038,7 +18161,6 @@ async function COINGECKO() {
18038
18161
  validateParams(coingeckoParamsSchema, { category, param1, param2 });
18039
18162
 
18040
18163
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Coingecko);
18041
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Coingecko)
18042
18164
 
18043
18165
  const headers = {
18044
18166
  accept: 'application/json',
@@ -18052,27 +18174,28 @@ async function COINGECKO() {
18052
18174
  break
18053
18175
  }
18054
18176
  case 'market': {
18055
- const map = { all:'', base:'base-ecosystem', meme:'meme-token', aiagents:'ai-agents', bitcoin:'bitcoin-ecosystem', ethereum:'ethereum-ecosystem', hyperliquid:'hyperliquid-ecosystem', pump:'pump-ecosystem', solana:'solana-ecosystem' };
18177
+ const map = { all: '', base: 'base-ecosystem', meme: 'meme-token', aiagents: 'ai-agents', bitcoin: 'bitcoin-ecosystem', ethereum: 'ethereum-ecosystem', hyperliquid: 'hyperliquid-ecosystem', pump: 'pump-ecosystem', solana: 'solana-ecosystem' };
18056
18178
  const _category = map[param1] || '';
18057
18179
  const trend = param2 ? `&price_change_percentage=${param2}` : '';
18058
- url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category?`&category=${_category}`:''}${trend}`;
18180
+ url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category ? `&category=${_category}` : ''}${trend}`;
18059
18181
  break
18060
18182
  }
18061
18183
  case 'stablecoins': {
18062
- const _category = param1==='all'? 'stablecoins' : param1;
18184
+ const _category = param1 === 'all' ? 'stablecoins' : param1;
18063
18185
  const trend = param2 ? `&price_change_percentage=${param2}` : '';
18064
18186
  url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&category=${_category}&order=market_cap_desc&page=1&per_page=100${trend}`;
18065
18187
  break
18066
18188
  }
18067
18189
  case 'derivatives': {
18068
- url = (!param1 || param1==='all')
18190
+ url = (!param1 || param1 === 'all')
18069
18191
  ? 'https://api.coingecko.com/api/v3/derivatives'
18070
18192
  : `https://api.coingecko.com/api/v3/derivatives/exchanges/${param1}?include_tickers=all`;
18071
18193
  break
18072
18194
  }
18073
18195
  }
18196
+ const {URL: finalUrl, HEADERS} = getUrlAndHeaders({url, serviceName: 'Coingecko', headers});
18074
18197
 
18075
- const res = await fetch(url, { headers });
18198
+ const res = await fetch(finalUrl, { headers: HEADERS });
18076
18199
  const json = await res.json();
18077
18200
  if (!res.ok) {
18078
18201
  const msg = json?.status?.error_message || '';
@@ -18080,17 +18203,17 @@ async function COINGECKO() {
18080
18203
  throw new NetworkError(SERVICES_API_KEY.Coingecko, res.status)
18081
18204
  }
18082
18205
 
18083
- if (category==='price') {
18206
+ if (category === 'price') {
18084
18207
  const out = {};
18085
18208
  for (const [token, prices] of Object.entries(json))
18086
- for (const [cur,val] of Object.entries(prices))
18087
- out[`${token.charAt(0).toUpperCase()+token.slice(1)}_${cur.toUpperCase()}`]=val;
18209
+ for (const [cur, val] of Object.entries(prices))
18210
+ out[`${token.charAt(0).toUpperCase() + token.slice(1)}_${cur.toUpperCase()}`] = val;
18088
18211
  return [out]
18089
18212
  }
18090
18213
 
18091
18214
  const data = Array.isArray(json) ? json : [json];
18092
- return data.map(item=>{
18093
- const flat={};
18215
+ return data.map(item => {
18216
+ const flat = {};
18094
18217
  for (const [key, value] of Object.entries(item)) {
18095
18218
  if (typeof value !== 'object' || value === null) {
18096
18219
  flat[key] = value;
@@ -18098,8 +18221,8 @@ async function COINGECKO() {
18098
18221
  }
18099
18222
  return flat
18100
18223
  })
18101
- } catch(err) {
18102
- return errorMessageHandler(err,'COINGECKO')
18224
+ } catch (err) {
18225
+ return errorMessageHandler(err, 'COINGECKO')
18103
18226
  }
18104
18227
  }
18105
18228
 
@@ -18110,10 +18233,9 @@ async function EOA() {
18110
18233
  validateParams(eoaParamsSchema, { addresses, category, chains, startTime, endTime, page, offset });
18111
18234
 
18112
18235
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
18113
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Etherscan)
18114
18236
 
18115
- const INPUTS = addresses.split(',').map(s=>s.trim()).filter(Boolean);
18116
- const CHAINS = chains.split(',').map(s=>s.trim()).filter(Boolean);
18237
+ const INPUTS = addresses.split(',').map(s => s.trim()).filter(Boolean);
18238
+ const CHAINS = chains.split(',').map(s => s.trim()).filter(Boolean);
18117
18239
 
18118
18240
  const ADDRESS_MAP = {};
18119
18241
  for (const inp of INPUTS) {
@@ -18128,7 +18250,11 @@ async function EOA() {
18128
18250
  const out = [];
18129
18251
 
18130
18252
  async function fetchJSON(url) {
18131
- const res = await fetch(url);
18253
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
18254
+ const res = await fetch(finalUrl, {
18255
+ method: 'GET',
18256
+ headers: HEADERS,
18257
+ });
18132
18258
  if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Etherscan, res.status)
18133
18259
  const json = await res.json();
18134
18260
 
@@ -18146,15 +18272,15 @@ async function EOA() {
18146
18272
 
18147
18273
  if (category === 'balance') {
18148
18274
  // chunk 20
18149
- for (let i=0; i<ADDRS.length; i+=20) {
18150
- const slice = ADDRS.slice(i,i+20).join(',');
18275
+ for (let i = 0; i < ADDRS.length; i += 20) {
18276
+ const slice = ADDRS.slice(i, i + 20).join(',');
18151
18277
  const url =
18152
- `https://api.etherscan.io/v2/api?chainid=${chainId}`+
18153
- `&module=account&action=addresstokenbalance&address=${slice}`+
18278
+ `https://api.etherscan.io/v2/api?chainid=${chainId}` +
18279
+ `&module=account&action=addresstokenbalance&address=${slice}` +
18154
18280
  `&page=${page}&offset=${offset}&apikey=${apiKey}`;
18155
18281
  const data = await fetchJSON(url);
18156
18282
  if (!Array.isArray(data)) return data
18157
- data.forEach((item, idx) => out.push({ chain, address: ADDRS[i+idx], name: ADDRESS_MAP[ADDRS[i+idx]], ...item }));
18283
+ data.forEach((item, idx) => out.push({ chain, address: ADDRS[i + idx], name: ADDRESS_MAP[ADDRS[i + idx]], ...item }));
18158
18284
  }
18159
18285
  } else {
18160
18286
  // txns
@@ -18164,9 +18290,9 @@ async function EOA() {
18164
18290
  if (!eb) throw new ValidationError(`Invalid endTime: ${endTime}`)
18165
18291
  for (const addr of ADDRS) {
18166
18292
  const url =
18167
- `https://api.etherscan.io/v2/api?chainid=${chainId}`+
18168
- `&module=account&action=tokentx&address=${addr}`+
18169
- `&startblock=${sb}&endblock=${eb}`+
18293
+ `https://api.etherscan.io/v2/api?chainid=${chainId}` +
18294
+ `&module=account&action=tokentx&address=${addr}` +
18295
+ `&startblock=${sb}&endblock=${eb}` +
18170
18296
  `&page=${page}&offset=${offset}&sort=asc&apikey=${apiKey}`;
18171
18297
  const data = await fetchJSON(url);
18172
18298
  if (!Array.isArray(data)) return data
@@ -18195,7 +18321,6 @@ async function SAFE() {
18195
18321
  validateParams(safeParamsSchema, { address, utility, chain, limit, offset });
18196
18322
 
18197
18323
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Safe);
18198
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Safe)
18199
18324
 
18200
18325
  const chainId = SAFE_CHAIN_MAP[chain];
18201
18326
  if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
@@ -18208,8 +18333,8 @@ async function SAFE() {
18208
18333
 
18209
18334
  const url = `https://api.safe.global/tx-service/${chainId}/api/v2/safes/${resolved}/multisig-transactions?limit=${limit}&offset=${offset}`;
18210
18335
 
18211
-
18212
- const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
18336
+ const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: { Authorization: `Bearer ${apiKey}` } });
18337
+ const res = await fetch(finalUrl, { headers: HEADERS });
18213
18338
  if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Safe, res.status)
18214
18339
  const json = await res.json();
18215
18340
 
@@ -18230,7 +18355,6 @@ async function DEFILLAMA() {
18230
18355
  const [category] = argsToArray(arguments);
18231
18356
  validateParams(defillamaParamsSchema, { category });
18232
18357
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Defillama);
18233
- if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Defillama)
18234
18358
  const url = CATEGORY_URLS[category];
18235
18359
  if (!url) throw new ValidationError(`Invalid category: ${category}`)
18236
18360
  const res = await fetch(url);
@@ -18239,20 +18363,20 @@ async function DEFILLAMA() {
18239
18363
 
18240
18364
  switch (category) {
18241
18365
  case 'protocols':
18242
- json = Array.isArray(json) ? json.slice(0,500) : [];
18366
+ json = Array.isArray(json) ? json.slice(0, 500) : [];
18243
18367
  break
18244
18368
  case 'yields':
18245
- json = Array.isArray(json.data) ? json.data.slice(0,500) : [];
18369
+ json = Array.isArray(json.data) ? json.data.slice(0, 500) : [];
18246
18370
  break
18247
18371
  case 'dex':
18248
18372
  case 'fees':
18249
- json = Array.isArray(json.protocols) ? json.protocols.slice(0,500) : [];
18373
+ json = Array.isArray(json.protocols) ? json.protocols.slice(0, 500) : [];
18250
18374
  break
18251
18375
  }
18252
18376
 
18253
18377
  return (Array.isArray(json) ? json : [json]).map(item => {
18254
18378
  const out = {};
18255
- for (const [k,v] of Object.entries(item)) {
18379
+ for (const [k, v] of Object.entries(item)) {
18256
18380
  if (v === null || typeof v !== 'object') out[k] = v;
18257
18381
  }
18258
18382
  return out
@@ -18288,7 +18412,7 @@ async function UNISWAP() {
18288
18412
  // flatten nested
18289
18413
  return json.map(item => {
18290
18414
  const flat = {};
18291
- Object.entries(item).forEach(([k,v]) => {
18415
+ Object.entries(item).forEach(([k, v]) => {
18292
18416
  if (v === null || typeof v !== 'object') flat[k] = v;
18293
18417
  });
18294
18418
  return flat
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fileverse-dev/formulajs",
3
- "version": "4.4.11-mod-77",
3
+ "version": "4.4.11-mod-78",
4
4
  "description": "JavaScript implementation of most Microsoft Excel formula functions",
5
5
  "author": "Formulajs",
6
6
  "publishConfig": {