hive-intelligence 1.16.1 → 1.17.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/agent-skills/packs/hive-build-onboarding/SKILL.md +17 -13
- package/agent-skills/packs/hive-mcp/references/client-install-matrix.md +0 -1
- package/build/{chunk-6M6O3DZM.js → chunk-TLADUAUA.js} +1 -1
- package/build/{chunk-757ZNB6W.js → chunk-UP47NKED.js} +272 -680
- package/build/cli.js +5 -5
- package/build/{doctor-SP73PMX2.js → doctor-PAVENKK7.js} +1 -1
- package/build/{mcpServer-4JE5FTVP.js → mcpServer-TJEF6MZ6.js} +1 -1
- package/build/monitor-worker.js +2 -2
- package/build/release.json +4 -4
- package/build/{serve-YV4RZIK5.js → serve-R6GMEH2G.js} +1 -1
- package/build/server.js +13 -644
- package/build/stdio.js +1 -1
- package/package.json +1 -1
|
@@ -14579,7 +14579,7 @@ var handlers = {
|
|
|
14579
14579
|
getApprovalSecurity: createHandler("getApprovalSecurity", {
|
|
14580
14580
|
suggestion: "Verify the chain ID and spender contract address. Use this before approving tokens to a contract.",
|
|
14581
14581
|
alternatives: [
|
|
14582
|
-
"
|
|
14582
|
+
"get_wallet_approvals - List existing approvals",
|
|
14583
14583
|
"get_token_security - Analyze token contract"
|
|
14584
14584
|
],
|
|
14585
14585
|
example: {
|
|
@@ -14601,7 +14601,7 @@ var handlers = {
|
|
|
14601
14601
|
getDappSecurity: createHandler("getDappSecurity", {
|
|
14602
14602
|
suggestion: "Provide a complete URL including https://. For comprehensive dApp analysis use this tool.",
|
|
14603
14603
|
alternatives: [
|
|
14604
|
-
"
|
|
14604
|
+
"check_phishing_site - Quick phishing check",
|
|
14605
14605
|
"check_malicious_address - Check associated addresses"
|
|
14606
14606
|
],
|
|
14607
14607
|
example: { url: "https://app.uniswap.org" }
|
|
@@ -14630,7 +14630,7 @@ var handlers = {
|
|
|
14630
14630
|
suggestion: "Provide chain_id, from, to, and data fields. Use hex-encoded calldata starting with 0x.",
|
|
14631
14631
|
alternatives: [
|
|
14632
14632
|
"get_solana_token_security - For Solana token analysis",
|
|
14633
|
-
"
|
|
14633
|
+
"decode_abi - To decode transaction data"
|
|
14634
14634
|
],
|
|
14635
14635
|
example: {
|
|
14636
14636
|
chain_id: "1",
|
|
@@ -18594,10 +18594,10 @@ var wrapper = {
|
|
|
18594
18594
|
// src/utils/fetchClient.ts
|
|
18595
18595
|
var HttpError = class extends Error {
|
|
18596
18596
|
config;
|
|
18597
|
-
constructor(message,
|
|
18597
|
+
constructor(message, config, code, response) {
|
|
18598
18598
|
super(message);
|
|
18599
18599
|
this.name = "HttpError";
|
|
18600
|
-
this.config =
|
|
18600
|
+
this.config = config;
|
|
18601
18601
|
if (code) this.code = code;
|
|
18602
18602
|
if (response) this.response = response;
|
|
18603
18603
|
}
|
|
@@ -18634,16 +18634,16 @@ var UNDICI_CODES = {
|
|
|
18634
18634
|
UND_ERR_BODY_TIMEOUT: "ETIMEDOUT",
|
|
18635
18635
|
UND_ERR_SOCKET: "ECONNRESET"
|
|
18636
18636
|
};
|
|
18637
|
-
function networkError(error, timedOut, timeout,
|
|
18637
|
+
function networkError(error, timedOut, timeout, config) {
|
|
18638
18638
|
if (timedOut) {
|
|
18639
|
-
return new HttpError(`timeout of ${timeout}ms exceeded`,
|
|
18639
|
+
return new HttpError(`timeout of ${timeout}ms exceeded`, config, "ECONNABORTED");
|
|
18640
18640
|
}
|
|
18641
18641
|
const cause = error?.cause;
|
|
18642
18642
|
const rawCode = cause?.code;
|
|
18643
18643
|
const code = (rawCode && UNDICI_CODES[rawCode]) ?? rawCode ?? "ERR_NETWORK";
|
|
18644
|
-
return new HttpError(cause?.message || rawCode || "Network Error",
|
|
18644
|
+
return new HttpError(cause?.message || rawCode || "Network Error", config, code);
|
|
18645
18645
|
}
|
|
18646
|
-
async function readBody(response, maxContentLength,
|
|
18646
|
+
async function readBody(response, maxContentLength, config, onChunk) {
|
|
18647
18647
|
if (!response.body) return "";
|
|
18648
18648
|
const reader = response.body.getReader();
|
|
18649
18649
|
const chunks = [];
|
|
@@ -18657,7 +18657,7 @@ async function readBody(response, maxContentLength, config2, onChunk) {
|
|
|
18657
18657
|
await reader.cancel();
|
|
18658
18658
|
throw new HttpError(
|
|
18659
18659
|
`maxContentLength size of ${maxContentLength} exceeded`,
|
|
18660
|
-
|
|
18660
|
+
config,
|
|
18661
18661
|
"ERR_BAD_RESPONSE"
|
|
18662
18662
|
);
|
|
18663
18663
|
}
|
|
@@ -18674,9 +18674,9 @@ function parseBody(text) {
|
|
|
18674
18674
|
}
|
|
18675
18675
|
}
|
|
18676
18676
|
function createFetchClient(options = {}) {
|
|
18677
|
-
async function request(method, url, data,
|
|
18677
|
+
async function request(method, url, data, config = {}) {
|
|
18678
18678
|
const info = { method, url };
|
|
18679
|
-
const timeout =
|
|
18679
|
+
const timeout = config.timeout ?? options.timeout ?? 0;
|
|
18680
18680
|
const controller = new AbortController();
|
|
18681
18681
|
let timedOut = false;
|
|
18682
18682
|
let timer;
|
|
@@ -18694,7 +18694,7 @@ function createFetchClient(options = {}) {
|
|
|
18694
18694
|
const headers = {
|
|
18695
18695
|
Accept: "application/json, text/plain, */*",
|
|
18696
18696
|
...options.headers,
|
|
18697
|
-
...
|
|
18697
|
+
...config.headers
|
|
18698
18698
|
};
|
|
18699
18699
|
let body;
|
|
18700
18700
|
if (data !== void 0) {
|
|
@@ -18707,7 +18707,7 @@ function createFetchClient(options = {}) {
|
|
|
18707
18707
|
let text;
|
|
18708
18708
|
let res;
|
|
18709
18709
|
try {
|
|
18710
|
-
res = await fetch(buildUrl(options.baseURL, url,
|
|
18710
|
+
res = await fetch(buildUrl(options.baseURL, url, config.params), {
|
|
18711
18711
|
method: method.toUpperCase(),
|
|
18712
18712
|
headers,
|
|
18713
18713
|
body,
|
|
@@ -18741,10 +18741,10 @@ function createFetchClient(options = {}) {
|
|
|
18741
18741
|
}
|
|
18742
18742
|
}
|
|
18743
18743
|
return {
|
|
18744
|
-
get: (url,
|
|
18745
|
-
post: (url, data,
|
|
18746
|
-
put: (url, data,
|
|
18747
|
-
delete: (url,
|
|
18744
|
+
get: (url, config) => request("get", url, void 0, config),
|
|
18745
|
+
post: (url, data, config) => request("post", url, data, config),
|
|
18746
|
+
put: (url, data, config) => request("put", url, data, config),
|
|
18747
|
+
delete: (url, config) => request("delete", url, void 0, config)
|
|
18748
18748
|
};
|
|
18749
18749
|
}
|
|
18750
18750
|
|
|
@@ -31592,8 +31592,7 @@ function isRetryableError(error) {
|
|
|
31592
31592
|
"ECONNRESET",
|
|
31593
31593
|
"ETIMEDOUT",
|
|
31594
31594
|
"ECONNREFUSED",
|
|
31595
|
-
"ENOTFOUND"
|
|
31596
|
-
"ECONNABORTED"
|
|
31595
|
+
"ENOTFOUND"
|
|
31597
31596
|
];
|
|
31598
31597
|
return retryableCodes.includes(error.code || "");
|
|
31599
31598
|
}
|
|
@@ -31612,23 +31611,23 @@ var ResilientHttpClient = class {
|
|
|
31612
31611
|
http;
|
|
31613
31612
|
config;
|
|
31614
31613
|
circuitBreaker;
|
|
31615
|
-
constructor(
|
|
31614
|
+
constructor(config) {
|
|
31616
31615
|
this.config = {
|
|
31617
|
-
baseURL:
|
|
31618
|
-
timeout:
|
|
31616
|
+
baseURL: config.baseURL,
|
|
31617
|
+
timeout: config.timeout ?? 3e4,
|
|
31619
31618
|
// 30 seconds default
|
|
31620
|
-
headers:
|
|
31621
|
-
serviceName:
|
|
31622
|
-
maxRetries:
|
|
31623
|
-
retryBaseDelay:
|
|
31624
|
-
enableCircuitBreaker:
|
|
31625
|
-
circuitBreakerThreshold:
|
|
31626
|
-
circuitBreakerResetTimeout:
|
|
31619
|
+
headers: config.headers,
|
|
31620
|
+
serviceName: config.serviceName,
|
|
31621
|
+
maxRetries: config.maxRetries ?? 3,
|
|
31622
|
+
retryBaseDelay: config.retryBaseDelay ?? 1e3,
|
|
31623
|
+
enableCircuitBreaker: config.enableCircuitBreaker ?? true,
|
|
31624
|
+
circuitBreakerThreshold: config.circuitBreakerThreshold ?? 5,
|
|
31625
|
+
circuitBreakerResetTimeout: config.circuitBreakerResetTimeout ?? 3e4
|
|
31627
31626
|
};
|
|
31628
31627
|
this.http = createFetchClient({
|
|
31629
31628
|
baseURL: this.config.baseURL,
|
|
31630
31629
|
timeout: this.config.timeout,
|
|
31631
|
-
maxContentLength:
|
|
31630
|
+
maxContentLength: config.maxContentLength,
|
|
31632
31631
|
headers: {
|
|
31633
31632
|
"Content-Type": "application/json",
|
|
31634
31633
|
Accept: "application/json",
|
|
@@ -31647,12 +31646,12 @@ var ResilientHttpClient = class {
|
|
|
31647
31646
|
url: endpoint,
|
|
31648
31647
|
params: options.params
|
|
31649
31648
|
});
|
|
31650
|
-
const
|
|
31649
|
+
const config = {
|
|
31651
31650
|
params: options.params,
|
|
31652
31651
|
timeout: options.timeout ?? this.config.timeout,
|
|
31653
31652
|
headers: options.headers
|
|
31654
31653
|
};
|
|
31655
|
-
const response = method === "get" || method === "delete" ? await this.http[method](endpoint,
|
|
31654
|
+
const response = method === "get" || method === "delete" ? await this.http[method](endpoint, config) : await this.http[method](endpoint, options.body, config);
|
|
31656
31655
|
secureLogger.debug(`[${this.config.serviceName}] Response`, {
|
|
31657
31656
|
status: response.status,
|
|
31658
31657
|
url: endpoint
|
|
@@ -31844,8 +31843,8 @@ var ResilientHttpClient = class {
|
|
|
31844
31843
|
);
|
|
31845
31844
|
}
|
|
31846
31845
|
};
|
|
31847
|
-
function createHttpClient(
|
|
31848
|
-
return new ResilientHttpClient(
|
|
31846
|
+
function createHttpClient(config) {
|
|
31847
|
+
return new ResilientHttpClient(config);
|
|
31849
31848
|
}
|
|
31850
31849
|
|
|
31851
31850
|
// src/tools/tenderly/tenderlyClient.ts
|
|
@@ -35981,15 +35980,15 @@ var getTransactionHandler = makeHandler(
|
|
|
35981
35980
|
},
|
|
35982
35981
|
(client2, args) => {
|
|
35983
35982
|
const signature = String(args.signature ?? "");
|
|
35984
|
-
const
|
|
35983
|
+
const config = {};
|
|
35985
35984
|
for (const key of [
|
|
35986
35985
|
"encoding",
|
|
35987
35986
|
"commitment",
|
|
35988
35987
|
"maxSupportedTransactionVersion"
|
|
35989
35988
|
]) {
|
|
35990
|
-
if (args[key] !== void 0)
|
|
35989
|
+
if (args[key] !== void 0) config[key] = args[key];
|
|
35991
35990
|
}
|
|
35992
|
-
return client2.request("getTransaction", [signature,
|
|
35991
|
+
return client2.request("getTransaction", [signature, config]);
|
|
35993
35992
|
}
|
|
35994
35993
|
);
|
|
35995
35994
|
var getTransactionsForAddressHandler = makeHandler(
|
|
@@ -36004,7 +36003,7 @@ var getTransactionsForAddressHandler = makeHandler(
|
|
|
36004
36003
|
1,
|
|
36005
36004
|
Math.min(transactionDetails === "full" ? 100 : 1e3, requestedLimit)
|
|
36006
36005
|
);
|
|
36007
|
-
const
|
|
36006
|
+
const config = { transactionDetails, limit };
|
|
36008
36007
|
for (const key of [
|
|
36009
36008
|
"sortOrder",
|
|
36010
36009
|
"commitment",
|
|
@@ -36014,11 +36013,11 @@ var getTransactionsForAddressHandler = makeHandler(
|
|
|
36014
36013
|
"maxSupportedTransactionVersion",
|
|
36015
36014
|
"filters"
|
|
36016
36015
|
]) {
|
|
36017
|
-
if (args[key] !== void 0)
|
|
36016
|
+
if (args[key] !== void 0) config[key] = args[key];
|
|
36018
36017
|
}
|
|
36019
36018
|
return client2.request("getTransactionsForAddress", [
|
|
36020
36019
|
String(args.address ?? ""),
|
|
36021
|
-
|
|
36020
|
+
config
|
|
36022
36021
|
]);
|
|
36023
36022
|
}
|
|
36024
36023
|
);
|
|
@@ -36029,7 +36028,7 @@ var getTransfersByAddressHandler = makeHandler(
|
|
|
36029
36028
|
{ address: EX_OWNER, limit: 50 },
|
|
36030
36029
|
(client2, args) => {
|
|
36031
36030
|
const requestedLimit = Number(args.limit ?? 100);
|
|
36032
|
-
const
|
|
36031
|
+
const config = {
|
|
36033
36032
|
limit: Math.max(1, Math.min(100, requestedLimit))
|
|
36034
36033
|
};
|
|
36035
36034
|
for (const key of [
|
|
@@ -36043,11 +36042,11 @@ var getTransfersByAddressHandler = makeHandler(
|
|
|
36043
36042
|
"minContextSlot",
|
|
36044
36043
|
"sortOrder"
|
|
36045
36044
|
]) {
|
|
36046
|
-
if (args[key] !== void 0)
|
|
36045
|
+
if (args[key] !== void 0) config[key] = args[key];
|
|
36047
36046
|
}
|
|
36048
36047
|
return client2.request("getTransfersByAddress", [
|
|
36049
36048
|
String(args.address ?? ""),
|
|
36050
|
-
|
|
36049
|
+
config
|
|
36051
36050
|
]);
|
|
36052
36051
|
}
|
|
36053
36052
|
);
|
|
@@ -36332,7 +36331,7 @@ var getTokenAccountsByOwnerV2Handler = makeHandler(
|
|
|
36332
36331
|
(client2, args) => {
|
|
36333
36332
|
const owner = String(args.owner ?? "");
|
|
36334
36333
|
const filter = args.mint !== void 0 ? { mint: String(args.mint) } : { programId: String(args.programId ?? TOKEN_PROGRAM_ID) };
|
|
36335
|
-
const
|
|
36334
|
+
const config = {
|
|
36336
36335
|
encoding: args.encoding ?? "jsonParsed",
|
|
36337
36336
|
limit: args.limit ?? 1e3
|
|
36338
36337
|
};
|
|
@@ -36344,9 +36343,9 @@ var getTokenAccountsByOwnerV2Handler = makeHandler(
|
|
|
36344
36343
|
"withContext",
|
|
36345
36344
|
"commitment"
|
|
36346
36345
|
]) {
|
|
36347
|
-
if (args[key] !== void 0)
|
|
36346
|
+
if (args[key] !== void 0) config[key] = args[key];
|
|
36348
36347
|
}
|
|
36349
|
-
return client2.request("getTokenAccountsByOwnerV2", [owner, filter,
|
|
36348
|
+
return client2.request("getTokenAccountsByOwnerV2", [owner, filter, config]);
|
|
36350
36349
|
}
|
|
36351
36350
|
);
|
|
36352
36351
|
var getProgramAccountsV2Handler = makeHandler(
|
|
@@ -36355,7 +36354,7 @@ var getProgramAccountsV2Handler = makeHandler(
|
|
|
36355
36354
|
["helius_get_token_accounts_by_owner_v2"],
|
|
36356
36355
|
{ programId: TOKEN_PROGRAM_ID, encoding: "base64", limit: 10 },
|
|
36357
36356
|
(client2, args) => {
|
|
36358
|
-
const
|
|
36357
|
+
const config = {
|
|
36359
36358
|
encoding: args.encoding ?? "base64",
|
|
36360
36359
|
limit: args.limit ?? 100
|
|
36361
36360
|
};
|
|
@@ -36368,11 +36367,11 @@ var getProgramAccountsV2Handler = makeHandler(
|
|
|
36368
36367
|
"withContext",
|
|
36369
36368
|
"commitment"
|
|
36370
36369
|
]) {
|
|
36371
|
-
if (args[key] !== void 0)
|
|
36370
|
+
if (args[key] !== void 0) config[key] = args[key];
|
|
36372
36371
|
}
|
|
36373
36372
|
return client2.request("getProgramAccountsV2", [
|
|
36374
36373
|
String(args.programId ?? ""),
|
|
36375
|
-
|
|
36374
|
+
config
|
|
36376
36375
|
]);
|
|
36377
36376
|
}
|
|
36378
36377
|
);
|
|
@@ -36522,8 +36521,8 @@ var AlchemyClient = class {
|
|
|
36522
36521
|
secureLogger.info("Alchemy client initialized");
|
|
36523
36522
|
}
|
|
36524
36523
|
getHttpClient(baseURL, serviceName) {
|
|
36525
|
-
const
|
|
36526
|
-
const existing = this.clients.get(
|
|
36524
|
+
const cacheKey = `${serviceName}:${baseURL}`;
|
|
36525
|
+
const existing = this.clients.get(cacheKey);
|
|
36527
36526
|
if (existing) return existing;
|
|
36528
36527
|
const client2 = createHttpClient({
|
|
36529
36528
|
baseURL,
|
|
@@ -36539,7 +36538,7 @@ var AlchemyClient = class {
|
|
|
36539
36538
|
circuitBreakerThreshold: 5,
|
|
36540
36539
|
circuitBreakerResetTimeout: 3e4
|
|
36541
36540
|
});
|
|
36542
|
-
this.clients.set(
|
|
36541
|
+
this.clients.set(cacheKey, client2);
|
|
36543
36542
|
return client2;
|
|
36544
36543
|
}
|
|
36545
36544
|
apiPath(path) {
|
|
@@ -47582,7 +47581,7 @@ async function fetchWithTimeout(url, options, timeout) {
|
|
|
47582
47581
|
}
|
|
47583
47582
|
async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
|
|
47584
47583
|
const startTime = Date.now();
|
|
47585
|
-
const
|
|
47584
|
+
const config = {
|
|
47586
47585
|
timeout: resilientOptions.timeout ?? 3e4,
|
|
47587
47586
|
maxRetries: resilientOptions.maxRetries ?? 3,
|
|
47588
47587
|
retryBaseDelay: resilientOptions.retryBaseDelay ?? 1e3,
|
|
@@ -47591,21 +47590,21 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
|
|
|
47591
47590
|
circuitBreakerThreshold: resilientOptions.circuitBreakerThreshold ?? 5,
|
|
47592
47591
|
circuitBreakerResetTimeout: resilientOptions.circuitBreakerResetTimeout ?? 3e4
|
|
47593
47592
|
};
|
|
47594
|
-
const circuitBreaker = getCircuitBreaker2(
|
|
47595
|
-
if (
|
|
47596
|
-
checkCircuitBreaker(circuitBreaker,
|
|
47593
|
+
const circuitBreaker = getCircuitBreaker2(config.serviceName);
|
|
47594
|
+
if (config.enableCircuitBreaker) {
|
|
47595
|
+
checkCircuitBreaker(circuitBreaker, config);
|
|
47597
47596
|
}
|
|
47598
47597
|
let lastError = null;
|
|
47599
|
-
for (let attempt = 0; attempt <=
|
|
47598
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
47600
47599
|
try {
|
|
47601
|
-
const response = await fetchWithTimeout(url, fetchOptions,
|
|
47600
|
+
const response = await fetchWithTimeout(url, fetchOptions, config.timeout);
|
|
47602
47601
|
if (!response.ok && isRetryableStatus(response.status)) {
|
|
47603
47602
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
47604
47603
|
}
|
|
47605
|
-
if (
|
|
47604
|
+
if (config.enableCircuitBreaker) {
|
|
47606
47605
|
recordSuccess(circuitBreaker);
|
|
47607
47606
|
}
|
|
47608
|
-
secureLogger.debug(`[${
|
|
47607
|
+
secureLogger.debug(`[${config.serviceName}] Request succeeded`, {
|
|
47609
47608
|
url: sanitizeUrl(url),
|
|
47610
47609
|
status: response.status,
|
|
47611
47610
|
duration: Date.now() - startTime
|
|
@@ -47613,15 +47612,15 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
|
|
|
47613
47612
|
return response;
|
|
47614
47613
|
} catch (error) {
|
|
47615
47614
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
47616
|
-
if (
|
|
47617
|
-
recordFailure(circuitBreaker,
|
|
47615
|
+
if (config.enableCircuitBreaker) {
|
|
47616
|
+
recordFailure(circuitBreaker, config);
|
|
47618
47617
|
}
|
|
47619
|
-
if (attempt <
|
|
47620
|
-
const delay2 = calculateBackoffDelay2(attempt,
|
|
47621
|
-
secureLogger.warn(`[${
|
|
47618
|
+
if (attempt < config.maxRetries) {
|
|
47619
|
+
const delay2 = calculateBackoffDelay2(attempt, config.retryBaseDelay);
|
|
47620
|
+
secureLogger.warn(`[${config.serviceName}] Request failed, retrying`, {
|
|
47622
47621
|
url: sanitizeUrl(url),
|
|
47623
47622
|
attempt: attempt + 1,
|
|
47624
|
-
maxRetries:
|
|
47623
|
+
maxRetries: config.maxRetries,
|
|
47625
47624
|
delayMs: Math.round(delay2),
|
|
47626
47625
|
error: lastError.message
|
|
47627
47626
|
});
|
|
@@ -47630,28 +47629,28 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
|
|
|
47630
47629
|
}
|
|
47631
47630
|
}
|
|
47632
47631
|
}
|
|
47633
|
-
secureLogger.error(`[${
|
|
47632
|
+
secureLogger.error(`[${config.serviceName}] Request failed after all retries`, lastError, {
|
|
47634
47633
|
url: sanitizeUrl(url),
|
|
47635
|
-
attempts:
|
|
47634
|
+
attempts: config.maxRetries + 1,
|
|
47636
47635
|
duration: Date.now() - startTime
|
|
47637
47636
|
});
|
|
47638
47637
|
throw lastError;
|
|
47639
47638
|
}
|
|
47640
|
-
function checkCircuitBreaker(breaker,
|
|
47639
|
+
function checkCircuitBreaker(breaker, config) {
|
|
47641
47640
|
const now = Date.now();
|
|
47642
47641
|
switch (breaker.state) {
|
|
47643
47642
|
case "OPEN" /* OPEN */:
|
|
47644
|
-
if (now - breaker.lastFailureTime >
|
|
47643
|
+
if (now - breaker.lastFailureTime > config.circuitBreakerResetTimeout) {
|
|
47645
47644
|
breaker.state = "HALF_OPEN" /* HALF_OPEN */;
|
|
47646
|
-
secureLogger.info(`[${
|
|
47645
|
+
secureLogger.info(`[${config.serviceName}] Circuit breaker HALF_OPEN, testing recovery`);
|
|
47647
47646
|
} else {
|
|
47648
47647
|
throw new Error(
|
|
47649
|
-
`Circuit breaker OPEN for ${
|
|
47648
|
+
`Circuit breaker OPEN for ${config.serviceName}. Will retry in ${Math.ceil((config.circuitBreakerResetTimeout - (now - breaker.lastFailureTime)) / 1e3)}s`
|
|
47650
47649
|
);
|
|
47651
47650
|
}
|
|
47652
47651
|
break;
|
|
47653
47652
|
case "HALF_OPEN" /* HALF_OPEN */:
|
|
47654
|
-
secureLogger.debug(`[${
|
|
47653
|
+
secureLogger.debug(`[${config.serviceName}] Testing recovery (HALF_OPEN)`);
|
|
47655
47654
|
break;
|
|
47656
47655
|
case "CLOSED" /* CLOSED */:
|
|
47657
47656
|
break;
|
|
@@ -47664,15 +47663,15 @@ function recordSuccess(breaker) {
|
|
|
47664
47663
|
breaker.state = "CLOSED" /* CLOSED */;
|
|
47665
47664
|
breaker.failures = 0;
|
|
47666
47665
|
}
|
|
47667
|
-
function recordFailure(breaker,
|
|
47666
|
+
function recordFailure(breaker, config) {
|
|
47668
47667
|
breaker.failures++;
|
|
47669
47668
|
breaker.lastFailureTime = Date.now();
|
|
47670
47669
|
if (breaker.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
47671
47670
|
breaker.state = "OPEN" /* OPEN */;
|
|
47672
|
-
secureLogger.warn(`[${
|
|
47673
|
-
} else if (breaker.failures >=
|
|
47671
|
+
secureLogger.warn(`[${config.serviceName}] Recovery failed, circuit OPEN`);
|
|
47672
|
+
} else if (breaker.failures >= config.circuitBreakerThreshold) {
|
|
47674
47673
|
breaker.state = "OPEN" /* OPEN */;
|
|
47675
|
-
secureLogger.warn(`[${
|
|
47674
|
+
secureLogger.warn(`[${config.serviceName}] Circuit OPEN after ${breaker.failures} failures`);
|
|
47676
47675
|
}
|
|
47677
47676
|
}
|
|
47678
47677
|
function extractServiceName(url) {
|
|
@@ -48917,243 +48916,6 @@ async function trackOAuthFirstMaterialReceipt(params) {
|
|
|
48917
48916
|
]);
|
|
48918
48917
|
}
|
|
48919
48918
|
|
|
48920
|
-
// src/wrapper/cache.ts
|
|
48921
|
-
import crypto from "crypto";
|
|
48922
|
-
|
|
48923
|
-
// src/utils/redis.ts
|
|
48924
|
-
import Redis from "ioredis";
|
|
48925
|
-
var client = null;
|
|
48926
|
-
var available = false;
|
|
48927
|
-
function logRedisInfo(message) {
|
|
48928
|
-
process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO]: ${message}
|
|
48929
|
-
`);
|
|
48930
|
-
}
|
|
48931
|
-
function getRedisClient() {
|
|
48932
|
-
return client;
|
|
48933
|
-
}
|
|
48934
|
-
function isRedisAvailable() {
|
|
48935
|
-
return available;
|
|
48936
|
-
}
|
|
48937
|
-
async function waitForRedisAvailability(timeoutMs = 1e4) {
|
|
48938
|
-
if (!client) return false;
|
|
48939
|
-
if (available) return true;
|
|
48940
|
-
const boundedTimeoutMs = Math.max(1, Math.min(timeoutMs, 3e4));
|
|
48941
|
-
const current = client;
|
|
48942
|
-
return new Promise((resolve) => {
|
|
48943
|
-
let settled = false;
|
|
48944
|
-
const finish = (ready) => {
|
|
48945
|
-
if (settled) return;
|
|
48946
|
-
settled = true;
|
|
48947
|
-
clearTimeout(timer);
|
|
48948
|
-
current.off("ready", onReady);
|
|
48949
|
-
current.off("end", onEnd);
|
|
48950
|
-
resolve(ready);
|
|
48951
|
-
};
|
|
48952
|
-
const onReady = () => finish(true);
|
|
48953
|
-
const onEnd = () => finish(false);
|
|
48954
|
-
const timer = setTimeout(() => finish(available), boundedTimeoutMs);
|
|
48955
|
-
current.once("ready", onReady);
|
|
48956
|
-
current.once("end", onEnd);
|
|
48957
|
-
if (available) finish(true);
|
|
48958
|
-
});
|
|
48959
|
-
}
|
|
48960
|
-
async function closeRedisClient() {
|
|
48961
|
-
if (!client) return;
|
|
48962
|
-
const current = client;
|
|
48963
|
-
client = null;
|
|
48964
|
-
available = false;
|
|
48965
|
-
try {
|
|
48966
|
-
await Promise.race([
|
|
48967
|
-
current.quit(),
|
|
48968
|
-
new Promise(
|
|
48969
|
-
(_, reject) => setTimeout(() => reject(new Error("Redis quit timed out")), 5e3)
|
|
48970
|
-
)
|
|
48971
|
-
]);
|
|
48972
|
-
logRedisInfo("[redis] Connection closed gracefully");
|
|
48973
|
-
} catch (err) {
|
|
48974
|
-
secureLogger.error(
|
|
48975
|
-
"[redis] Error closing connection, forcing disconnect",
|
|
48976
|
-
err,
|
|
48977
|
-
{}
|
|
48978
|
-
);
|
|
48979
|
-
current.disconnect();
|
|
48980
|
-
}
|
|
48981
|
-
}
|
|
48982
|
-
var DEGRADED_AFTER_ATTEMPTS = 3;
|
|
48983
|
-
var MAX_RECONNECT_DELAY_MS = 3e3;
|
|
48984
|
-
function redisRetryStrategy(times) {
|
|
48985
|
-
if (times === DEGRADED_AFTER_ATTEMPTS) {
|
|
48986
|
-
secureLogger.warn(
|
|
48987
|
-
`[redis] Connection failed after ${DEGRADED_AFTER_ATTEMPTS} retries, falling back to in-memory while reconnection continues`,
|
|
48988
|
-
{}
|
|
48989
|
-
);
|
|
48990
|
-
available = false;
|
|
48991
|
-
}
|
|
48992
|
-
return Math.min(times * 100, MAX_RECONNECT_DELAY_MS);
|
|
48993
|
-
}
|
|
48994
|
-
function redisClientOptions() {
|
|
48995
|
-
return {
|
|
48996
|
-
maxRetriesPerRequest: 3,
|
|
48997
|
-
retryStrategy: redisRetryStrategy,
|
|
48998
|
-
lazyConnect: true
|
|
48999
|
-
};
|
|
49000
|
-
}
|
|
49001
|
-
var redisUrl = getEnvVar("REDIS_URL");
|
|
49002
|
-
function isRedisConfigured() {
|
|
49003
|
-
return Boolean(redisUrl);
|
|
49004
|
-
}
|
|
49005
|
-
if (redisUrl) {
|
|
49006
|
-
try {
|
|
49007
|
-
client = new Redis(redisUrl, redisClientOptions());
|
|
49008
|
-
client.connect().then(() => {
|
|
49009
|
-
available = true;
|
|
49010
|
-
logRedisInfo("[redis] Connected successfully");
|
|
49011
|
-
}).catch((err) => {
|
|
49012
|
-
secureLogger.warn("[redis] Connection failed", {
|
|
49013
|
-
error: err.message
|
|
49014
|
-
});
|
|
49015
|
-
available = false;
|
|
49016
|
-
});
|
|
49017
|
-
client.on("error", (err) => {
|
|
49018
|
-
secureLogger.warn("[redis] Error", { error: err.message });
|
|
49019
|
-
available = false;
|
|
49020
|
-
});
|
|
49021
|
-
client.on("ready", () => {
|
|
49022
|
-
available = true;
|
|
49023
|
-
});
|
|
49024
|
-
const gracefulShutdown = async (signal) => {
|
|
49025
|
-
logRedisInfo(`[redis] Received ${signal}, closing connection...`);
|
|
49026
|
-
await closeRedisClient();
|
|
49027
|
-
};
|
|
49028
|
-
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
49029
|
-
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
49030
|
-
} catch (err) {
|
|
49031
|
-
secureLogger.warn("[redis] Failed to initialise", {
|
|
49032
|
-
error: String(err)
|
|
49033
|
-
});
|
|
49034
|
-
client = null;
|
|
49035
|
-
}
|
|
49036
|
-
} else {
|
|
49037
|
-
logRedisInfo("[redis] No REDIS_URL provided, using in-memory fallbacks");
|
|
49038
|
-
}
|
|
49039
|
-
|
|
49040
|
-
// src/wrapper/cache.ts
|
|
49041
|
-
var PREFIX = "mcp-cache:";
|
|
49042
|
-
var CACHE_ENVELOPE_VERSION = 1;
|
|
49043
|
-
var TTL_MARKET_S = 30;
|
|
49044
|
-
var TTL_METADATA_S = 5 * 60;
|
|
49045
|
-
var TTL_STATIC_S = 60 * 60;
|
|
49046
|
-
var BUCKETS = [
|
|
49047
|
-
{
|
|
49048
|
-
// Static reference data — list of chains, supported currencies, asset
|
|
49049
|
-
// platforms. Changes on the order of weeks/months.
|
|
49050
|
-
patterns: [
|
|
49051
|
-
/_get_(asset_platforms|networks|supported_currencies|categories_list|coins_list|new_coins_list|exchanges_list|exchange_rates)\b/,
|
|
49052
|
-
/\bdefillama_get_chains\b/
|
|
49053
|
-
],
|
|
49054
|
-
ttlS: TTL_STATIC_S
|
|
49055
|
-
},
|
|
49056
|
-
{
|
|
49057
|
-
// Live market data — prices, volume, OHLC, market caps. Refreshes on
|
|
49058
|
-
// 30s-1m boundaries upstream.
|
|
49059
|
-
patterns: [
|
|
49060
|
-
/_get_(price|prices|coins_market_data_browser|coins_markets|simple_price|token_price|historical_token_prices|ohlc|funding_rate|open_interest|ticker|tickers)\b/,
|
|
49061
|
-
/\bmarket_data\b/,
|
|
49062
|
-
/\bvolume\b/,
|
|
49063
|
-
/\bderivatives\b/
|
|
49064
|
-
],
|
|
49065
|
-
ttlS: TTL_MARKET_S
|
|
49066
|
-
},
|
|
49067
|
-
{
|
|
49068
|
-
// Token / coin metadata — descriptions, contract addresses, holder
|
|
49069
|
-
// breakdowns, top-N rankings. Refreshes slowly.
|
|
49070
|
-
patterns: [
|
|
49071
|
-
/_get_(coin_by_id|token_holders|top_holders|onchain_token_top_holders|token_data|protocol_tvl|protocols|categories|trending|nft_collection)\b/
|
|
49072
|
-
],
|
|
49073
|
-
ttlS: TTL_METADATA_S
|
|
49074
|
-
}
|
|
49075
|
-
];
|
|
49076
|
-
function ttlForTool(toolName) {
|
|
49077
|
-
for (const b of BUCKETS) {
|
|
49078
|
-
if (b.patterns.some((rx) => rx.test(toolName))) return b.ttlS;
|
|
49079
|
-
}
|
|
49080
|
-
return 0;
|
|
49081
|
-
}
|
|
49082
|
-
function hashArgs(args) {
|
|
49083
|
-
return crypto.createHash("sha256").update(stableStringify(args)).digest("hex").slice(0, 32);
|
|
49084
|
-
}
|
|
49085
|
-
function stableStringify(value) {
|
|
49086
|
-
if (value === null || typeof value !== "object") {
|
|
49087
|
-
return JSON.stringify(value);
|
|
49088
|
-
}
|
|
49089
|
-
if (Array.isArray(value)) {
|
|
49090
|
-
return `[${value.map(stableStringify).join(",")}]`;
|
|
49091
|
-
}
|
|
49092
|
-
const obj = value;
|
|
49093
|
-
const keys = Object.keys(obj).sort();
|
|
49094
|
-
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
|
|
49095
|
-
}
|
|
49096
|
-
function cacheKey(toolName, args) {
|
|
49097
|
-
return `${PREFIX}${toolName}:${hashArgs(args)}`;
|
|
49098
|
-
}
|
|
49099
|
-
async function getCached(toolName, args) {
|
|
49100
|
-
const redis = getRedisClient();
|
|
49101
|
-
if (!redis || !isRedisAvailable()) return null;
|
|
49102
|
-
if (ttlForTool(toolName) === 0) return null;
|
|
49103
|
-
try {
|
|
49104
|
-
const raw = await redis.get(cacheKey(toolName, args));
|
|
49105
|
-
if (!raw) return null;
|
|
49106
|
-
try {
|
|
49107
|
-
const parsed = JSON.parse(raw);
|
|
49108
|
-
if (parsed._hive_cache_version === CACHE_ENVELOPE_VERSION && typeof parsed.observed_at === "string" && typeof parsed.payload === "string") {
|
|
49109
|
-
const observedMs = Date.parse(parsed.observed_at);
|
|
49110
|
-
return {
|
|
49111
|
-
payload: parsed.payload,
|
|
49112
|
-
observedAt: parsed.observed_at,
|
|
49113
|
-
ageMs: Number.isFinite(observedMs) ? Math.max(0, Date.now() - observedMs) : null,
|
|
49114
|
-
originSource: parsed.origin_source === "live" || parsed.origin_source === "fallback" ? parsed.origin_source : null
|
|
49115
|
-
};
|
|
49116
|
-
}
|
|
49117
|
-
} catch {
|
|
49118
|
-
}
|
|
49119
|
-
return {
|
|
49120
|
-
payload: raw,
|
|
49121
|
-
observedAt: null,
|
|
49122
|
-
ageMs: null,
|
|
49123
|
-
originSource: null
|
|
49124
|
-
};
|
|
49125
|
-
} catch (err) {
|
|
49126
|
-
secureLogger.warn("[mcp-cache] get failed", {
|
|
49127
|
-
error: err instanceof Error ? err.message : String(err)
|
|
49128
|
-
});
|
|
49129
|
-
return null;
|
|
49130
|
-
}
|
|
49131
|
-
}
|
|
49132
|
-
async function setCached(toolName, args, payload, originSource = "live") {
|
|
49133
|
-
const redis = getRedisClient();
|
|
49134
|
-
if (!redis || !isRedisAvailable()) return;
|
|
49135
|
-
const ttlS = ttlForTool(toolName);
|
|
49136
|
-
if (ttlS === 0) return;
|
|
49137
|
-
try {
|
|
49138
|
-
const envelope = {
|
|
49139
|
-
_hive_cache_version: CACHE_ENVELOPE_VERSION,
|
|
49140
|
-
observed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49141
|
-
origin_source: originSource,
|
|
49142
|
-
payload
|
|
49143
|
-
};
|
|
49144
|
-
await redis.set(
|
|
49145
|
-
cacheKey(toolName, args),
|
|
49146
|
-
JSON.stringify(envelope),
|
|
49147
|
-
"EX",
|
|
49148
|
-
ttlS
|
|
49149
|
-
);
|
|
49150
|
-
} catch (err) {
|
|
49151
|
-
secureLogger.warn("[mcp-cache] set failed", {
|
|
49152
|
-
error: err instanceof Error ? err.message : String(err)
|
|
49153
|
-
});
|
|
49154
|
-
}
|
|
49155
|
-
}
|
|
49156
|
-
|
|
49157
48919
|
// src/providers/catalog.ts
|
|
49158
48920
|
var UNKNOWN_PROVIDER_DESCRIPTOR = {
|
|
49159
48921
|
id: "unknown",
|
|
@@ -50412,31 +50174,6 @@ function createSafeHandler(handler100, metadata103, toolName, inputSchema) {
|
|
|
50412
50174
|
}
|
|
50413
50175
|
const { response_format: responseFormat, ...safeArgs } = args ?? {};
|
|
50414
50176
|
const wantsMarkdown = responseFormat === "markdown";
|
|
50415
|
-
const cacheableTtlS = ttlForTool(toolName);
|
|
50416
|
-
if (cacheableTtlS > 0 && !wantsMarkdown) {
|
|
50417
|
-
const cached = await getCached(toolName, safeArgs);
|
|
50418
|
-
if (cached) {
|
|
50419
|
-
trackToolCall({
|
|
50420
|
-
toolName,
|
|
50421
|
-
success: true,
|
|
50422
|
-
durationMs: Date.now() - t0,
|
|
50423
|
-
category: "cache_hit"
|
|
50424
|
-
});
|
|
50425
|
-
return withContentAnnotations(
|
|
50426
|
-
withExecMarker(
|
|
50427
|
-
{ content: [{ type: "text", text: cached.payload }] },
|
|
50428
|
-
{
|
|
50429
|
-
source: "cached",
|
|
50430
|
-
originSource: cached.originSource,
|
|
50431
|
-
cacheStatus: "hit",
|
|
50432
|
-
observedAt: cached.observedAt,
|
|
50433
|
-
cacheAgeMs: cached.ageMs
|
|
50434
|
-
}
|
|
50435
|
-
),
|
|
50436
|
-
false
|
|
50437
|
-
);
|
|
50438
|
-
}
|
|
50439
|
-
}
|
|
50440
50177
|
let result2 = await handler100(effectiveClient, safeArgs);
|
|
50441
50178
|
const observedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
50442
50179
|
if (result2._hiveExec?.source === "fallback") usedFallback = true;
|
|
@@ -50562,23 +50299,14 @@ function createSafeHandler(handler100, metadata103, toolName, inputSchema) {
|
|
|
50562
50299
|
true
|
|
50563
50300
|
);
|
|
50564
50301
|
}
|
|
50565
|
-
if (cacheableTtlS > 0 && !wantsMarkdown) {
|
|
50566
|
-
setCached(
|
|
50567
|
-
toolName,
|
|
50568
|
-
safeArgs,
|
|
50569
|
-
text,
|
|
50570
|
-
usedFallback ? "fallback" : "live"
|
|
50571
|
-
).catch(() => {
|
|
50572
|
-
});
|
|
50573
|
-
}
|
|
50574
50302
|
trackToolCall({
|
|
50575
50303
|
toolName,
|
|
50576
50304
|
success: !result2.isError,
|
|
50577
50305
|
durationMs: Date.now() - t0,
|
|
50578
|
-
category:
|
|
50306
|
+
category: "live_uncached"
|
|
50579
50307
|
});
|
|
50580
50308
|
const successMarker = {
|
|
50581
|
-
cacheStatus:
|
|
50309
|
+
cacheStatus: "bypass",
|
|
50582
50310
|
observedAt,
|
|
50583
50311
|
cacheAgeMs: 0,
|
|
50584
50312
|
originSource: usedFallback ? "fallback" : "live",
|
|
@@ -51922,290 +51650,6 @@ function buildToolCatalogEntry(endpoint) {
|
|
|
51922
51650
|
};
|
|
51923
51651
|
}
|
|
51924
51652
|
|
|
51925
|
-
// src/config/toolNameMappings.ts
|
|
51926
|
-
var TOOL_NAME_MAPPINGS = {
|
|
51927
|
-
// ============================================
|
|
51928
|
-
// Category 1: Market Data and Price (43 tools)
|
|
51929
|
-
// ============================================
|
|
51930
|
-
// CoinGecko endpoints
|
|
51931
|
-
coins_index: "get_coins_index",
|
|
51932
|
-
coins_market_data_browser: "get_coins_market_data",
|
|
51933
|
-
coins_history_browser: "get_coin_history",
|
|
51934
|
-
range_coins_market_chart_browser: "get_coin_market_chart_range",
|
|
51935
|
-
range_coins_ohlc_browser: "get_coin_ohlc_range",
|
|
51936
|
-
simple_price_browser: "get_price",
|
|
51937
|
-
gainers_losers_browser: "get_gainers_losers",
|
|
51938
|
-
contract_coins_browser: "get_contract_coin",
|
|
51939
|
-
range_contract_coins_market_chart_browser: "get_contract_market_chart_range",
|
|
51940
|
-
id_simple_token_price_browser: "get_token_price_by_contract",
|
|
51941
|
-
global_browser: "get_global_stats",
|
|
51942
|
-
simple_supported_vs_currencies_browser: "get_supported_currencies",
|
|
51943
|
-
// Codex endpoints
|
|
51944
|
-
retrieve_token_pricing: "codex_get_token_price",
|
|
51945
|
-
fetch_price_chart_data: "get_token_chart_data",
|
|
51946
|
-
fetch_token_mini_charts: "get_token_sparklines",
|
|
51947
|
-
fetch_token_chart_urls: "get_token_chart_urls",
|
|
51948
|
-
// CoinGecko additional
|
|
51949
|
-
coin_tickers_data: "get_coin_tickers",
|
|
51950
|
-
coin_historical_chart: "get_coin_historical_chart",
|
|
51951
|
-
btc_exchange_rates: "get_btc_exchange_rates",
|
|
51952
|
-
global_market_cap_chart: "get_global_market_cap_chart",
|
|
51953
|
-
companies_crypto_treasury: "get_companies_treasury",
|
|
51954
|
-
// Stablecoins (DeFiLlama)
|
|
51955
|
-
stablecoins_list: "get_stablecoins",
|
|
51956
|
-
stablecoin_chains_list: "get_stablecoin_chains",
|
|
51957
|
-
stablecoin_charts_global: "get_stablecoin_charts_global",
|
|
51958
|
-
stablecoin_charts_by_chain: "get_stablecoin_charts_by_chain",
|
|
51959
|
-
stablecoin_prices_current: "get_stablecoin_prices",
|
|
51960
|
-
// CCXT
|
|
51961
|
-
trading_pair_ticker_data: "get_ticker",
|
|
51962
|
-
multiple_tickers_data: "get_tickers",
|
|
51963
|
-
trading_pair_orderbook_data: "get_orderbook",
|
|
51964
|
-
trading_pair_recent_trades: "get_recent_trades",
|
|
51965
|
-
trading_pair_candlestick_data: "get_ohlcv",
|
|
51966
|
-
multiple_pairs_best_prices: "get_best_bid_ask",
|
|
51967
|
-
level2_orderbook_data: "get_l2_orderbook",
|
|
51968
|
-
derivatives_index_candlestick: "get_index_ohlcv",
|
|
51969
|
-
derivatives_mark_candlestick: "get_mark_ohlcv",
|
|
51970
|
-
perpetual_premium_index_data: "get_premium_index_ohlcv",
|
|
51971
|
-
perpetual_funding_rate_current: "get_funding_rate",
|
|
51972
|
-
perpetual_funding_rate_history: "get_funding_rate_history",
|
|
51973
|
-
perpetual_funding_rates_all: "get_funding_rates",
|
|
51974
|
-
// ============================================
|
|
51975
|
-
// Category 2: On-Chain DEX & Pool Analytics (50 tools)
|
|
51976
|
-
// ============================================
|
|
51977
|
-
// GeckoTerminal (CoinGecko OnChain)
|
|
51978
|
-
onchain_categories_browser: "get_onchain_categories",
|
|
51979
|
-
pools_onchain_categories_browser: "get_pools_by_category",
|
|
51980
|
-
networks_onchain_new_pools_browser: "get_new_pools",
|
|
51981
|
-
network_networks_onchain_new_pools_browser: "get_new_pools_by_network",
|
|
51982
|
-
networks_onchain_trending_pools_browser: "get_trending_pools",
|
|
51983
|
-
network_networks_onchain_trending_pools_browser: "get_trending_pools_by_network",
|
|
51984
|
-
networks_onchain_dexes_browser: "get_dexes",
|
|
51985
|
-
pools_networks_onchain_dexes_browser: "get_pools_by_dex",
|
|
51986
|
-
networks_onchain_pools_browser: "get_pools",
|
|
51987
|
-
address_networks_onchain_pools_browser: "get_pools_by_address",
|
|
51988
|
-
pools_networks_onchain_info_browser: "get_pool_info",
|
|
51989
|
-
timeframe_pools_networks_onchain_ohlcv_browser: "get_pool_ohlcv",
|
|
51990
|
-
pools_networks_onchain_trades_browser: "get_pool_trades",
|
|
51991
|
-
timeframe_tokens_networks_onchain_ohlcv_browser: "get_token_ohlcv",
|
|
51992
|
-
tokens_networks_onchain_pools_browser: "get_token_pools",
|
|
51993
|
-
tokens_networks_onchain_trades_browser: "get_token_trades",
|
|
51994
|
-
pools_onchain_megafilter_browser: "filter_pools",
|
|
51995
|
-
pools_onchain_trending_search_browser: "search_trending_pools",
|
|
51996
|
-
search_onchain_pools_browser: "search_pools",
|
|
51997
|
-
addresses_networks_simple_onchain_token_price_browser: "get_onchain_token_price",
|
|
51998
|
-
// Codex
|
|
51999
|
-
retrieve_token_transactions: "get_token_transactions",
|
|
52000
|
-
fetch_trading_pair_metrics: "get_pair_stats",
|
|
52001
|
-
fetch_multiple_pairs_metrics: "get_pairs_stats",
|
|
52002
|
-
search_filter_pairs: "filter_pairs",
|
|
52003
|
-
fetch_pair_information: "get_pair_info",
|
|
52004
|
-
list_token_pairs: "get_token_pairs",
|
|
52005
|
-
fetch_token_pairs_details: "get_token_pairs_metadata",
|
|
52006
|
-
retrieve_liquidity_information: "get_liquidity_info",
|
|
52007
|
-
fetch_liquidity_lock_details: "get_liquidity_locks",
|
|
52008
|
-
search_exchange_platforms: "filter_exchanges",
|
|
52009
|
-
describe_onchain_transaction: "explain_transaction",
|
|
52010
|
-
// CoinGecko Exchanges
|
|
52011
|
-
exchanges_data: "get_exchanges",
|
|
52012
|
-
exchange_details: "get_exchange",
|
|
52013
|
-
exchange_tickers_data: "get_exchange_tickers",
|
|
52014
|
-
exchange_volume_chart: "get_exchange_volume_chart",
|
|
52015
|
-
exchange_volume_chart_range: "get_exchange_volume_chart_range",
|
|
52016
|
-
derivatives_tickers_data: "get_derivatives_tickers",
|
|
52017
|
-
derivatives_exchanges_data: "get_derivatives_exchanges",
|
|
52018
|
-
derivative_exchange_details: "get_derivatives_exchange",
|
|
52019
|
-
// Additional
|
|
52020
|
-
network_trending_pools: "get_network_trending_pools",
|
|
52021
|
-
multi_pools_data: "get_multi_pools",
|
|
52022
|
-
network_exchanges_list: "get_network_dexes",
|
|
52023
|
-
pair_chart_metadata: "get_pair_chart_metadata",
|
|
52024
|
-
token_liquidity_metadata: "get_token_liquidity_metadata",
|
|
52025
|
-
// DeFiLlama DEX
|
|
52026
|
-
dex_volumes_overview: "get_dex_volumes",
|
|
52027
|
-
dex_volume_specific: "get_dex_volume",
|
|
52028
|
-
dex_volumes_chain_specific: "get_dex_volumes_by_chain",
|
|
52029
|
-
options_trading_overview: "get_options_overview",
|
|
52030
|
-
options_trading_by_chain: "get_options_by_chain",
|
|
52031
|
-
options_protocol_summary: "get_options_protocol",
|
|
52032
|
-
// ============================================
|
|
52033
|
-
// Category 3: Portfolio & Wallet (14 tools)
|
|
52034
|
-
// ============================================
|
|
52035
|
-
// Codex
|
|
52036
|
-
fetch_wallet_balances: "get_wallet_balances",
|
|
52037
|
-
fetch_wallet_token_activity: "get_wallet_token_events",
|
|
52038
|
-
wallets_search_filter: "filter_wallets",
|
|
52039
|
-
token_wallets_filter: "filter_token_wallets",
|
|
52040
|
-
wallet_detailed_stats: "get_wallet_stats",
|
|
52041
|
-
wallet_chart_data: "get_wallet_chart",
|
|
52042
|
-
// ============================================
|
|
52043
|
-
// Category 4: Token & Contract Data (15 tools)
|
|
52044
|
-
// ============================================
|
|
52045
|
-
// GeckoTerminal
|
|
52046
|
-
address_networks_onchain_tokens_browser: "get_tokens_by_address",
|
|
52047
|
-
tokens_networks_onchain_info_browser: "get_token_info",
|
|
52048
|
-
tokens_networks_onchain_top_holders_browser: "get_token_top_holders",
|
|
52049
|
-
tokens_networks_onchain_holders_chart_browser: "get_token_holders_chart",
|
|
52050
|
-
// Codex
|
|
52051
|
-
retrieve_token_details: "get_token_details",
|
|
52052
|
-
fetch_multiple_tokens: "get_tokens",
|
|
52053
|
-
search_tokens_by_criteria: "filter_tokens",
|
|
52054
|
-
list_token_holders: "get_token_holders",
|
|
52055
|
-
calculate_top_holders_percentage: "get_top_holders_percentage",
|
|
52056
|
-
list_newest_token_contracts: "get_new_tokens",
|
|
52057
|
-
multi_tokens_data: "get_multi_tokens",
|
|
52058
|
-
tokens_recent_updates: "get_recently_updated_tokens",
|
|
52059
|
-
token_top_traders_stats: "get_token_top_traders",
|
|
52060
|
-
fetch_coin_metadata: "get_coin_metadata",
|
|
52061
|
-
// ============================================
|
|
52062
|
-
// Category 5: DeFi Protocol Analytics
|
|
52063
|
-
// ============================================
|
|
52064
|
-
// CoinGecko
|
|
52065
|
-
global_defi_data: "get_global_defi",
|
|
52066
|
-
// DeFiLlama
|
|
52067
|
-
defi_protocols_list: "get_defi_protocols",
|
|
52068
|
-
defi_protocol_details: "get_defi_protocol",
|
|
52069
|
-
protocol_tvl_current: "get_protocol_tvl",
|
|
52070
|
-
protocol_fees_data: "get_protocol_fees",
|
|
52071
|
-
blockchain_chains_list: "get_chains",
|
|
52072
|
-
chain_tvl_history: "get_chain_tvl_history",
|
|
52073
|
-
chains_tvl_historical_all: "get_chains_tvl_history",
|
|
52074
|
-
yield_pools_list: "get_yield_pools",
|
|
52075
|
-
yield_pool_details: "get_yield_pool_chart",
|
|
52076
|
-
yield_pool_chart_history: "get_yield_pool_chart",
|
|
52077
|
-
protocol_fees_overview: "get_fees_overview",
|
|
52078
|
-
chain_fees_overview: "get_chain_fees",
|
|
52079
|
-
// ============================================
|
|
52080
|
-
// Category 6: NFT Analytics (30 tools)
|
|
52081
|
-
// ============================================
|
|
52082
|
-
// CoinGecko NFTs
|
|
52083
|
-
id_nfts_browser: "get_nft",
|
|
52084
|
-
list_nfts_browser: "get_nfts",
|
|
52085
|
-
nfts_market_chart_browser: "get_nft_market_chart",
|
|
52086
|
-
// ============================================
|
|
52087
|
-
// Category 7: Security & Risk Analysis (8 tools)
|
|
52088
|
-
// ============================================
|
|
52089
|
-
// GoPlus (mostly compliant)
|
|
52090
|
-
get_token_security: "get_token_security",
|
|
52091
|
-
// Already compliant
|
|
52092
|
-
get_nft_security: "get_nft_security",
|
|
52093
|
-
// Already compliant
|
|
52094
|
-
check_malicious_address: "check_malicious_address",
|
|
52095
|
-
// Already compliant
|
|
52096
|
-
check_approval_security: "check_approval_security",
|
|
52097
|
-
// Already compliant
|
|
52098
|
-
get_user_approvals: "get_wallet_approvals",
|
|
52099
|
-
check_dapp_security: "check_dapp_security",
|
|
52100
|
-
// Already compliant
|
|
52101
|
-
detect_phishing_site: "check_phishing_site",
|
|
52102
|
-
decode_abi_data: "decode_abi",
|
|
52103
|
-
// ============================================
|
|
52104
|
-
// Category 8: Network & Infrastructure (12 tools)
|
|
52105
|
-
// ============================================
|
|
52106
|
-
// GeckoTerminal
|
|
52107
|
-
onchain_networks_browser: "get_networks",
|
|
52108
|
-
// Codex
|
|
52109
|
-
list_blockchain_networks: "get_networks_list",
|
|
52110
|
-
check_network_health: "get_network_status",
|
|
52111
|
-
fetch_network_metrics: "get_network_stats",
|
|
52112
|
-
// CoinGecko
|
|
52113
|
-
asset_platforms_browser: "get_asset_platforms",
|
|
52114
|
-
// Codex
|
|
52115
|
-
community_notes_data: "get_community_notes",
|
|
52116
|
-
monitor_system_updates: "get_system_changes",
|
|
52117
|
-
// CCXT
|
|
52118
|
-
exchange_system_status: "get_exchange_status",
|
|
52119
|
-
exchange_server_time: "get_exchange_time",
|
|
52120
|
-
exchange_markets_browser: "get_exchange_markets",
|
|
52121
|
-
exchange_currencies_browser: "get_exchange_currencies",
|
|
52122
|
-
// ============================================
|
|
52123
|
-
// Category 9: Search & Discovery (9 tools)
|
|
52124
|
-
// ============================================
|
|
52125
|
-
// CoinGecko
|
|
52126
|
-
search_browser: "search_all",
|
|
52127
|
-
search_trending_browser: "get_trending",
|
|
52128
|
-
coins_categories_browser: "get_categories",
|
|
52129
|
-
coins_list_browser: "get_coins_list",
|
|
52130
|
-
new_coins_list_browser: "get_new_coins",
|
|
52131
|
-
coins_categories_market_data: "get_categories_market_data",
|
|
52132
|
-
exchanges_list_simple: "get_exchanges_list",
|
|
52133
|
-
derivatives_exchanges_list: "get_derivatives_exchanges_list",
|
|
52134
|
-
// Codex
|
|
52135
|
-
event_labels_list: "get_event_labels"
|
|
52136
|
-
};
|
|
52137
|
-
var REVERSE_TOOL_NAME_MAPPINGS = Object.entries(TOOL_NAME_MAPPINGS).reduce(
|
|
52138
|
-
(acc, [legacy, standard]) => {
|
|
52139
|
-
acc[standard] = legacy;
|
|
52140
|
-
return acc;
|
|
52141
|
-
},
|
|
52142
|
-
{}
|
|
52143
|
-
);
|
|
52144
|
-
var COMPLIANT_TOOLS = [
|
|
52145
|
-
"get_token_security",
|
|
52146
|
-
"get_nft_security",
|
|
52147
|
-
"check_malicious_address",
|
|
52148
|
-
"check_approval_security",
|
|
52149
|
-
"check_dapp_security"
|
|
52150
|
-
];
|
|
52151
|
-
function getStandardName(legacyName) {
|
|
52152
|
-
return TOOL_NAME_MAPPINGS[legacyName] || legacyName;
|
|
52153
|
-
}
|
|
52154
|
-
function isLegacyName(name) {
|
|
52155
|
-
return name in TOOL_NAME_MAPPINGS && TOOL_NAME_MAPPINGS[name] !== name;
|
|
52156
|
-
}
|
|
52157
|
-
|
|
52158
|
-
// src/config/toolAliasSystem.ts
|
|
52159
|
-
var defaultConfig = {
|
|
52160
|
-
enableWarnings: true,
|
|
52161
|
-
enableTracking: true,
|
|
52162
|
-
strictMode: false
|
|
52163
|
-
};
|
|
52164
|
-
var config = { ...defaultConfig };
|
|
52165
|
-
var usageStats = {
|
|
52166
|
-
legacyUsage: {},
|
|
52167
|
-
standardUsage: {},
|
|
52168
|
-
lastUpdated: /* @__PURE__ */ new Date()
|
|
52169
|
-
};
|
|
52170
|
-
function logDeprecationWarning(legacyName, standardName) {
|
|
52171
|
-
if (!config.enableWarnings) return;
|
|
52172
|
-
const message = `[DEPRECATED] Tool "${legacyName}" is deprecated. Use "${standardName}" instead.`;
|
|
52173
|
-
if (config.warningHandler) {
|
|
52174
|
-
config.warningHandler(message, legacyName, standardName);
|
|
52175
|
-
} else {
|
|
52176
|
-
console.warn(`\x1B[33m${message}\x1B[0m`);
|
|
52177
|
-
}
|
|
52178
|
-
}
|
|
52179
|
-
function trackUsage(toolName, isLegacy) {
|
|
52180
|
-
if (!config.enableTracking) return;
|
|
52181
|
-
usageStats.lastUpdated = /* @__PURE__ */ new Date();
|
|
52182
|
-
if (isLegacy) {
|
|
52183
|
-
usageStats.legacyUsage[toolName] = (usageStats.legacyUsage[toolName] || 0) + 1;
|
|
52184
|
-
} else {
|
|
52185
|
-
usageStats.standardUsage[toolName] = (usageStats.standardUsage[toolName] || 0) + 1;
|
|
52186
|
-
}
|
|
52187
|
-
}
|
|
52188
|
-
function resolveToolName(requestedName) {
|
|
52189
|
-
if (isLegacyName(requestedName)) {
|
|
52190
|
-
const standardName = getStandardName(requestedName);
|
|
52191
|
-
logDeprecationWarning(requestedName, standardName);
|
|
52192
|
-
trackUsage(requestedName, true);
|
|
52193
|
-
return standardName;
|
|
52194
|
-
}
|
|
52195
|
-
if (requestedName in REVERSE_TOOL_NAME_MAPPINGS) {
|
|
52196
|
-
trackUsage(requestedName, false);
|
|
52197
|
-
return requestedName;
|
|
52198
|
-
}
|
|
52199
|
-
if (COMPLIANT_TOOLS.includes(requestedName)) {
|
|
52200
|
-
trackUsage(requestedName, false);
|
|
52201
|
-
return requestedName;
|
|
52202
|
-
}
|
|
52203
|
-
if (config.strictMode) {
|
|
52204
|
-
throw new Error(`Unknown tool: "${requestedName}"`);
|
|
52205
|
-
}
|
|
52206
|
-
return requestedName;
|
|
52207
|
-
}
|
|
52208
|
-
|
|
52209
51653
|
// src/utils/errorCodes.ts
|
|
52210
51654
|
var ERROR_DOC_BASE = "https://www.hiveintelligence.xyz/errors";
|
|
52211
51655
|
function entry(code, transports, meaning, nextAction, retryable = false) {
|
|
@@ -53018,7 +52462,7 @@ function isRecord2(value) {
|
|
|
53018
52462
|
}
|
|
53019
52463
|
function resolveEndpoint(endpoints, toolName) {
|
|
53020
52464
|
const requestedToolName = toolName ?? "";
|
|
53021
|
-
const resolvedToolName = requestedToolName
|
|
52465
|
+
const resolvedToolName = requestedToolName;
|
|
53022
52466
|
const endpoint = endpoints.find(
|
|
53023
52467
|
(item) => item.tool.name === resolvedToolName
|
|
53024
52468
|
);
|
|
@@ -53035,7 +52479,7 @@ function normalizeInvokeArgs(args) {
|
|
|
53035
52479
|
message: "No endpoint provided. Pass 'endpoint_name' (or 'endpoint') and optionally 'args'."
|
|
53036
52480
|
};
|
|
53037
52481
|
}
|
|
53038
|
-
const resolvedToolName =
|
|
52482
|
+
const resolvedToolName = requestedToolName;
|
|
53039
52483
|
let nestedArgs = args?.args;
|
|
53040
52484
|
if (typeof nestedArgs === "string") {
|
|
53041
52485
|
try {
|
|
@@ -53151,9 +52595,9 @@ function createHiveExecutionMetadata(endpoint, durationMs, runtimeStatus, source
|
|
|
53151
52595
|
observed_at: observedAt,
|
|
53152
52596
|
cache_age_ms: cacheAgeMs,
|
|
53153
52597
|
duration_ms: durationMs,
|
|
53154
|
-
// Markers from createSafeHandler (
|
|
53155
|
-
//
|
|
53156
|
-
//
|
|
52598
|
+
// Markers from createSafeHandler (fallback client, truncation) take
|
|
52599
|
+
// precedence over the caller-supplied defaults so the agent sees whether
|
|
52600
|
+
// data is live or fallback-tier.
|
|
53157
52601
|
cache_status: exec?.cacheStatus ?? "unknown",
|
|
53158
52602
|
source: effectiveSource,
|
|
53159
52603
|
origin_source: originSource,
|
|
@@ -54426,7 +53870,7 @@ function heroTools(endpoints, options = {}) {
|
|
|
54426
53870
|
'Chain name, for example "eth", "base", "arbitrum", or "solana". Defaults to eth for 0x addresses; Solana is auto-detected.'
|
|
54427
53871
|
),
|
|
54428
53872
|
include_spam: z.boolean().optional().describe(
|
|
54429
|
-
"Show likely spam airdrops (tokens with a URL or claim lure in the name, and on EVM chains tokens with no market price). Default false; the response says how many were hidden."
|
|
53873
|
+
"Show likely spam airdrops (tokens with a URL or claim lure in the name, and on EVM chains tokens with no market price or not listed on CoinGecko). Default false; the response says how many were hidden."
|
|
54430
53874
|
),
|
|
54431
53875
|
response_format: RESPONSE_FORMAT
|
|
54432
53876
|
});
|
|
@@ -54512,15 +53956,21 @@ function heroTools(endpoints, options = {}) {
|
|
|
54512
53956
|
address: tokenAddress,
|
|
54513
53957
|
balance,
|
|
54514
53958
|
usd_value: token.totalValueUsd ?? token.valueUsd ?? token.usd_value ?? (typeof token.totalValueUsdCents === "number" ? token.totalValueUsdCents / 100 : usdFromPrices(token, balance)),
|
|
54515
|
-
...token.h24_change_pct != null ? { h24_change_pct: token.h24_change_pct } : {}
|
|
53959
|
+
...token.h24_change_pct != null ? { h24_change_pct: token.h24_change_pct } : {},
|
|
53960
|
+
...token.coingecko_listed === false ? { coingecko_listed: false } : {}
|
|
54516
53961
|
};
|
|
54517
53962
|
});
|
|
54518
53963
|
const nonZero = summarized.filter(
|
|
54519
53964
|
(token) => !isRecord3(token) || token.balance !== "0"
|
|
54520
53965
|
);
|
|
54521
|
-
const isSpam = (token) => isRecord3(token) && token.address != null && (SPAM_LURE.test(`${token.name ?? ""} ${token.symbol ?? ""}`) || priced && token.usd_value == null);
|
|
53966
|
+
const isSpam = (token) => isRecord3(token) && token.address != null && (SPAM_LURE.test(`${token.name ?? ""} ${token.symbol ?? ""}`) || priced && token.usd_value == null || token.coingecko_listed === false);
|
|
54522
53967
|
const held = includeSpam ? nonZero : nonZero.filter((t) => !isSpam(t));
|
|
54523
53968
|
const hidden = nonZero.length - held.length;
|
|
53969
|
+
const total = payload.total_value_usd;
|
|
53970
|
+
const hiddenUsd = nonZero.filter((t) => !held.includes(t)).reduce(
|
|
53971
|
+
(sum, t) => sum + (isRecord3(t) && typeof t.usd_value === "number" ? t.usd_value : 0),
|
|
53972
|
+
0
|
|
53973
|
+
);
|
|
54524
53974
|
return {
|
|
54525
53975
|
address,
|
|
54526
53976
|
chain: chainLabel,
|
|
@@ -54528,7 +53978,7 @@ function heroTools(endpoints, options = {}) {
|
|
|
54528
53978
|
...hidden > 0 ? {
|
|
54529
53979
|
spam_hidden: {
|
|
54530
53980
|
count: hidden,
|
|
54531
|
-
reason: priced ? "no market price, or a URL/claim lure in the name" : "a URL/claim lure in the name",
|
|
53981
|
+
reason: priced ? "no market price, not listed on CoinGecko, or a URL/claim lure in the name" : "a URL/claim lure in the name",
|
|
54532
53982
|
note: "Likely spam airdrops; pass include_spam=true to show them."
|
|
54533
53983
|
}
|
|
54534
53984
|
} : {},
|
|
@@ -54537,7 +53987,8 @@ function heroTools(endpoints, options = {}) {
|
|
|
54537
53987
|
note: `Showing the first ${MAX_CONCISE_TOKENS} of ${held.length} held tokens (zero balances omitted). Use response_format=detailed for the full provider payload.`
|
|
54538
53988
|
} : summarized.length > nonZero.length ? {
|
|
54539
53989
|
note: `${summarized.length - nonZero.length} zero-balance tokens omitted. Use response_format=detailed for the full provider payload.`
|
|
54540
|
-
} : {}
|
|
53990
|
+
} : {},
|
|
53991
|
+
...typeof total === "number" ? { total_value_usd: Math.round((total - hiddenUsd) * 100) / 100 } : {}
|
|
54541
53992
|
};
|
|
54542
53993
|
};
|
|
54543
53994
|
const coingeckoBalances = (payload) => {
|
|
@@ -54553,7 +54004,9 @@ function heroTools(endpoints, options = {}) {
|
|
|
54553
54004
|
balance: row.balance ?? null,
|
|
54554
54005
|
decimals: 0,
|
|
54555
54006
|
usd_value: toNumber(row.value_usd),
|
|
54556
|
-
h24_change_pct: toNumber(row.h24_price_change_percentage)
|
|
54007
|
+
h24_change_pct: toNumber(row.h24_price_change_percentage),
|
|
54008
|
+
// Only an explicit null means unlisted; a missing field fails open.
|
|
54009
|
+
coingecko_listed: row.coingecko_coin_id !== null
|
|
54557
54010
|
}))
|
|
54558
54011
|
};
|
|
54559
54012
|
};
|
|
@@ -54606,13 +54059,13 @@ function heroTools(endpoints, options = {}) {
|
|
|
54606
54059
|
per_page: 100
|
|
54607
54060
|
}, "get_wallet_portfolio");
|
|
54608
54061
|
if (!network || "hive" in result3 && result3.ok) {
|
|
54609
|
-
return respond(
|
|
54610
|
-
|
|
54611
|
-
|
|
54612
|
-
|
|
54613
|
-
|
|
54614
|
-
|
|
54615
|
-
|
|
54062
|
+
return respond(
|
|
54063
|
+
result3,
|
|
54064
|
+
format,
|
|
54065
|
+
(payload) => trimWalletPortfolio(address, normalized, includeSpam, true)(
|
|
54066
|
+
coingeckoBalances(payload)
|
|
54067
|
+
)
|
|
54068
|
+
);
|
|
54616
54069
|
}
|
|
54617
54070
|
fallbackNote = "CoinGecko wallet balances failed for this call; served from Alchemy.";
|
|
54618
54071
|
}
|
|
@@ -57301,6 +56754,123 @@ async function executeEndpointWithRouteFallback(endpoints, endpoint, args, conte
|
|
|
57301
56754
|
// src/health/scheduledCanaries.ts
|
|
57302
56755
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
57303
56756
|
|
|
56757
|
+
// src/utils/redis.ts
|
|
56758
|
+
import Redis from "ioredis";
|
|
56759
|
+
var client = null;
|
|
56760
|
+
var available = false;
|
|
56761
|
+
function logRedisInfo(message) {
|
|
56762
|
+
process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO]: ${message}
|
|
56763
|
+
`);
|
|
56764
|
+
}
|
|
56765
|
+
function getRedisClient() {
|
|
56766
|
+
return client;
|
|
56767
|
+
}
|
|
56768
|
+
function isRedisAvailable() {
|
|
56769
|
+
return available;
|
|
56770
|
+
}
|
|
56771
|
+
async function waitForRedisAvailability(timeoutMs = 1e4) {
|
|
56772
|
+
if (!client) return false;
|
|
56773
|
+
if (available) return true;
|
|
56774
|
+
const boundedTimeoutMs = Math.max(1, Math.min(timeoutMs, 3e4));
|
|
56775
|
+
const current = client;
|
|
56776
|
+
return new Promise((resolve) => {
|
|
56777
|
+
let settled = false;
|
|
56778
|
+
const finish = (ready) => {
|
|
56779
|
+
if (settled) return;
|
|
56780
|
+
settled = true;
|
|
56781
|
+
clearTimeout(timer);
|
|
56782
|
+
current.off("ready", onReady);
|
|
56783
|
+
current.off("end", onEnd);
|
|
56784
|
+
resolve(ready);
|
|
56785
|
+
};
|
|
56786
|
+
const onReady = () => finish(true);
|
|
56787
|
+
const onEnd = () => finish(false);
|
|
56788
|
+
const timer = setTimeout(() => finish(available), boundedTimeoutMs);
|
|
56789
|
+
current.once("ready", onReady);
|
|
56790
|
+
current.once("end", onEnd);
|
|
56791
|
+
if (available) finish(true);
|
|
56792
|
+
});
|
|
56793
|
+
}
|
|
56794
|
+
async function closeRedisClient() {
|
|
56795
|
+
if (!client) return;
|
|
56796
|
+
const current = client;
|
|
56797
|
+
client = null;
|
|
56798
|
+
available = false;
|
|
56799
|
+
try {
|
|
56800
|
+
await Promise.race([
|
|
56801
|
+
current.quit(),
|
|
56802
|
+
new Promise(
|
|
56803
|
+
(_, reject) => setTimeout(() => reject(new Error("Redis quit timed out")), 5e3)
|
|
56804
|
+
)
|
|
56805
|
+
]);
|
|
56806
|
+
logRedisInfo("[redis] Connection closed gracefully");
|
|
56807
|
+
} catch (err) {
|
|
56808
|
+
secureLogger.error(
|
|
56809
|
+
"[redis] Error closing connection, forcing disconnect",
|
|
56810
|
+
err,
|
|
56811
|
+
{}
|
|
56812
|
+
);
|
|
56813
|
+
current.disconnect();
|
|
56814
|
+
}
|
|
56815
|
+
}
|
|
56816
|
+
var DEGRADED_AFTER_ATTEMPTS = 3;
|
|
56817
|
+
var MAX_RECONNECT_DELAY_MS = 3e3;
|
|
56818
|
+
function redisRetryStrategy(times) {
|
|
56819
|
+
if (times === DEGRADED_AFTER_ATTEMPTS) {
|
|
56820
|
+
secureLogger.warn(
|
|
56821
|
+
`[redis] Connection failed after ${DEGRADED_AFTER_ATTEMPTS} retries, falling back to in-memory while reconnection continues`,
|
|
56822
|
+
{}
|
|
56823
|
+
);
|
|
56824
|
+
available = false;
|
|
56825
|
+
}
|
|
56826
|
+
return Math.min(times * 100, MAX_RECONNECT_DELAY_MS);
|
|
56827
|
+
}
|
|
56828
|
+
function redisClientOptions() {
|
|
56829
|
+
return {
|
|
56830
|
+
maxRetriesPerRequest: 3,
|
|
56831
|
+
retryStrategy: redisRetryStrategy,
|
|
56832
|
+
lazyConnect: true
|
|
56833
|
+
};
|
|
56834
|
+
}
|
|
56835
|
+
var redisUrl = getEnvVar("REDIS_URL");
|
|
56836
|
+
function isRedisConfigured() {
|
|
56837
|
+
return Boolean(redisUrl);
|
|
56838
|
+
}
|
|
56839
|
+
if (redisUrl) {
|
|
56840
|
+
try {
|
|
56841
|
+
client = new Redis(redisUrl, redisClientOptions());
|
|
56842
|
+
client.connect().then(() => {
|
|
56843
|
+
available = true;
|
|
56844
|
+
logRedisInfo("[redis] Connected successfully");
|
|
56845
|
+
}).catch((err) => {
|
|
56846
|
+
secureLogger.warn("[redis] Connection failed", {
|
|
56847
|
+
error: err.message
|
|
56848
|
+
});
|
|
56849
|
+
available = false;
|
|
56850
|
+
});
|
|
56851
|
+
client.on("error", (err) => {
|
|
56852
|
+
secureLogger.warn("[redis] Error", { error: err.message });
|
|
56853
|
+
available = false;
|
|
56854
|
+
});
|
|
56855
|
+
client.on("ready", () => {
|
|
56856
|
+
available = true;
|
|
56857
|
+
});
|
|
56858
|
+
const gracefulShutdown = async (signal) => {
|
|
56859
|
+
logRedisInfo(`[redis] Received ${signal}, closing connection...`);
|
|
56860
|
+
await closeRedisClient();
|
|
56861
|
+
};
|
|
56862
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
56863
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
56864
|
+
} catch (err) {
|
|
56865
|
+
secureLogger.warn("[redis] Failed to initialise", {
|
|
56866
|
+
error: String(err)
|
|
56867
|
+
});
|
|
56868
|
+
client = null;
|
|
56869
|
+
}
|
|
56870
|
+
} else {
|
|
56871
|
+
logRedisInfo("[redis] No REDIS_URL provided, using in-memory fallbacks");
|
|
56872
|
+
}
|
|
56873
|
+
|
|
57304
56874
|
// src/health/canaryHistory.ts
|
|
57305
56875
|
var HEALTH_EVIDENCE_STATUSES = [
|
|
57306
56876
|
"unknown",
|
|
@@ -58987,16 +58557,16 @@ function sameScopes(left, right) {
|
|
|
58987
58557
|
return left.length === right.length && right.every((scope) => left.includes(scope));
|
|
58988
58558
|
}
|
|
58989
58559
|
var HiveOAuthProvider = class {
|
|
58990
|
-
constructor(
|
|
58991
|
-
this.config =
|
|
58560
|
+
constructor(config, storage2, options = {}) {
|
|
58561
|
+
this.config = config;
|
|
58992
58562
|
this.storage = storage2;
|
|
58993
|
-
if (!
|
|
58563
|
+
if (!config.configured || !config.issuerUrl || !config.resourceUrl || !config.consentUrl) {
|
|
58994
58564
|
throw new Error("Cannot construct OAuth provider from incomplete configuration.");
|
|
58995
58565
|
}
|
|
58996
58566
|
this.clientsStore = new HiveOAuthClientsStore({
|
|
58997
58567
|
storage: storage2,
|
|
58998
|
-
dcrClientTtlSeconds:
|
|
58999
|
-
cimdAllowedHosts:
|
|
58568
|
+
dcrClientTtlSeconds: config.dcrClientTtlSeconds,
|
|
58569
|
+
cimdAllowedHosts: config.cimdAllowedHosts,
|
|
59000
58570
|
fetcher: options.fetcher
|
|
59001
58571
|
});
|
|
59002
58572
|
}
|
|
@@ -59745,11 +59315,11 @@ function elapsed(started) {
|
|
|
59745
59315
|
function check(name, status, started, detail) {
|
|
59746
59316
|
return { name, status, duration: elapsed(started), detail };
|
|
59747
59317
|
}
|
|
59748
|
-
function healthResult(started, status,
|
|
59318
|
+
function healthResult(started, status, config, persistentStorage, checks) {
|
|
59749
59319
|
return {
|
|
59750
59320
|
status,
|
|
59751
|
-
enabled:
|
|
59752
|
-
configured:
|
|
59321
|
+
enabled: config.enabled,
|
|
59322
|
+
configured: config.configured,
|
|
59753
59323
|
persistentStorage,
|
|
59754
59324
|
checks,
|
|
59755
59325
|
passed: checks.filter((entry2) => entry2.status === "passed").length,
|
|
@@ -60101,6 +59671,7 @@ function parsePositiveInteger(value, fallback) {
|
|
|
60101
59671
|
function sleep4(ms) {
|
|
60102
59672
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60103
59673
|
}
|
|
59674
|
+
var GOPLUS_CALL_BUDGET_MS = 45e3;
|
|
60104
59675
|
function chainIdPathSegment(value) {
|
|
60105
59676
|
return assertDecimalPathSegment(value, "chainId");
|
|
60106
59677
|
}
|
|
@@ -60247,6 +59818,27 @@ var GoPlusClient = class {
|
|
|
60247
59818
|
* @internal
|
|
60248
59819
|
*/
|
|
60249
59820
|
async request(endpoint, params, method = "GET") {
|
|
59821
|
+
let timer;
|
|
59822
|
+
const budget = new Promise((_, reject) => {
|
|
59823
|
+
timer = setTimeout(
|
|
59824
|
+
() => reject(
|
|
59825
|
+
new Error(
|
|
59826
|
+
`GoPlus ${endpoint} timed out after ${GOPLUS_CALL_BUDGET_MS / 1e3}s; nothing was returned.`
|
|
59827
|
+
)
|
|
59828
|
+
),
|
|
59829
|
+
GOPLUS_CALL_BUDGET_MS
|
|
59830
|
+
);
|
|
59831
|
+
});
|
|
59832
|
+
try {
|
|
59833
|
+
return await Promise.race([
|
|
59834
|
+
this.send(endpoint, params, method),
|
|
59835
|
+
budget
|
|
59836
|
+
]);
|
|
59837
|
+
} finally {
|
|
59838
|
+
clearTimeout(timer);
|
|
59839
|
+
}
|
|
59840
|
+
}
|
|
59841
|
+
async send(endpoint, params, method) {
|
|
60250
59842
|
const startTime = Date.now();
|
|
60251
59843
|
try {
|
|
60252
59844
|
let url = endpoint;
|
|
@@ -60851,9 +60443,9 @@ var CCXTClient = class {
|
|
|
60851
60443
|
throw new Error("Exchange ID is required");
|
|
60852
60444
|
}
|
|
60853
60445
|
const ccxt = await loadCcxt();
|
|
60854
|
-
const
|
|
60855
|
-
if (this.exchanges.has(
|
|
60856
|
-
return this.exchanges.get(
|
|
60446
|
+
const cacheKey = `${exchangeId}`;
|
|
60447
|
+
if (this.exchanges.has(cacheKey)) {
|
|
60448
|
+
return this.exchanges.get(cacheKey);
|
|
60857
60449
|
}
|
|
60858
60450
|
if (REMOVED_CCXT_EXCHANGES.has(exchangeId.toLowerCase())) {
|
|
60859
60451
|
throw new Error(removedVenueMessage(exchangeId));
|
|
@@ -60869,7 +60461,7 @@ var CCXTClient = class {
|
|
|
60869
60461
|
// Prevent API rate limit violations
|
|
60870
60462
|
...options
|
|
60871
60463
|
});
|
|
60872
|
-
this.exchanges.set(
|
|
60464
|
+
this.exchanges.set(cacheKey, exchange);
|
|
60873
60465
|
secureLogger.debug("Exchange initialized", {
|
|
60874
60466
|
exchangeId,
|
|
60875
60467
|
hasRateLimit: true
|
|
@@ -63053,14 +62645,14 @@ function firstString(value, keys) {
|
|
|
63053
62645
|
}
|
|
63054
62646
|
return void 0;
|
|
63055
62647
|
}
|
|
63056
|
-
function getCachedDynamicArgs(
|
|
63057
|
-
const cached = dynamicProbeArgCache.get(
|
|
62648
|
+
function getCachedDynamicArgs(cacheKey, resolver) {
|
|
62649
|
+
const cached = dynamicProbeArgCache.get(cacheKey);
|
|
63058
62650
|
if (cached) return cached;
|
|
63059
62651
|
const promise = resolver().catch((err) => {
|
|
63060
|
-
dynamicProbeArgCache.delete(
|
|
62652
|
+
dynamicProbeArgCache.delete(cacheKey);
|
|
63061
62653
|
throw err;
|
|
63062
62654
|
});
|
|
63063
|
-
dynamicProbeArgCache.set(
|
|
62655
|
+
dynamicProbeArgCache.set(cacheKey, promise);
|
|
63064
62656
|
return promise;
|
|
63065
62657
|
}
|
|
63066
62658
|
var hiveCanarySubjectContextPromise;
|
|
@@ -64996,7 +64588,7 @@ var refreshing = null;
|
|
|
64996
64588
|
var testOverrides = null;
|
|
64997
64589
|
async function refreshWithCanary() {
|
|
64998
64590
|
const now = Date.now();
|
|
64999
|
-
const
|
|
64591
|
+
const config = buildConfigSnapshot(now);
|
|
65000
64592
|
try {
|
|
65001
64593
|
const history = await getProviderCanaryHistory(1);
|
|
65002
64594
|
const latest = history.evidence.state === "present" ? history.latest : null;
|
|
@@ -65009,20 +64601,20 @@ async function refreshWithCanary() {
|
|
|
65009
64601
|
const observed = availabilityFromRuntimeStatus(
|
|
65010
64602
|
api.runtimeStatus ?? (api.status === "passed" ? "ok" : api.status === "inactive" ? "degraded" : "failing")
|
|
65011
64603
|
);
|
|
65012
|
-
|
|
65013
|
-
|
|
64604
|
+
config.byProviderName[descriptor.name] = worseOf(
|
|
64605
|
+
config.byProviderName[descriptor.name] ?? "ok",
|
|
65014
64606
|
observed
|
|
65015
64607
|
);
|
|
65016
64608
|
}
|
|
65017
|
-
|
|
65018
|
-
|
|
64609
|
+
config.source = "config+canary";
|
|
64610
|
+
config.canaryObservedAt = latest.observedAt ?? latest.timestamp ?? null;
|
|
65019
64611
|
}
|
|
65020
64612
|
} catch (error) {
|
|
65021
64613
|
secureLogger.warn("Provider availability canary overlay failed", {
|
|
65022
64614
|
error: error instanceof Error ? error.message : String(error)
|
|
65023
64615
|
});
|
|
65024
64616
|
}
|
|
65025
|
-
cachedSnapshot =
|
|
64617
|
+
cachedSnapshot = config;
|
|
65026
64618
|
}
|
|
65027
64619
|
function kickRefresh() {
|
|
65028
64620
|
if (refreshing) return;
|
|
@@ -67867,11 +67459,6 @@ export {
|
|
|
67867
67459
|
trackServerEvent,
|
|
67868
67460
|
trackCliCommand,
|
|
67869
67461
|
trackOAuthFirstMaterialReceipt,
|
|
67870
|
-
getRedisClient,
|
|
67871
|
-
isRedisAvailable,
|
|
67872
|
-
waitForRedisAvailability,
|
|
67873
|
-
closeRedisClient,
|
|
67874
|
-
isRedisConfigured,
|
|
67875
67462
|
PROVIDER_CATALOG,
|
|
67876
67463
|
getProviderRuntimeStatus,
|
|
67877
67464
|
READ_ENDPOINT_INVOKER,
|
|
@@ -67896,6 +67483,11 @@ export {
|
|
|
67896
67483
|
HERO_TOOL_NAMES,
|
|
67897
67484
|
heroTools,
|
|
67898
67485
|
TASK_TOOLSETS,
|
|
67486
|
+
getRedisClient,
|
|
67487
|
+
isRedisAvailable,
|
|
67488
|
+
waitForRedisAvailability,
|
|
67489
|
+
closeRedisClient,
|
|
67490
|
+
isRedisConfigured,
|
|
67899
67491
|
OAUTH_SCOPES,
|
|
67900
67492
|
MCP_BASIC_SCOPES,
|
|
67901
67493
|
MCP_RESOURCE_SCOPES,
|