@defillama/sdk 5.0.240 → 5.0.244

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.
Files changed (133) hide show
  1. package/build/Balances.d.ts +139 -0
  2. package/build/Balances.js +363 -0
  3. package/build/ChainApi.d.ts +142 -0
  4. package/build/ChainApi.js +310 -0
  5. package/build/abi/abi2.d.ts +5 -0
  6. package/build/abi/abi2.js +215 -0
  7. package/build/abi/cachedABIs.d.ts +4 -0
  8. package/build/abi/cachedABIs.js +8 -0
  9. package/build/abi/convertResults.d.ts +5 -0
  10. package/build/abi/convertResults.js +60 -0
  11. package/build/abi/index.d.ts +31 -0
  12. package/build/abi/index.js +327 -0
  13. package/build/abi/multicall.d.ts +23 -0
  14. package/build/abi/multicall.js +383 -0
  15. package/build/abi/multicall3.d.ts +7 -0
  16. package/build/abi/multicall3.js +405 -0
  17. package/build/abi/rpcCall.d.ts +4 -0
  18. package/build/abi/rpcCall.js +62 -0
  19. package/build/abi/tron.d.ts +33 -0
  20. package/build/abi/tron.js +118 -0
  21. package/build/api.d.ts +10 -0
  22. package/build/api.js +45 -0
  23. package/build/api2.d.ts +5 -0
  24. package/build/api2.js +41 -0
  25. package/build/chains/algorand.d.ts +277 -0
  26. package/build/chains/algorand.js +618 -0
  27. package/build/chains/aptos.d.ts +269 -0
  28. package/build/chains/aptos.js +700 -0
  29. package/build/chains/cardano.d.ts +242 -0
  30. package/build/chains/cardano.js +407 -0
  31. package/build/chains/cosmos.d.ts +252 -0
  32. package/build/chains/cosmos.js +623 -0
  33. package/build/chains/icp.d.ts +235 -0
  34. package/build/chains/icp.js +1040 -0
  35. package/build/chains/index.d.ts +23 -0
  36. package/build/chains/index.js +59 -0
  37. package/build/chains/near.d.ts +192 -0
  38. package/build/chains/near.js +446 -0
  39. package/build/chains/rpc.d.ts +125 -0
  40. package/build/chains/rpc.js +332 -0
  41. package/build/chains/starknet.d.ts +205 -0
  42. package/build/chains/starknet.js +886 -0
  43. package/build/chains/stellar.d.ts +410 -0
  44. package/build/chains/stellar.js +1082 -0
  45. package/build/chains/substrate.d.ts +333 -0
  46. package/build/chains/substrate.js +1042 -0
  47. package/build/chains/sui.d.ts +392 -0
  48. package/build/chains/sui.js +1213 -0
  49. package/build/chains/svm.d.ts +340 -0
  50. package/build/chains/svm.js +764 -0
  51. package/build/chains/tezos.d.ts +225 -0
  52. package/build/chains/tezos.js +412 -0
  53. package/build/chains/ton.d.ts +353 -0
  54. package/build/chains/ton.js +788 -0
  55. package/build/chains/tron.d.ts +45 -0
  56. package/build/chains/tron.js +110 -0
  57. package/build/chains/utxo.d.ts +210 -0
  58. package/build/chains/utxo.js +678 -0
  59. package/build/chains/xrpl.d.ts +179 -0
  60. package/build/chains/xrpl.js +467 -0
  61. package/build/computeTVL/blocks.d.ts +1 -0
  62. package/build/computeTVL/blocks.js +12 -0
  63. package/build/computeTVL/humanizeNumber.d.ts +1 -0
  64. package/build/computeTVL/humanizeNumber.js +19 -0
  65. package/build/erc20/index.d.ts +31 -0
  66. package/build/erc20/index.js +56 -0
  67. package/build/eth/index.d.ts +22 -0
  68. package/build/eth/index.js +118 -0
  69. package/build/general.d.ts +5 -0
  70. package/build/general.js +20 -0
  71. package/build/generalUtil.d.ts +8 -0
  72. package/build/generalUtil.js +73 -0
  73. package/build/index.d.ts +33 -0
  74. package/build/index.js +75 -0
  75. package/build/providers.json +1 -0
  76. package/build/types.d.ts +76 -0
  77. package/build/types.js +2 -0
  78. package/build/util/LlamaProvider.d.ts +46 -0
  79. package/build/util/LlamaProvider.js +343 -0
  80. package/build/util/blocks.d.ts +36 -0
  81. package/build/util/blocks.js +500 -0
  82. package/build/util/cache.d.ts +45 -0
  83. package/build/util/cache.js +309 -0
  84. package/build/util/callStats.d.ts +74 -0
  85. package/build/util/callStats.js +385 -0
  86. package/build/util/chainUtils/data.json +1459 -0
  87. package/build/util/chainUtils/index.d.ts +11 -0
  88. package/build/util/chainUtils/index.js +136 -0
  89. package/build/util/coins.d.ts +19 -0
  90. package/build/util/coins.js +124 -0
  91. package/build/util/common.d.ts +34 -0
  92. package/build/util/common.js +376 -0
  93. package/build/util/computeTVL.d.ts +19 -0
  94. package/build/util/computeTVL.js +102 -0
  95. package/build/util/cosmos.d.ts +1 -0
  96. package/build/util/cosmos.js +8 -0
  97. package/build/util/debugLog.d.ts +4 -0
  98. package/build/util/debugLog.js +18 -0
  99. package/build/util/discord.d.ts +1 -0
  100. package/build/util/discord.js +33 -0
  101. package/build/util/elastic.d.ts +43 -0
  102. package/build/util/elastic.js +113 -0
  103. package/build/util/env.d.ts +20 -0
  104. package/build/util/env.js +176 -0
  105. package/build/util/graph.d.ts +8 -0
  106. package/build/util/graph.js +50 -0
  107. package/build/util/index.d.ts +32 -0
  108. package/build/util/index.js +227 -0
  109. package/build/util/indexer.compatibility.d.ts +6 -0
  110. package/build/util/indexer.compatibility.js +64 -0
  111. package/build/util/indexer.d.ts +92 -0
  112. package/build/util/indexer.js +854 -0
  113. package/build/util/indexerSql.d.ts +9 -0
  114. package/build/util/indexerSql.js +102 -0
  115. package/build/util/internal-cache.d.ts +11 -0
  116. package/build/util/internal-cache.js +77 -0
  117. package/build/util/logs.d.ts +58 -0
  118. package/build/util/logs.decode.shared.d.ts +8 -0
  119. package/build/util/logs.decode.shared.js +289 -0
  120. package/build/util/logs.js +432 -0
  121. package/build/util/promisePool.d.ts +8 -0
  122. package/build/util/promisePool.js +31 -0
  123. package/build/util/r2.d.ts +4 -0
  124. package/build/util/r2.js +52 -0
  125. package/build/util/removeRedundantRPCs.d.ts +1 -0
  126. package/build/util/removeRedundantRPCs.js +49 -0
  127. package/build/util/transactions.d.ts +35 -0
  128. package/build/util/transactions.js +22 -0
  129. package/build/util/updateChainLabels.d.ts +1 -0
  130. package/build/util/updateChainLabels.js +5 -0
  131. package/build/util/updateProviderList.d.ts +1 -0
  132. package/build/util/updateProviderList.js +275 -0
  133. package/package.json +3 -2
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ var _a;
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DEFAULT_MIN_GET_LOGS = exports.DEFAULT_MIN_CALLS = exports.ES_INDEX = void 0;
8
+ exports.registerEndpoints = registerEndpoints;
9
+ exports.resolveChain = resolveChain;
10
+ exports.ignoreHost = ignoreHost;
11
+ exports.recordMethod = recordMethod;
12
+ exports.install = install;
13
+ exports.getCurrent = getCurrent;
14
+ exports.snapshot = snapshot;
15
+ exports.mergeSnapshots = mergeSnapshots;
16
+ exports.run = run;
17
+ exports.getMinCalls = getMinCalls;
18
+ exports.buildDocs = buildDocs;
19
+ exports.report = report;
20
+ /**
21
+ * Per-run counters for every outbound HTTP request a process makes, attributed to a chain
22
+ * and to the adapter run that made them, and flushed to Elasticsearch when the run ends.
23
+ *
24
+ * How it works
25
+ * - `install()` wraps `http.request` / `http.get` / `https.request` / `https.get` and subscribes to
26
+ * the `undici:request:create` diagnostics channel (global `fetch`). That catches axios, ethers,
27
+ * @solana/web3.js, graphql-request, raw fetch... without touching any call site.
28
+ * - The SDK registers the RPC urls it resolves for a chain (`registerEndpoints`, called from
29
+ * LlamaProvider and the `chains/*` endpoint resolvers). A request whose url starts with a
30
+ * registered endpoint is counted against that chain, everything else against its host only.
31
+ * - `run(meta, fn)` executes `fn` inside an AsyncLocalStorage context, so concurrent adapter runs
32
+ * in one process (the server's pooled children) each get their own counters.
33
+ *
34
+ * All state lives on `globalThis` under a well-known symbol: when two copies of the SDK are loaded
35
+ * (server's node_modules + the adapters repo's node_modules) they share one hook, one endpoint
36
+ * registry and one context, and nothing is counted twice.
37
+ */
38
+ const async_hooks_1 = require("async_hooks");
39
+ const http_1 = __importDefault(require("http"));
40
+ const https_1 = __importDefault(require("https"));
41
+ const diagnostics_channel_1 = __importDefault(require("diagnostics_channel"));
42
+ const elastic_1 = require("./elastic");
43
+ const debugLog_1 = require("./debugLog");
44
+ const env_1 = require("./env");
45
+ exports.ES_INDEX = 'adapter-call-stats';
46
+ exports.DEFAULT_MIN_CALLS = 50;
47
+ /** a chain bucket is also kept when it has at least this many getLogs requests, however few calls it made */
48
+ exports.DEFAULT_MIN_GET_LOGS = 10;
49
+ const STATE_KEY = Symbol.for('@defillama/sdk/callStats');
50
+ function newStats(meta) {
51
+ return { meta, startTime: Date.now(), total: 0, byChain: {}, byHost: {}, unattributed: 0, byMethod: {} };
52
+ }
53
+ const shared = (_a = globalThis[STATE_KEY]) !== null && _a !== void 0 ? _a : (globalThis[STATE_KEY] = {
54
+ als: new async_hooks_1.AsyncLocalStorage(),
55
+ installed: false,
56
+ endpoints: new Map(),
57
+ global: newStats({ application: 'global', name: '-' }),
58
+ ignoredHosts: new Set(),
59
+ registered: new Set(),
60
+ });
61
+ // ---------------------------------------------------------------------------
62
+ // endpoint registry
63
+ // ---------------------------------------------------------------------------
64
+ function parseUrl(url) {
65
+ try {
66
+ const u = new URL(url);
67
+ if (u.protocol !== 'http:' && u.protocol !== 'https:')
68
+ return;
69
+ return { host: u.host.toLowerCase(), path: u.pathname.replace(/\/+$/, '') };
70
+ }
71
+ catch {
72
+ return;
73
+ }
74
+ }
75
+ /**
76
+ * Remember that `endpoints` serve `chain`, so requests to them are counted against that chain.
77
+ * Called by the SDK wherever it resolves rpc urls; adapters can call it for endpoints they manage themselves.
78
+ */
79
+ function registerEndpoints(chain, endpoints) {
80
+ if (!chain || !endpoints)
81
+ return;
82
+ chain = chain.toLowerCase();
83
+ // callers pass the same list on every request: skip the url parsing after the first time
84
+ const key = chain + '|' + (Array.isArray(endpoints) ? endpoints.join(',') : endpoints);
85
+ if (shared.registered.has(key))
86
+ return;
87
+ shared.registered.add(key);
88
+ const list = Array.isArray(endpoints) ? endpoints : endpoints.split(',');
89
+ for (const raw of list) {
90
+ const parsed = parseUrl(String(raw).trim());
91
+ if (!parsed)
92
+ continue;
93
+ let entries = shared.endpoints.get(parsed.host);
94
+ if (!entries) {
95
+ entries = [];
96
+ shared.endpoints.set(parsed.host, entries);
97
+ }
98
+ if (entries.some(e => e.path === parsed.path && e.chain === chain))
99
+ continue;
100
+ entries.push({ path: parsed.path, chain });
101
+ entries.sort((a, b) => b.path.length - a.path.length);
102
+ }
103
+ }
104
+ /** Chain a url is counted against, or undefined when it matches no registered endpoint. */
105
+ function resolveChain(url) {
106
+ const parsed = parseUrl(url);
107
+ if (!parsed)
108
+ return;
109
+ const entries = shared.endpoints.get(parsed.host);
110
+ if (!entries)
111
+ return;
112
+ for (const entry of entries) {
113
+ if (!entry.path || parsed.path === entry.path || parsed.path.startsWith(entry.path + '/'))
114
+ return entry.chain;
115
+ }
116
+ }
117
+ /** Requests to these hosts are not counted (eg. the elasticsearch cluster the stats are written to). */
118
+ function ignoreHost(url) {
119
+ const parsed = parseUrl(url);
120
+ if (parsed)
121
+ shared.ignoredHosts.add(parsed.host);
122
+ }
123
+ // ---------------------------------------------------------------------------
124
+ // recording
125
+ // ---------------------------------------------------------------------------
126
+ function record(url) {
127
+ var _a, _b, _c;
128
+ const parsed = parseUrl(url);
129
+ if (!parsed || shared.ignoredHosts.has(parsed.host))
130
+ return;
131
+ const stats = (_a = shared.als.getStore()) !== null && _a !== void 0 ? _a : shared.global;
132
+ stats.total++;
133
+ stats.byHost[parsed.host] = ((_b = stats.byHost[parsed.host]) !== null && _b !== void 0 ? _b : 0) + 1;
134
+ const chain = resolveChain(url);
135
+ if (chain)
136
+ stats.byChain[chain] = ((_c = stats.byChain[chain]) !== null && _c !== void 0 ? _c : 0) + 1;
137
+ else
138
+ stats.unattributed++;
139
+ }
140
+ /**
141
+ * Count a logical rpc request (one attempt, so retries count) against `method` and `chain` in the current run.
142
+ * The http layer already counts the request itself; this adds the method breakdown (getLogs being the one that matters).
143
+ */
144
+ function recordMethod(method, chain = 'unknown') {
145
+ var _a, _b, _c;
146
+ const stats = (_a = shared.als.getStore()) !== null && _a !== void 0 ? _a : shared.global;
147
+ const byChain = (_b = stats.byMethod[method]) !== null && _b !== void 0 ? _b : (stats.byMethod[method] = {});
148
+ chain = chain.toLowerCase();
149
+ byChain[chain] = ((_c = byChain[chain]) !== null && _c !== void 0 ? _c : 0) + 1;
150
+ }
151
+ function getLogsCount(stats, chain) {
152
+ var _a, _b, _c;
153
+ const byChain = (_b = (_a = stats.byMethod) === null || _a === void 0 ? void 0 : _a.getLogs) !== null && _b !== void 0 ? _b : {};
154
+ if (chain)
155
+ return (_c = byChain[chain]) !== null && _c !== void 0 ? _c : 0;
156
+ return Object.values(byChain).reduce((a, b) => a + b, 0);
157
+ }
158
+ /** method -> requests across chains */
159
+ function methodTotals(stats) {
160
+ var _a;
161
+ const out = {};
162
+ for (const [method, byChain] of Object.entries((_a = stats.byMethod) !== null && _a !== void 0 ? _a : {}))
163
+ out[method] = Object.values(byChain).reduce((a, b) => a + b, 0);
164
+ return out;
165
+ }
166
+ /** method -> requests for one chain (only methods the chain used) */
167
+ function methodsForChain(stats, chain) {
168
+ var _a;
169
+ const out = {};
170
+ for (const [method, byChain] of Object.entries((_a = stats.byMethod) !== null && _a !== void 0 ? _a : {}))
171
+ if (byChain[chain])
172
+ out[method] = byChain[chain];
173
+ return out;
174
+ }
175
+ function urlFromRequestArgs(args, defaultProtocol) {
176
+ let url;
177
+ let options;
178
+ if (typeof args[0] === 'string') {
179
+ url = args[0];
180
+ if (args[1] && typeof args[1] === 'object')
181
+ options = args[1];
182
+ }
183
+ else if (args[0] instanceof URL) {
184
+ url = args[0].href;
185
+ if (args[1] && typeof args[1] === 'object')
186
+ options = args[1];
187
+ }
188
+ else if (args[0] && typeof args[0] === 'object') {
189
+ options = args[0];
190
+ }
191
+ if (url && (!options || (!options.hostname && !options.host && !options.path)))
192
+ return url;
193
+ if (!options)
194
+ return url;
195
+ // options override the url (same precedence as node)
196
+ const base = url ? new URL(url) : undefined;
197
+ const protocol = options.protocol || (base === null || base === void 0 ? void 0 : base.protocol) || defaultProtocol;
198
+ const host = options.hostname || options.host || (base === null || base === void 0 ? void 0 : base.hostname) || 'localhost';
199
+ const port = options.port ? `:${options.port}` : (options.hostname || !options.host) && (base === null || base === void 0 ? void 0 : base.port) ? `:${base.port}` : '';
200
+ const path = options.path || (base ? base.pathname + base.search : '/');
201
+ return `${protocol}//${host}${host.includes(':') ? '' : port}${path}`;
202
+ }
203
+ function wrap(mod, name, defaultProtocol) {
204
+ const original = mod[name];
205
+ if (typeof original !== 'function')
206
+ return;
207
+ const patched = function (...args) {
208
+ try {
209
+ const url = urlFromRequestArgs(args, defaultProtocol);
210
+ if (url)
211
+ record(url);
212
+ }
213
+ catch { /* never break the request */ }
214
+ return original.apply(this, args);
215
+ };
216
+ Object.defineProperty(patched, 'name', { value: original.name });
217
+ mod[name] = patched;
218
+ }
219
+ /** Patch the node http layer. Idempotent, shared across sdk copies. Called by `run`. */
220
+ function install() {
221
+ var _a, _b;
222
+ if (shared.installed)
223
+ return;
224
+ shared.installed = true;
225
+ wrap(http_1.default, 'request', 'http:');
226
+ wrap(http_1.default, 'get', 'http:');
227
+ wrap(https_1.default, 'request', 'https:');
228
+ wrap(https_1.default, 'get', 'https:');
229
+ try {
230
+ // global fetch (undici); node < 18.7 has no subscribe, fetch is then simply not counted
231
+ ;
232
+ (_b = (_a = diagnostics_channel_1.default).subscribe) === null || _b === void 0 ? void 0 : _b.call(_a, 'undici:request:create', (message) => {
233
+ var _a;
234
+ try {
235
+ const request = message === null || message === void 0 ? void 0 : message.request;
236
+ if (request === null || request === void 0 ? void 0 : request.origin)
237
+ record(String(request.origin) + String((_a = request.path) !== null && _a !== void 0 ? _a : ''));
238
+ }
239
+ catch { /* ignore */ }
240
+ });
241
+ }
242
+ catch { /* ignore */ }
243
+ try {
244
+ const esConfig = (0, env_1.getEnvValue)('ELASTICSEARCH_CONFIG');
245
+ if (esConfig)
246
+ ignoreHost(JSON.parse(esConfig.replace(/\\"/g, '"')).host);
247
+ }
248
+ catch { /* ignore */ }
249
+ }
250
+ /** Stats of the current run context, or the process-wide bucket when called outside `run`. */
251
+ function getCurrent() {
252
+ var _a;
253
+ return (_a = shared.als.getStore()) !== null && _a !== void 0 ? _a : shared.global;
254
+ }
255
+ function snapshot(stats = getCurrent()) {
256
+ const byMethod = {};
257
+ for (const [method, byChain] of Object.entries(stats.byMethod))
258
+ byMethod[method] = { ...byChain };
259
+ return { total: stats.total, byChain: { ...stats.byChain }, byHost: { ...stats.byHost }, unattributed: stats.unattributed, byMethod };
260
+ }
261
+ function mergeSnapshots(snapshots) {
262
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
263
+ const out = { total: 0, byChain: {}, byHost: {}, unattributed: 0, byMethod: {} };
264
+ for (const s of snapshots) {
265
+ if (!s)
266
+ continue;
267
+ out.total += (_a = s.total) !== null && _a !== void 0 ? _a : 0;
268
+ out.unattributed += (_b = s.unattributed) !== null && _b !== void 0 ? _b : 0;
269
+ for (const [k, v] of Object.entries((_c = s.byChain) !== null && _c !== void 0 ? _c : {}))
270
+ out.byChain[k] = ((_d = out.byChain[k]) !== null && _d !== void 0 ? _d : 0) + v;
271
+ for (const [k, v] of Object.entries((_e = s.byHost) !== null && _e !== void 0 ? _e : {}))
272
+ out.byHost[k] = ((_f = out.byHost[k]) !== null && _f !== void 0 ? _f : 0) + v;
273
+ for (const [method, byChain] of Object.entries((_g = s.byMethod) !== null && _g !== void 0 ? _g : {})) {
274
+ const target = (_h = out.byMethod[method]) !== null && _h !== void 0 ? _h : (out.byMethod[method] = {});
275
+ for (const [k, v] of Object.entries(byChain))
276
+ target[k] = ((_j = target[k]) !== null && _j !== void 0 ? _j : 0) + v;
277
+ }
278
+ }
279
+ return out;
280
+ }
281
+ /**
282
+ * Run `fn` with its own counters and report them when it settles (success or failure).
283
+ * Nested calls get their own context; calls made by `fn` through any http client are attributed to it.
284
+ */
285
+ async function run(meta, fn, options = {}) {
286
+ install();
287
+ const stats = newStats(meta);
288
+ return shared.als.run(stats, async () => {
289
+ let success = false;
290
+ try {
291
+ const result = await fn();
292
+ success = true;
293
+ return result;
294
+ }
295
+ finally {
296
+ try {
297
+ await report(stats, { success, runtime: (Date.now() - stats.startTime) / 1000, ...options });
298
+ }
299
+ catch (e) {
300
+ (0, debugLog_1.debugLog)('[callStats] failed to report', e === null || e === void 0 ? void 0 : e.message);
301
+ }
302
+ }
303
+ });
304
+ }
305
+ // ---------------------------------------------------------------------------
306
+ // reporting
307
+ // ---------------------------------------------------------------------------
308
+ function sortedEntries(map, minCalls, limit) {
309
+ const entries = Object.entries(map).filter(([, calls]) => calls >= minCalls).map(([key, calls]) => ({ key, calls }));
310
+ entries.sort((a, b) => b.calls - a.calls);
311
+ return limit ? entries.slice(0, limit) : entries;
312
+ }
313
+ function getMinCalls(minCalls) {
314
+ if (minCalls !== undefined)
315
+ return minCalls;
316
+ return +(0, env_1.getEnvValue)('CALL_STATS_MIN_CALLS', String(exports.DEFAULT_MIN_CALLS));
317
+ }
318
+ function getMinGetLogs() {
319
+ return +(0, env_1.getEnvValue)('CALL_STATS_MIN_GET_LOGS', String(exports.DEFAULT_MIN_GET_LOGS));
320
+ }
321
+ /**
322
+ * Chains worth a row: at least `minCalls` http requests, or at least `minGetLogs` getLogs requests
323
+ * (a chain that makes 20 getLogs calls is heavier than one making 50 eth_calls). Most calls first.
324
+ */
325
+ function chainEntries(stats, minCalls) {
326
+ var _a, _b;
327
+ const minGetLogs = getMinGetLogs();
328
+ const chains = new Set([...Object.keys(stats.byChain), ...Object.keys((_b = (_a = stats.byMethod) === null || _a === void 0 ? void 0 : _a.getLogs) !== null && _b !== void 0 ? _b : {})]);
329
+ const entries = [...chains]
330
+ .map(key => { var _a; return ({ key, calls: (_a = stats.byChain[key]) !== null && _a !== void 0 ? _a : 0, getLogs: getLogsCount(stats, key) }); })
331
+ .filter(i => i.calls >= minCalls || i.getLogs >= minGetLogs);
332
+ entries.sort((a, b) => b.calls - a.calls || b.getLogs - a.getLogs);
333
+ return entries;
334
+ }
335
+ /** Elasticsearch documents for a run: one `run` summary, one `chain` doc per chain and one `host` doc per unattributed host at or above `minCalls`. */
336
+ function buildDocs(stats, meta, { success, runtime, minCalls } = {}) {
337
+ minCalls = getMinCalls(minCalls);
338
+ const timestamp = Date.now();
339
+ const chains = chainEntries(stats, minCalls);
340
+ const hosts = sortedEntries(stats.byHost, minCalls, 25);
341
+ const rpcCalls = Object.values(stats.byChain).reduce((a, b) => a + b, 0);
342
+ const getLogsCalls = getLogsCount(stats);
343
+ const unattributedHosts = sortedEntries(Object.fromEntries(Object.entries(stats.byHost).filter(([host]) => !shared.endpoints.has(host))), minCalls);
344
+ const docs = [];
345
+ if (stats.total < minCalls && getLogsCalls < getMinGetLogs())
346
+ return docs;
347
+ docs.push({
348
+ timestamp, type: 'run', metadata: meta, success, runtime,
349
+ calls: stats.total, rpcCalls, otherCalls: stats.unattributed, getLogsCalls,
350
+ methods: methodTotals(stats),
351
+ chains: chains.map(i => ({ chain: i.key, calls: i.calls, getLogs: i.getLogs })),
352
+ hosts: hosts.map(i => ({ host: i.key, calls: i.calls })),
353
+ });
354
+ for (const i of chains)
355
+ docs.push({ timestamp, type: 'chain', metadata: meta, chain: i.key, calls: i.calls, getLogs: i.getLogs, methods: methodsForChain(stats, i.key) });
356
+ for (const i of unattributedHosts)
357
+ docs.push({ timestamp, type: 'host', metadata: meta, host: i.key, calls: i.calls });
358
+ return docs;
359
+ }
360
+ /** Write the docs for `stats` to elasticsearch (no-op when ELASTICSEARCH_CONFIG is unset) and print the summary in debug mode. */
361
+ async function report(stats, { success, runtime, minCalls, print, skipElastic, meta } = {}) {
362
+ var _a;
363
+ meta = (_a = meta !== null && meta !== void 0 ? meta : stats.meta) !== null && _a !== void 0 ? _a : { application: 'unknown', name: '-' };
364
+ minCalls = getMinCalls(minCalls);
365
+ const docs = buildDocs(stats, meta, { success, runtime, minCalls });
366
+ if (print)
367
+ printStats(stats, meta, minCalls, console.log, console.table);
368
+ else
369
+ printStats(stats, meta, minCalls, debugLog_1.debugLog, debugLog_1.debugTable);
370
+ if (skipElastic || !docs.length)
371
+ return;
372
+ await Promise.all(docs.map(doc => (0, elastic_1.writeLog)(exports.ES_INDEX, doc)));
373
+ }
374
+ function printStats(stats, meta, minCalls, log, table) {
375
+ const getLogsCalls = getLogsCount(stats);
376
+ if (stats.total < minCalls && getLogsCalls < getMinGetLogs())
377
+ return;
378
+ log(`[callStats] ${meta.application}/${meta.name}: ${stats.total} http requests (${stats.unattributed} not matching a known rpc, ${getLogsCalls} getLogs)`);
379
+ const rows = [
380
+ ...chainEntries(stats, minCalls).map(i => ({ chain: i.key, calls: i.calls, getLogs: i.getLogs })),
381
+ ...sortedEntries(Object.fromEntries(Object.entries(stats.byHost).filter(([host]) => !shared.endpoints.has(host))), minCalls).map(i => ({ chain: `host: ${i.key}`, calls: i.calls, getLogs: 0 })),
382
+ ];
383
+ if (rows.length)
384
+ table(rows);
385
+ }