hive-intelligence 1.15.0 → 1.16.0
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/build/{api-client-POBN6Y5S.js → api-client-MK3CVNCH.js} +2 -2
- package/build/{auth-6XVL5CE3.js → auth-TZQC54EJ.js} +1 -1
- package/build/{call-args-BUB6YNHW.js → call-args-4YRVKOLV.js} +2 -2
- package/build/{chunk-ZSPPJW4G.js → chunk-4U4IL5KA.js} +15 -1
- package/build/{chunk-KQVPKTEO.js → chunk-AVTIJGWS.js} +2 -2
- package/build/{chunk-762ZUJ4Q.js → chunk-B53GNIWW.js} +1 -1
- package/build/chunk-MYSS5SBE.js +71 -0
- package/build/{chunk-YLHNUAFT.js → chunk-O5YKCM67.js} +22 -6
- package/build/{chunk-APBLB62S.js → chunk-PODCJTBV.js} +1 -1
- package/build/{chunk-GNZGLVFE.js → chunk-QSKFAT7Z.js} +466 -442
- package/build/{chunk-RNVZIPNY.js → chunk-VO6NWVJD.js} +1 -1
- package/build/{chunk-AZFOTKS2.js → chunk-WZ2NMSV3.js} +1 -1
- package/build/cli.js +31 -29
- package/build/{doctor-25WPHR4J.js → doctor-UKOGXRSW.js} +4 -4
- package/build/{errors-YQAVCXXO.js → errors-BPXK3KCR.js} +1 -1
- package/build/{feedback-G2DFCCI6.js → feedback-6XX2R75U.js} +2 -2
- package/build/{init-all-UDWHV2ER.js → init-all-XDQRGJ3D.js} +1 -1
- package/build/{mcpServer-O4KXRE62.js → mcpServer-77FPS534.js} +2 -1
- package/build/monitor-worker.js +3 -2
- package/build/release.json +4 -4
- package/build/{routing-4VKAVRYR.js → routing-S7DPEROC.js} +2 -2
- package/build/{serve-V2KPPJCD.js → serve-2NIEUCJN.js} +6 -4
- package/build/server.js +112 -105
- package/build/stdio.js +2 -1
- package/build/{tools-K2P77L4T.js → tools-NSHQSUIK.js} +5 -5
- package/build/{uninstall-I6ERJ2ED.js → uninstall-CECLA5YZ.js} +2 -2
- package/build/{watch-BUSEPVDM.js → watch-4VHBLAL6.js} +3 -3
- package/package.json +5 -15
|
@@ -5,63 +5,20 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
OAUTH_FIRST_MATERIAL_RECEIPT_EVENT
|
|
7
7
|
} from "./chunk-EPF36Q3Z.js";
|
|
8
|
+
import {
|
|
9
|
+
getCsvEnv,
|
|
10
|
+
getEnvVar,
|
|
11
|
+
getLogLevel,
|
|
12
|
+
getNodeEnv,
|
|
13
|
+
getRequiredEnvVar,
|
|
14
|
+
hasEnvVars,
|
|
15
|
+
loadEnvFile
|
|
16
|
+
} from "./chunk-MYSS5SBE.js";
|
|
8
17
|
import {
|
|
9
18
|
SERVER_NAME,
|
|
10
19
|
SERVER_VERSION
|
|
11
20
|
} from "./chunk-ZXKFJQDE.js";
|
|
12
21
|
|
|
13
|
-
// src/mcpServer.ts
|
|
14
|
-
import dotenv from "dotenv";
|
|
15
|
-
|
|
16
|
-
// src/config/env.ts
|
|
17
|
-
import { z } from "zod";
|
|
18
|
-
var nodeEnvSchema = z.enum(["development", "production", "test"]).catch("development");
|
|
19
|
-
var logLevelSchema = z.enum(["debug", "info", "warn", "error"]).catch("info");
|
|
20
|
-
var portSchema = z.coerce.number().int().min(1).max(65535);
|
|
21
|
-
var rateLimitMaxSchema = z.coerce.number().int().min(1).max(1e4);
|
|
22
|
-
function getEnvVar(name) {
|
|
23
|
-
const value = process.env[name]?.trim();
|
|
24
|
-
return value ? value : void 0;
|
|
25
|
-
}
|
|
26
|
-
function getRequiredEnvVar(name, message) {
|
|
27
|
-
const value = getEnvVar(name);
|
|
28
|
-
if (!value) {
|
|
29
|
-
throw new Error(message ?? `Missing required environment variable: ${name}`);
|
|
30
|
-
}
|
|
31
|
-
return value;
|
|
32
|
-
}
|
|
33
|
-
function hasEnvVars(...names) {
|
|
34
|
-
return names.every((name) => Boolean(getEnvVar(name)));
|
|
35
|
-
}
|
|
36
|
-
function getCsvEnv(name) {
|
|
37
|
-
const value = getEnvVar(name);
|
|
38
|
-
if (!value) return [];
|
|
39
|
-
return value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
40
|
-
}
|
|
41
|
-
function getNodeEnv() {
|
|
42
|
-
return nodeEnvSchema.parse(process.env.NODE_ENV);
|
|
43
|
-
}
|
|
44
|
-
function isProduction() {
|
|
45
|
-
return getNodeEnv() === "production";
|
|
46
|
-
}
|
|
47
|
-
function getLogLevel() {
|
|
48
|
-
return logLevelSchema.parse(process.env.LOG_LEVEL);
|
|
49
|
-
}
|
|
50
|
-
function getPort() {
|
|
51
|
-
return portSchema.parse(process.env.PORT ?? 8080);
|
|
52
|
-
}
|
|
53
|
-
function getRateLimitMax() {
|
|
54
|
-
return rateLimitMaxSchema.parse(process.env.RATE_LIMIT_MAX ?? 30);
|
|
55
|
-
}
|
|
56
|
-
function getCredentialedRateLimitMax() {
|
|
57
|
-
return rateLimitMaxSchema.parse(
|
|
58
|
-
process.env.CREDENTIALED_RATE_LIMIT_MAX ?? 1500
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
function getCorsAllowedOrigins() {
|
|
62
|
-
return getCsvEnv("CORS_ALLOWED_ORIGINS");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
22
|
// src/tools/types.ts
|
|
66
23
|
function asTextContentResult(result2, isError = false) {
|
|
67
24
|
const jsonString = JSON.stringify(result2);
|
|
@@ -18634,65 +18591,161 @@ var wrapper = {
|
|
|
18634
18591
|
]
|
|
18635
18592
|
};
|
|
18636
18593
|
|
|
18637
|
-
// src/
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
|
|
18641
|
-
|
|
18642
|
-
|
|
18643
|
-
|
|
18644
|
-
|
|
18645
|
-
|
|
18646
|
-
}
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
18650
|
-
|
|
18651
|
-
|
|
18652
|
-
);
|
|
18653
|
-
|
|
18654
|
-
|
|
18655
|
-
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
|
|
18659
|
-
|
|
18660
|
-
|
|
18661
|
-
|
|
18662
|
-
})
|
|
18663
|
-
|
|
18664
|
-
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18685
|
-
|
|
18686
|
-
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
|
|
18594
|
+
// src/utils/fetchClient.ts
|
|
18595
|
+
var HttpError = class extends Error {
|
|
18596
|
+
config;
|
|
18597
|
+
constructor(message, config2, code, response) {
|
|
18598
|
+
super(message);
|
|
18599
|
+
this.name = "HttpError";
|
|
18600
|
+
this.config = config2;
|
|
18601
|
+
if (code) this.code = code;
|
|
18602
|
+
if (response) this.response = response;
|
|
18603
|
+
}
|
|
18604
|
+
};
|
|
18605
|
+
function encode(value) {
|
|
18606
|
+
return encodeURIComponent(value).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+");
|
|
18607
|
+
}
|
|
18608
|
+
function appendParam(pairs, key, value) {
|
|
18609
|
+
if (value === null || value === void 0) return;
|
|
18610
|
+
if (Array.isArray(value)) {
|
|
18611
|
+
for (const item of value) appendParam(pairs, `${key}[]`, item);
|
|
18612
|
+
} else if (value instanceof Date) {
|
|
18613
|
+
pairs.push(`${encode(key)}=${encode(value.toISOString())}`);
|
|
18614
|
+
} else if (typeof value === "object") {
|
|
18615
|
+
for (const [sub, item] of Object.entries(value)) {
|
|
18616
|
+
appendParam(pairs, `${key}[${sub}]`, item);
|
|
18617
|
+
}
|
|
18618
|
+
} else {
|
|
18619
|
+
pairs.push(`${encode(key)}=${encode(String(value))}`);
|
|
18620
|
+
}
|
|
18621
|
+
}
|
|
18622
|
+
function buildUrl(baseURL, url, params) {
|
|
18623
|
+
const full = !baseURL || /^[a-z][a-z\d+.-]*:\/\//i.test(url) ? url : url ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : baseURL;
|
|
18624
|
+
const pairs = [];
|
|
18625
|
+
for (const [key, value] of Object.entries(params ?? {})) {
|
|
18626
|
+
appendParam(pairs, key, value);
|
|
18627
|
+
}
|
|
18628
|
+
if (pairs.length === 0) return full;
|
|
18629
|
+
return `${full}${full.includes("?") ? "&" : "?"}${pairs.join("&")}`;
|
|
18630
|
+
}
|
|
18631
|
+
var UNDICI_CODES = {
|
|
18632
|
+
UND_ERR_CONNECT_TIMEOUT: "ETIMEDOUT",
|
|
18633
|
+
UND_ERR_HEADERS_TIMEOUT: "ETIMEDOUT",
|
|
18634
|
+
UND_ERR_BODY_TIMEOUT: "ETIMEDOUT",
|
|
18635
|
+
UND_ERR_SOCKET: "ECONNRESET"
|
|
18636
|
+
};
|
|
18637
|
+
function networkError(error, timedOut, timeout, config2) {
|
|
18638
|
+
if (timedOut) {
|
|
18639
|
+
return new HttpError(`timeout of ${timeout}ms exceeded`, config2, "ECONNABORTED");
|
|
18640
|
+
}
|
|
18641
|
+
const cause = error?.cause;
|
|
18642
|
+
const rawCode = cause?.code;
|
|
18643
|
+
const code = (rawCode && UNDICI_CODES[rawCode]) ?? rawCode ?? "ERR_NETWORK";
|
|
18644
|
+
return new HttpError(cause?.message || rawCode || "Network Error", config2, code);
|
|
18645
|
+
}
|
|
18646
|
+
async function readBody(response, maxContentLength, config2, onChunk) {
|
|
18647
|
+
if (!response.body) return "";
|
|
18648
|
+
const reader = response.body.getReader();
|
|
18649
|
+
const chunks = [];
|
|
18650
|
+
let size = 0;
|
|
18651
|
+
for (; ; ) {
|
|
18652
|
+
const { done, value } = await reader.read();
|
|
18653
|
+
if (done) break;
|
|
18654
|
+
onChunk();
|
|
18655
|
+
size += value.byteLength;
|
|
18656
|
+
if (maxContentLength && size > maxContentLength) {
|
|
18657
|
+
await reader.cancel();
|
|
18658
|
+
throw new HttpError(
|
|
18659
|
+
`maxContentLength size of ${maxContentLength} exceeded`,
|
|
18660
|
+
config2,
|
|
18661
|
+
"ERR_BAD_RESPONSE"
|
|
18662
|
+
);
|
|
18663
|
+
}
|
|
18664
|
+
chunks.push(value);
|
|
18693
18665
|
}
|
|
18694
|
-
|
|
18695
|
-
|
|
18666
|
+
return new TextDecoder().decode(Buffer.concat(chunks));
|
|
18667
|
+
}
|
|
18668
|
+
function parseBody(text) {
|
|
18669
|
+
if (!text) return text;
|
|
18670
|
+
try {
|
|
18671
|
+
return JSON.parse(text);
|
|
18672
|
+
} catch {
|
|
18673
|
+
return text;
|
|
18674
|
+
}
|
|
18675
|
+
}
|
|
18676
|
+
function createFetchClient(options = {}) {
|
|
18677
|
+
async function request(method, url, data, config2 = {}) {
|
|
18678
|
+
const info = { method, url };
|
|
18679
|
+
const timeout = config2.timeout ?? options.timeout ?? 0;
|
|
18680
|
+
const controller = new AbortController();
|
|
18681
|
+
let timedOut = false;
|
|
18682
|
+
let timer;
|
|
18683
|
+
const armTimeout = () => {
|
|
18684
|
+
clearTimeout(timer);
|
|
18685
|
+
if (timeout <= 0) return;
|
|
18686
|
+
timer = setTimeout(() => {
|
|
18687
|
+
timedOut = true;
|
|
18688
|
+
controller.abort();
|
|
18689
|
+
}, timeout);
|
|
18690
|
+
};
|
|
18691
|
+
armTimeout();
|
|
18692
|
+
try {
|
|
18693
|
+
options.onRequest?.({ method, url, data });
|
|
18694
|
+
const headers = {
|
|
18695
|
+
Accept: "application/json, text/plain, */*",
|
|
18696
|
+
...options.headers,
|
|
18697
|
+
...config2.headers
|
|
18698
|
+
};
|
|
18699
|
+
let body;
|
|
18700
|
+
if (data !== void 0) {
|
|
18701
|
+
body = typeof data === "string" ? data : JSON.stringify(data);
|
|
18702
|
+
const hasContentType = Object.keys(headers).some(
|
|
18703
|
+
(name) => name.toLowerCase() === "content-type"
|
|
18704
|
+
);
|
|
18705
|
+
if (!hasContentType) headers["Content-Type"] = "application/json";
|
|
18706
|
+
}
|
|
18707
|
+
let text;
|
|
18708
|
+
let res;
|
|
18709
|
+
try {
|
|
18710
|
+
res = await fetch(buildUrl(options.baseURL, url, config2.params), {
|
|
18711
|
+
method: method.toUpperCase(),
|
|
18712
|
+
headers,
|
|
18713
|
+
body,
|
|
18714
|
+
signal: controller.signal
|
|
18715
|
+
});
|
|
18716
|
+
armTimeout();
|
|
18717
|
+
text = await readBody(res, options.maxContentLength, info, armTimeout);
|
|
18718
|
+
} catch (error) {
|
|
18719
|
+
if (error instanceof HttpError) throw error;
|
|
18720
|
+
throw networkError(error, timedOut, timeout, info);
|
|
18721
|
+
}
|
|
18722
|
+
const response = {
|
|
18723
|
+
data: parseBody(text),
|
|
18724
|
+
status: res.status,
|
|
18725
|
+
headers: Object.fromEntries(res.headers)
|
|
18726
|
+
};
|
|
18727
|
+
if (res.status < 200 || res.status >= 300) {
|
|
18728
|
+
throw new HttpError(
|
|
18729
|
+
`Request failed with status code ${res.status}`,
|
|
18730
|
+
info,
|
|
18731
|
+
res.status < 500 ? "ERR_BAD_REQUEST" : "ERR_BAD_RESPONSE",
|
|
18732
|
+
response
|
|
18733
|
+
);
|
|
18734
|
+
}
|
|
18735
|
+
return response;
|
|
18736
|
+
} catch (error) {
|
|
18737
|
+
options.onError?.(error);
|
|
18738
|
+
throw error;
|
|
18739
|
+
} finally {
|
|
18740
|
+
clearTimeout(timer);
|
|
18741
|
+
}
|
|
18742
|
+
}
|
|
18743
|
+
return {
|
|
18744
|
+
get: (url, config2) => request("get", url, void 0, config2),
|
|
18745
|
+
post: (url, data, config2) => request("post", url, data, config2),
|
|
18746
|
+
put: (url, data, config2) => request("put", url, data, config2),
|
|
18747
|
+
delete: (url, config2) => request("delete", url, void 0, config2)
|
|
18748
|
+
};
|
|
18696
18749
|
}
|
|
18697
18750
|
|
|
18698
18751
|
// src/tools/defillamaTools/api/defillama.ts
|
|
@@ -18701,69 +18754,60 @@ var DeFiLlamaAPI = class {
|
|
|
18701
18754
|
stablecoinsClient;
|
|
18702
18755
|
yieldsClient;
|
|
18703
18756
|
coinsClient;
|
|
18704
|
-
logger =
|
|
18757
|
+
logger = secureLogger;
|
|
18705
18758
|
baseURL = "https://api.llama.fi";
|
|
18706
18759
|
stablecoinsURL = "https://stablecoins.llama.fi";
|
|
18707
18760
|
yieldsURL = "https://yields.llama.fi";
|
|
18708
18761
|
coinsURL = "https://coins.llama.fi";
|
|
18709
18762
|
constructor() {
|
|
18710
|
-
|
|
18763
|
+
const errorHandler = (error) => {
|
|
18764
|
+
const status = error.response?.status;
|
|
18765
|
+
const message = error.response?.data?.message || error.message;
|
|
18766
|
+
if (status === 402) {
|
|
18767
|
+
throw new Error(
|
|
18768
|
+
`DeFiLlama API Error: this endpoint requires a DeFiLlama Pro plan subscription (HTTP 402); retrying on the free API will not succeed. ${message}`
|
|
18769
|
+
);
|
|
18770
|
+
}
|
|
18771
|
+
throw new Error(`DeFiLlama API Error: ${message}`);
|
|
18772
|
+
};
|
|
18773
|
+
this.client = createFetchClient({
|
|
18711
18774
|
baseURL: this.baseURL,
|
|
18712
18775
|
timeout: 6e4,
|
|
18713
18776
|
// Increased from 30s to 60s for large responses
|
|
18714
18777
|
headers: {
|
|
18715
18778
|
"Content-Type": "application/json",
|
|
18716
18779
|
"User-Agent": "defillama-mcp-server/1.0.0"
|
|
18717
|
-
}
|
|
18780
|
+
},
|
|
18781
|
+
onError: errorHandler
|
|
18718
18782
|
});
|
|
18719
|
-
this.stablecoinsClient =
|
|
18783
|
+
this.stablecoinsClient = createFetchClient({
|
|
18720
18784
|
baseURL: this.stablecoinsURL,
|
|
18721
18785
|
timeout: 3e4,
|
|
18722
18786
|
// Reduced to 30s for MCP production
|
|
18723
18787
|
headers: {
|
|
18724
18788
|
"Content-Type": "application/json",
|
|
18725
18789
|
"User-Agent": "defillama-mcp-server/1.0.0"
|
|
18726
|
-
}
|
|
18790
|
+
},
|
|
18791
|
+
onError: errorHandler
|
|
18727
18792
|
});
|
|
18728
|
-
this.yieldsClient =
|
|
18793
|
+
this.yieldsClient = createFetchClient({
|
|
18729
18794
|
baseURL: this.yieldsURL,
|
|
18730
18795
|
timeout: 6e4,
|
|
18731
18796
|
headers: {
|
|
18732
18797
|
"Content-Type": "application/json",
|
|
18733
18798
|
"User-Agent": "defillama-mcp-server/1.0.0"
|
|
18734
|
-
}
|
|
18799
|
+
},
|
|
18800
|
+
onError: errorHandler
|
|
18735
18801
|
});
|
|
18736
|
-
this.coinsClient =
|
|
18802
|
+
this.coinsClient = createFetchClient({
|
|
18737
18803
|
baseURL: this.coinsURL,
|
|
18738
18804
|
timeout: 3e4,
|
|
18739
18805
|
headers: {
|
|
18740
18806
|
"Content-Type": "application/json",
|
|
18741
18807
|
"User-Agent": "defillama-mcp-server/1.0.0"
|
|
18742
|
-
}
|
|
18808
|
+
},
|
|
18809
|
+
onError: errorHandler
|
|
18743
18810
|
});
|
|
18744
|
-
const errorHandler = (error) => {
|
|
18745
|
-
const status = error.response?.status;
|
|
18746
|
-
const message = error.response?.data?.message || error.message;
|
|
18747
|
-
if (status === 402) {
|
|
18748
|
-
throw new Error(
|
|
18749
|
-
`DeFiLlama API Error: this endpoint requires a DeFiLlama Pro plan subscription (HTTP 402); retrying on the free API will not succeed. ${message}`
|
|
18750
|
-
);
|
|
18751
|
-
}
|
|
18752
|
-
throw new Error(`DeFiLlama API Error: ${message}`);
|
|
18753
|
-
};
|
|
18754
|
-
this.client.interceptors.response.use((response) => response, errorHandler);
|
|
18755
|
-
this.stablecoinsClient.interceptors.response.use(
|
|
18756
|
-
(response) => response,
|
|
18757
|
-
errorHandler
|
|
18758
|
-
);
|
|
18759
|
-
this.yieldsClient.interceptors.response.use(
|
|
18760
|
-
(response) => response,
|
|
18761
|
-
errorHandler
|
|
18762
|
-
);
|
|
18763
|
-
this.coinsClient.interceptors.response.use(
|
|
18764
|
-
(response) => response,
|
|
18765
|
-
errorHandler
|
|
18766
|
-
);
|
|
18767
18811
|
}
|
|
18768
18812
|
/**
|
|
18769
18813
|
* Helper method to log API calls with timing and response details
|
|
@@ -19424,7 +19468,7 @@ var DeFiLlamaAPI = class {
|
|
|
19424
19468
|
});
|
|
19425
19469
|
return response.data;
|
|
19426
19470
|
} catch (error) {
|
|
19427
|
-
if (
|
|
19471
|
+
if (error instanceof HttpError) {
|
|
19428
19472
|
if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
|
|
19429
19473
|
throw new Error(
|
|
19430
19474
|
`Timeout while fetching DEX volume data for ${dexName}. The response may be too large.`
|
|
@@ -31492,9 +31536,6 @@ function getAllCCXTEndpoints() {
|
|
|
31492
31536
|
}
|
|
31493
31537
|
|
|
31494
31538
|
// src/utils/httpClient.ts
|
|
31495
|
-
import axios2, {
|
|
31496
|
-
AxiosError
|
|
31497
|
-
} from "axios";
|
|
31498
31539
|
var circuitBreakers = /* @__PURE__ */ new Map();
|
|
31499
31540
|
function getCircuitBreaker(serviceName) {
|
|
31500
31541
|
if (!circuitBreakers.has(serviceName)) {
|
|
@@ -31526,7 +31567,7 @@ function upstreamDetail(error) {
|
|
|
31526
31567
|
return compact ? compact.slice(0, 240) : null;
|
|
31527
31568
|
}
|
|
31528
31569
|
function withUpstreamDetail(error) {
|
|
31529
|
-
if (!(error instanceof
|
|
31570
|
+
if (!(error instanceof HttpError)) return error;
|
|
31530
31571
|
const detail = upstreamDetail(error);
|
|
31531
31572
|
if (detail && !error.message.includes(detail)) {
|
|
31532
31573
|
error.message = `${error.message}: ${detail}`;
|
|
@@ -31535,7 +31576,7 @@ function withUpstreamDetail(error) {
|
|
|
31535
31576
|
}
|
|
31536
31577
|
function failureMessage(error) {
|
|
31537
31578
|
let message = "";
|
|
31538
|
-
if (error instanceof
|
|
31579
|
+
if (error instanceof HttpError) {
|
|
31539
31580
|
message = upstreamDetail(error) ?? error.message;
|
|
31540
31581
|
} else if (error instanceof Error) {
|
|
31541
31582
|
message = error.message;
|
|
@@ -31568,7 +31609,7 @@ function sleep(ms) {
|
|
|
31568
31609
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31569
31610
|
}
|
|
31570
31611
|
var ResilientHttpClient = class {
|
|
31571
|
-
|
|
31612
|
+
http;
|
|
31572
31613
|
config;
|
|
31573
31614
|
circuitBreaker;
|
|
31574
31615
|
constructor(config2) {
|
|
@@ -31584,10 +31625,10 @@ var ResilientHttpClient = class {
|
|
|
31584
31625
|
circuitBreakerThreshold: config2.circuitBreakerThreshold ?? 5,
|
|
31585
31626
|
circuitBreakerResetTimeout: config2.circuitBreakerResetTimeout ?? 3e4
|
|
31586
31627
|
};
|
|
31587
|
-
this.
|
|
31628
|
+
this.http = createFetchClient({
|
|
31588
31629
|
baseURL: this.config.baseURL,
|
|
31589
31630
|
timeout: this.config.timeout,
|
|
31590
|
-
|
|
31631
|
+
maxContentLength: config2.maxContentLength,
|
|
31591
31632
|
headers: {
|
|
31592
31633
|
"Content-Type": "application/json",
|
|
31593
31634
|
Accept: "application/json",
|
|
@@ -31595,35 +31636,28 @@ var ResilientHttpClient = class {
|
|
|
31595
31636
|
}
|
|
31596
31637
|
});
|
|
31597
31638
|
this.circuitBreaker = getCircuitBreaker(this.config.serviceName);
|
|
31598
|
-
|
|
31599
|
-
|
|
31600
|
-
|
|
31601
|
-
|
|
31602
|
-
|
|
31603
|
-
|
|
31604
|
-
|
|
31605
|
-
|
|
31606
|
-
|
|
31607
|
-
|
|
31608
|
-
|
|
31609
|
-
|
|
31610
|
-
|
|
31611
|
-
|
|
31612
|
-
|
|
31613
|
-
|
|
31614
|
-
);
|
|
31615
|
-
this.
|
|
31616
|
-
|
|
31617
|
-
|
|
31618
|
-
|
|
31619
|
-
|
|
31620
|
-
});
|
|
31621
|
-
return response;
|
|
31622
|
-
},
|
|
31623
|
-
(error) => {
|
|
31624
|
-
return Promise.reject(error);
|
|
31625
|
-
}
|
|
31626
|
-
);
|
|
31639
|
+
}
|
|
31640
|
+
/**
|
|
31641
|
+
* Send one request, with debug logging on either side. Failures are logged
|
|
31642
|
+
* by the retry logic.
|
|
31643
|
+
*/
|
|
31644
|
+
async send(method, endpoint, options) {
|
|
31645
|
+
secureLogger.debug(`[${this.config.serviceName}] Request`, {
|
|
31646
|
+
method: method.toUpperCase(),
|
|
31647
|
+
url: endpoint,
|
|
31648
|
+
params: options.params
|
|
31649
|
+
});
|
|
31650
|
+
const config2 = {
|
|
31651
|
+
params: options.params,
|
|
31652
|
+
timeout: options.timeout ?? this.config.timeout,
|
|
31653
|
+
headers: options.headers
|
|
31654
|
+
};
|
|
31655
|
+
const response = method === "get" || method === "delete" ? await this.http[method](endpoint, config2) : await this.http[method](endpoint, options.body, config2);
|
|
31656
|
+
secureLogger.debug(`[${this.config.serviceName}] Response`, {
|
|
31657
|
+
status: response.status,
|
|
31658
|
+
url: endpoint
|
|
31659
|
+
});
|
|
31660
|
+
return response;
|
|
31627
31661
|
}
|
|
31628
31662
|
/**
|
|
31629
31663
|
* Check if the circuit breaker allows the request
|
|
@@ -31706,7 +31740,7 @@ var ResilientHttpClient = class {
|
|
|
31706
31740
|
return response.data;
|
|
31707
31741
|
} catch (error) {
|
|
31708
31742
|
lastError = error;
|
|
31709
|
-
if (error instanceof
|
|
31743
|
+
if (error instanceof HttpError && isRetryableError(error)) {
|
|
31710
31744
|
this.recordFailure(error);
|
|
31711
31745
|
if (attempt < maxRetries) {
|
|
31712
31746
|
const delay2 = calculateBackoffDelay(
|
|
@@ -31727,7 +31761,7 @@ var ResilientHttpClient = class {
|
|
|
31727
31761
|
continue;
|
|
31728
31762
|
}
|
|
31729
31763
|
} else {
|
|
31730
|
-
if (error instanceof
|
|
31764
|
+
if (error instanceof HttpError) {
|
|
31731
31765
|
const status = error.response?.status ?? 0;
|
|
31732
31766
|
const oversized = error.message.includes("maxContentLength");
|
|
31733
31767
|
if (!status && !oversized || status >= 500 || status === 429) {
|
|
@@ -31735,7 +31769,7 @@ var ResilientHttpClient = class {
|
|
|
31735
31769
|
}
|
|
31736
31770
|
}
|
|
31737
31771
|
}
|
|
31738
|
-
const errorDetails = error instanceof
|
|
31772
|
+
const errorDetails = error instanceof HttpError ? {
|
|
31739
31773
|
status: error.response?.status,
|
|
31740
31774
|
code: error.code,
|
|
31741
31775
|
message: error.message,
|
|
@@ -31757,13 +31791,8 @@ var ResilientHttpClient = class {
|
|
|
31757
31791
|
* Perform a GET request
|
|
31758
31792
|
*/
|
|
31759
31793
|
async get(endpoint, options = {}) {
|
|
31760
|
-
const config2 = {
|
|
31761
|
-
params: options.params,
|
|
31762
|
-
timeout: options.timeout ?? this.config.timeout,
|
|
31763
|
-
headers: options.headers
|
|
31764
|
-
};
|
|
31765
31794
|
return this.executeWithRetry(
|
|
31766
|
-
() => this.
|
|
31795
|
+
() => this.send("get", endpoint, options),
|
|
31767
31796
|
options
|
|
31768
31797
|
);
|
|
31769
31798
|
}
|
|
@@ -31771,13 +31800,8 @@ var ResilientHttpClient = class {
|
|
|
31771
31800
|
* Perform a POST request
|
|
31772
31801
|
*/
|
|
31773
31802
|
async post(endpoint, options = {}) {
|
|
31774
|
-
const config2 = {
|
|
31775
|
-
params: options.params,
|
|
31776
|
-
timeout: options.timeout ?? this.config.timeout,
|
|
31777
|
-
headers: options.headers
|
|
31778
|
-
};
|
|
31779
31803
|
return this.executeWithRetry(
|
|
31780
|
-
() => this.
|
|
31804
|
+
() => this.send("post", endpoint, options),
|
|
31781
31805
|
options
|
|
31782
31806
|
);
|
|
31783
31807
|
}
|
|
@@ -31785,13 +31809,8 @@ var ResilientHttpClient = class {
|
|
|
31785
31809
|
* Perform a PUT request
|
|
31786
31810
|
*/
|
|
31787
31811
|
async put(endpoint, options = {}) {
|
|
31788
|
-
const config2 = {
|
|
31789
|
-
params: options.params,
|
|
31790
|
-
timeout: options.timeout ?? this.config.timeout,
|
|
31791
|
-
headers: options.headers
|
|
31792
|
-
};
|
|
31793
31812
|
return this.executeWithRetry(
|
|
31794
|
-
() => this.
|
|
31813
|
+
() => this.send("put", endpoint, options),
|
|
31795
31814
|
options
|
|
31796
31815
|
);
|
|
31797
31816
|
}
|
|
@@ -31799,13 +31818,8 @@ var ResilientHttpClient = class {
|
|
|
31799
31818
|
* Perform a DELETE request
|
|
31800
31819
|
*/
|
|
31801
31820
|
async delete(endpoint, options = {}) {
|
|
31802
|
-
const config2 = {
|
|
31803
|
-
params: options.params,
|
|
31804
|
-
timeout: options.timeout ?? this.config.timeout,
|
|
31805
|
-
headers: options.headers
|
|
31806
|
-
};
|
|
31807
31821
|
return this.executeWithRetry(
|
|
31808
|
-
() => this.
|
|
31822
|
+
() => this.send("delete", endpoint, options),
|
|
31809
31823
|
options
|
|
31810
31824
|
);
|
|
31811
31825
|
}
|
|
@@ -38764,7 +38778,6 @@ function removedVenueMessage(venue) {
|
|
|
38764
38778
|
}
|
|
38765
38779
|
|
|
38766
38780
|
// src/tools/hyperliquid/api/hyperliquid.ts
|
|
38767
|
-
import axios3 from "axios";
|
|
38768
38781
|
var HYPERLIQUID_API_URL = "https://api.hyperliquid.xyz";
|
|
38769
38782
|
var DEFAULT_LEADERBOARD_LIMIT = 20;
|
|
38770
38783
|
var MAX_LEADERBOARD_LIMIT = 500;
|
|
@@ -38785,30 +38798,27 @@ var HyperliquidAPI = class {
|
|
|
38785
38798
|
now;
|
|
38786
38799
|
constructor(now = Date.now) {
|
|
38787
38800
|
this.now = now;
|
|
38788
|
-
this.client =
|
|
38801
|
+
this.client = createFetchClient({
|
|
38789
38802
|
baseURL: HYPERLIQUID_API_URL,
|
|
38790
38803
|
timeout: 3e4,
|
|
38791
38804
|
headers: {
|
|
38792
38805
|
"Content-Type": "application/json",
|
|
38793
38806
|
"User-Agent": "hive-mcp-server/1.0.0"
|
|
38794
|
-
}
|
|
38795
|
-
|
|
38796
|
-
|
|
38797
|
-
|
|
38798
|
-
|
|
38799
|
-
|
|
38800
|
-
|
|
38801
|
-
|
|
38802
|
-
|
|
38803
|
-
this.client.interceptors.response.use(
|
|
38804
|
-
(response) => response,
|
|
38805
|
-
(error) => {
|
|
38807
|
+
},
|
|
38808
|
+
// One gate for every /info read that scopes to a builder dex.
|
|
38809
|
+
onRequest: ({ data }) => {
|
|
38810
|
+
const dex = data?.dex;
|
|
38811
|
+
if (typeof dex === "string" && REMOVED_HYPERLIQUID_DEXES.has(dex)) {
|
|
38812
|
+
throw new Error(removedVenueMessage(`hyperliquid:${dex}`));
|
|
38813
|
+
}
|
|
38814
|
+
},
|
|
38815
|
+
onError: (error) => {
|
|
38806
38816
|
const err = error;
|
|
38807
38817
|
const message = err?.response?.data?.message || err?.message || "request failed";
|
|
38808
38818
|
secureLogger.warn("Hyperliquid API error", { message });
|
|
38809
38819
|
throw new Error(`Hyperliquid API Error: ${message}`);
|
|
38810
38820
|
}
|
|
38811
|
-
);
|
|
38821
|
+
});
|
|
38812
38822
|
}
|
|
38813
38823
|
/**
|
|
38814
38824
|
* Per-pair 24h notional volume leaderboard for a Hyperliquid perp DEX.
|
|
@@ -42164,7 +42174,7 @@ var PolymarketNotFoundError = class extends Error {
|
|
|
42164
42174
|
}
|
|
42165
42175
|
url;
|
|
42166
42176
|
};
|
|
42167
|
-
function
|
|
42177
|
+
function buildUrl2(base, path, params = {}) {
|
|
42168
42178
|
const url = new URL(path, base);
|
|
42169
42179
|
for (const [key, value] of Object.entries(params)) {
|
|
42170
42180
|
if (value === void 0) continue;
|
|
@@ -42803,7 +42813,7 @@ function toActivityRow(raw) {
|
|
|
42803
42813
|
}
|
|
42804
42814
|
async function fetchGammaKeyset(resource, params) {
|
|
42805
42815
|
const label = `Gamma /${resource}/keyset`;
|
|
42806
|
-
const url =
|
|
42816
|
+
const url = buildUrl2(GAMMA_BASE_URL, `/${resource}/keyset`, params);
|
|
42807
42817
|
const page = asRecord(await fetchPolymarketJson(url, label));
|
|
42808
42818
|
return {
|
|
42809
42819
|
url,
|
|
@@ -42831,7 +42841,7 @@ function parseDataPage(value, label) {
|
|
|
42831
42841
|
};
|
|
42832
42842
|
}
|
|
42833
42843
|
async function searchGammaMarkets(query, closed) {
|
|
42834
|
-
const url =
|
|
42844
|
+
const url = buildUrl2(GAMMA_BASE_URL, "/public-search", {
|
|
42835
42845
|
q: query,
|
|
42836
42846
|
limit_per_type: SEARCH_EVENT_LIMIT,
|
|
42837
42847
|
events_status: closed ? "closed" : "active"
|
|
@@ -42869,7 +42879,7 @@ async function resolveMarket(selector) {
|
|
|
42869
42879
|
if (gamma.rows.length > 0) {
|
|
42870
42880
|
return { url: gamma.url, market: normalizeGammaMarket(gamma.rows[0]) };
|
|
42871
42881
|
}
|
|
42872
|
-
const clobUrl =
|
|
42882
|
+
const clobUrl = buildUrl2(
|
|
42873
42883
|
CLOB_BASE_URL,
|
|
42874
42884
|
`/clob-markets/${selector.conditionId}`
|
|
42875
42885
|
);
|
|
@@ -42895,7 +42905,7 @@ async function resolveMarket(selector) {
|
|
|
42895
42905
|
}
|
|
42896
42906
|
}
|
|
42897
42907
|
async function fetchOrderbook(tokenId) {
|
|
42898
|
-
const url =
|
|
42908
|
+
const url = buildUrl2(CLOB_BASE_URL, "/book", { token_id: tokenId });
|
|
42899
42909
|
try {
|
|
42900
42910
|
const data = await fetchPolymarketJson(url, "CLOB /book");
|
|
42901
42911
|
const raw = asRecord(data);
|
|
@@ -42921,11 +42931,11 @@ async function fetchPriceHistory(tokenId, interval, fidelity) {
|
|
|
42921
42931
|
interval,
|
|
42922
42932
|
bucket_seconds: fidelity * 60
|
|
42923
42933
|
};
|
|
42924
|
-
const url =
|
|
42934
|
+
const url = buildUrl2(DATA_API_BASE_URL, "/v2/prices-history", params);
|
|
42925
42935
|
const rows = [];
|
|
42926
42936
|
let cursor = null;
|
|
42927
42937
|
for (let page = 0; page < MAX_HISTORY_PAGES; page++) {
|
|
42928
|
-
const pageUrl = cursor ?
|
|
42938
|
+
const pageUrl = cursor ? buildUrl2(DATA_API_BASE_URL, "/v2/prices-history", {
|
|
42929
42939
|
...params,
|
|
42930
42940
|
cursor
|
|
42931
42941
|
}) : url;
|
|
@@ -42943,7 +42953,7 @@ async function fetchPriceHistory(tokenId, interval, fidelity) {
|
|
|
42943
42953
|
}
|
|
42944
42954
|
async function fetchPositions(user, limit, cursor) {
|
|
42945
42955
|
const label = "Data API /v2/positions";
|
|
42946
|
-
const url =
|
|
42956
|
+
const url = buildUrl2(DATA_API_BASE_URL, "/v2/positions", {
|
|
42947
42957
|
user,
|
|
42948
42958
|
limit,
|
|
42949
42959
|
cursor: cursor ?? void 0
|
|
@@ -42957,7 +42967,7 @@ async function fetchPositions(user, limit, cursor) {
|
|
|
42957
42967
|
}
|
|
42958
42968
|
async function fetchActivity(user, limit, cursor) {
|
|
42959
42969
|
const label = "Data API /v2/activity";
|
|
42960
|
-
const url =
|
|
42970
|
+
const url = buildUrl2(DATA_API_BASE_URL, "/v2/activity", {
|
|
42961
42971
|
user,
|
|
42962
42972
|
limit,
|
|
42963
42973
|
cursor: cursor ?? void 0
|
|
@@ -43633,7 +43643,7 @@ var KalshiNotFoundError = class extends Error {
|
|
|
43633
43643
|
}
|
|
43634
43644
|
url;
|
|
43635
43645
|
};
|
|
43636
|
-
function
|
|
43646
|
+
function buildUrl3(path, params = {}, base = KALSHI_BASE_URL) {
|
|
43637
43647
|
const url = new URL(`${base}${path}`);
|
|
43638
43648
|
for (const [key, value] of Object.entries(params)) {
|
|
43639
43649
|
if (value === void 0) continue;
|
|
@@ -44208,7 +44218,7 @@ function readCursor(record) {
|
|
|
44208
44218
|
return cursor;
|
|
44209
44219
|
}
|
|
44210
44220
|
async function fetchMarketsPage(params) {
|
|
44211
|
-
const url =
|
|
44221
|
+
const url = buildUrl3("/markets", params);
|
|
44212
44222
|
const data = await fetchKalshiJson(url, "GET /markets");
|
|
44213
44223
|
const record = asRecord2(data);
|
|
44214
44224
|
return {
|
|
@@ -44268,7 +44278,7 @@ async function searchMarkets(filters) {
|
|
|
44268
44278
|
};
|
|
44269
44279
|
}
|
|
44270
44280
|
async function fetchMarket(ticker) {
|
|
44271
|
-
const url =
|
|
44281
|
+
const url = buildUrl3(`/markets/${encodeURIComponent(ticker)}`);
|
|
44272
44282
|
try {
|
|
44273
44283
|
const data = await fetchKalshiJson(url, "GET /markets/{ticker}");
|
|
44274
44284
|
const record = asRecord2(asRecord2(data)?.market);
|
|
@@ -44288,7 +44298,7 @@ async function fetchMarket(ticker) {
|
|
|
44288
44298
|
}
|
|
44289
44299
|
}
|
|
44290
44300
|
async function fetchEventsPage(params) {
|
|
44291
|
-
const url =
|
|
44301
|
+
const url = buildUrl3("/events", {
|
|
44292
44302
|
status: params.status ?? void 0,
|
|
44293
44303
|
series_ticker: params.seriesTicker ?? void 0,
|
|
44294
44304
|
limit: params.limit,
|
|
@@ -44303,7 +44313,7 @@ async function fetchEventsPage(params) {
|
|
|
44303
44313
|
return { url, rows, nextCursor: readCursor(record) };
|
|
44304
44314
|
}
|
|
44305
44315
|
async function fetchEvent(eventTicker, withNested) {
|
|
44306
|
-
const url =
|
|
44316
|
+
const url = buildUrl3(`/events/${encodeURIComponent(eventTicker)}`, {
|
|
44307
44317
|
with_nested_markets: withNested ? true : void 0
|
|
44308
44318
|
});
|
|
44309
44319
|
try {
|
|
@@ -44326,7 +44336,7 @@ async function fetchEvent(eventTicker, withNested) {
|
|
|
44326
44336
|
}
|
|
44327
44337
|
}
|
|
44328
44338
|
async function fetchOrderbook2(ticker, depth) {
|
|
44329
|
-
const url =
|
|
44339
|
+
const url = buildUrl3(`/markets/${encodeURIComponent(ticker)}/orderbook`);
|
|
44330
44340
|
try {
|
|
44331
44341
|
const data = await fetchKalshiJson(
|
|
44332
44342
|
url,
|
|
@@ -44349,7 +44359,7 @@ async function fetchOrderbook2(ticker, depth) {
|
|
|
44349
44359
|
}
|
|
44350
44360
|
}
|
|
44351
44361
|
async function fetchTrades(ticker, limit, cursor) {
|
|
44352
|
-
const url =
|
|
44362
|
+
const url = buildUrl3("/markets/trades", {
|
|
44353
44363
|
ticker,
|
|
44354
44364
|
limit,
|
|
44355
44365
|
cursor: cursor ?? void 0
|
|
@@ -44366,7 +44376,7 @@ async function assertMarketExists(ticker) {
|
|
|
44366
44376
|
await fetchMarket(ticker);
|
|
44367
44377
|
}
|
|
44368
44378
|
async function fetchCandlesticks(seriesTicker, ticker, window) {
|
|
44369
|
-
const url =
|
|
44379
|
+
const url = buildUrl3(
|
|
44370
44380
|
`/series/${encodeURIComponent(seriesTicker)}/markets/${encodeURIComponent(ticker)}/candlesticks`,
|
|
44371
44381
|
{
|
|
44372
44382
|
start_ts: window.start_ts,
|
|
@@ -47811,7 +47821,7 @@ async function assertHostResolvesPublic(host) {
|
|
|
47811
47821
|
}
|
|
47812
47822
|
}
|
|
47813
47823
|
}
|
|
47814
|
-
function
|
|
47824
|
+
function buildUrl4(entry2, path, query) {
|
|
47815
47825
|
if (/^[a-z]+:\/\//i.test(path) || path.includes("@")) {
|
|
47816
47826
|
throw new FetchInputError(
|
|
47817
47827
|
`Invalid argument: path "${path}" must be a path on the host, not a full URL.`
|
|
@@ -47844,7 +47854,7 @@ async function fetchPublicApi(params) {
|
|
|
47844
47854
|
`Method "${method}" is not supported for host "${entry2.host}" (allowed: ${entry2.methods.join(", ")}).`
|
|
47845
47855
|
);
|
|
47846
47856
|
}
|
|
47847
|
-
const url =
|
|
47857
|
+
const url = buildUrl4(entry2, params.path, params.query);
|
|
47848
47858
|
await assertHostResolvesPublic(entry2.host);
|
|
47849
47859
|
const headers = { Accept: "application/json" };
|
|
47850
47860
|
let payload;
|
|
@@ -51409,11 +51419,11 @@ import { fileURLToPath } from "url";
|
|
|
51409
51419
|
import Coingecko5 from "@coingecko/coingecko-typescript";
|
|
51410
51420
|
|
|
51411
51421
|
// src/tools/dynamic-tools.ts
|
|
51412
|
-
import { z as
|
|
51422
|
+
import { z as z3 } from "zod";
|
|
51413
51423
|
import { isDeepStrictEqual } from "util";
|
|
51414
51424
|
|
|
51415
51425
|
// src/tools/heroTools.ts
|
|
51416
|
-
import { z
|
|
51426
|
+
import { z } from "zod";
|
|
51417
51427
|
|
|
51418
51428
|
// src/services/tool-execution-pipeline.ts
|
|
51419
51429
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -53940,7 +53950,7 @@ var HERO_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
53940
53950
|
"check_token_safety",
|
|
53941
53951
|
"get_wallet_portfolio"
|
|
53942
53952
|
]);
|
|
53943
|
-
var RESPONSE_FORMAT =
|
|
53953
|
+
var RESPONSE_FORMAT = z.enum(["concise", "detailed", "json", "markdown"]).optional().describe(
|
|
53944
53954
|
"concise (default) returns the trimmed essentials; detailed returns the full provider payload. json and markdown, the platform-wide values every other tool advertises, are accepted and treated as concise."
|
|
53945
53955
|
);
|
|
53946
53956
|
function heroFormat(value) {
|
|
@@ -54203,15 +54213,15 @@ function heroTools(endpoints, options = {}) {
|
|
|
54203
54213
|
source_receipt: sourceReceipt(result2)
|
|
54204
54214
|
});
|
|
54205
54215
|
};
|
|
54206
|
-
const tokenPriceSchema =
|
|
54207
|
-
token:
|
|
54216
|
+
const tokenPriceSchema = z.object({
|
|
54217
|
+
token: z.string().trim().min(1).max(100).optional().describe(
|
|
54208
54218
|
'CoinGecko coin id or ticker symbol, for example "bitcoin" or "BTC". Omit when passing chain + address.'
|
|
54209
54219
|
),
|
|
54210
|
-
chain:
|
|
54220
|
+
chain: z.string().trim().max(40).optional().describe(
|
|
54211
54221
|
'Chain name for the contract-address variant, for example "eth", "base", "bsc", or "solana".'
|
|
54212
54222
|
),
|
|
54213
|
-
address:
|
|
54214
|
-
vs_currency:
|
|
54223
|
+
address: z.string().trim().max(100).optional().describe("Token contract address; requires chain."),
|
|
54224
|
+
vs_currency: z.string().trim().max(20).optional().describe('Quote currency. Default "usd".'),
|
|
54215
54225
|
response_format: RESPONSE_FORMAT
|
|
54216
54226
|
});
|
|
54217
54227
|
const trimSimplePrice = (query, vsCurrency) => (payload) => {
|
|
@@ -54318,11 +54328,11 @@ function heroTools(endpoints, options = {}) {
|
|
|
54318
54328
|
);
|
|
54319
54329
|
}
|
|
54320
54330
|
};
|
|
54321
|
-
const tokenSafetySchema =
|
|
54322
|
-
address:
|
|
54331
|
+
const tokenSafetySchema = z.object({
|
|
54332
|
+
address: z.string().trim().min(1).max(100).describe(
|
|
54323
54333
|
"Required. Token contract address (0x\u2026 for EVM, base58 for Solana)."
|
|
54324
54334
|
),
|
|
54325
|
-
chain:
|
|
54335
|
+
chain: z.string().trim().max(40).optional().describe(
|
|
54326
54336
|
'Chain name or EVM chain id, for example "eth", "bsc", "8453", or "solana". Defaults to eth for 0x addresses; Solana is auto-detected.'
|
|
54327
54337
|
),
|
|
54328
54338
|
response_format: RESPONSE_FORMAT
|
|
@@ -54410,12 +54420,12 @@ function heroTools(endpoints, options = {}) {
|
|
|
54410
54420
|
return respond(result2, format, trimTokenSafety(address, normalized));
|
|
54411
54421
|
}
|
|
54412
54422
|
};
|
|
54413
|
-
const walletPortfolioSchema =
|
|
54414
|
-
address:
|
|
54415
|
-
chain:
|
|
54423
|
+
const walletPortfolioSchema = z.object({
|
|
54424
|
+
address: z.string().trim().min(1).max(100).describe("Required. Wallet address (0x\u2026 for EVM, base58 for Solana)."),
|
|
54425
|
+
chain: z.string().trim().max(40).optional().describe(
|
|
54416
54426
|
'Chain name, for example "eth", "base", "arbitrum", or "solana". Defaults to eth for 0x addresses; Solana is auto-detected.'
|
|
54417
54427
|
),
|
|
54418
|
-
include_spam:
|
|
54428
|
+
include_spam: z.boolean().optional().describe(
|
|
54419
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."
|
|
54420
54430
|
),
|
|
54421
54431
|
response_format: RESPONSE_FORMAT
|
|
@@ -57754,7 +57764,7 @@ function canonicalResource(value) {
|
|
|
57754
57764
|
|
|
57755
57765
|
// src/auth/oauth/clients.ts
|
|
57756
57766
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
57757
|
-
import { z as
|
|
57767
|
+
import { z as z2 } from "zod";
|
|
57758
57768
|
import { InvalidClientMetadataError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
|
|
57759
57769
|
var OAUTH_DEPLOYMENT_CANARY_SOFTWARE_ID = "xyz.hiveintelligence/deployment-canary";
|
|
57760
57770
|
var OAUTH_DEPLOYMENT_CANARY_CLIENT_NAME = "Hive deployment OAuth canary";
|
|
@@ -57834,21 +57844,21 @@ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]
|
|
|
57834
57844
|
var EXACT_NATIVE_REDIRECT_URIS = /* @__PURE__ */ new Set([
|
|
57835
57845
|
CURSOR_DESKTOP_OAUTH_REDIRECT_URI
|
|
57836
57846
|
]);
|
|
57837
|
-
var cimdDocumentSchema =
|
|
57838
|
-
client_id:
|
|
57839
|
-
client_name:
|
|
57840
|
-
redirect_uris:
|
|
57841
|
-
token_endpoint_auth_method:
|
|
57842
|
-
grant_types:
|
|
57843
|
-
response_types:
|
|
57844
|
-
client_uri:
|
|
57845
|
-
logo_uri:
|
|
57846
|
-
scope:
|
|
57847
|
-
contacts:
|
|
57848
|
-
tos_uri:
|
|
57849
|
-
policy_uri:
|
|
57850
|
-
software_id:
|
|
57851
|
-
software_version:
|
|
57847
|
+
var cimdDocumentSchema = z2.object({
|
|
57848
|
+
client_id: z2.string().url(),
|
|
57849
|
+
client_name: z2.string().trim().min(1).max(200),
|
|
57850
|
+
redirect_uris: z2.array(z2.string().url()).min(1).max(20),
|
|
57851
|
+
token_endpoint_auth_method: z2.literal("none").optional(),
|
|
57852
|
+
grant_types: z2.array(z2.string()).max(4).optional(),
|
|
57853
|
+
response_types: z2.array(z2.string()).max(4).optional(),
|
|
57854
|
+
client_uri: z2.string().url().optional(),
|
|
57855
|
+
logo_uri: z2.string().url().optional(),
|
|
57856
|
+
scope: z2.string().max(1e3).optional(),
|
|
57857
|
+
contacts: z2.array(z2.string().max(320)).max(10).optional(),
|
|
57858
|
+
tos_uri: z2.string().url().optional(),
|
|
57859
|
+
policy_uri: z2.string().url().optional(),
|
|
57860
|
+
software_id: z2.string().max(200).optional(),
|
|
57861
|
+
software_version: z2.string().max(100).optional()
|
|
57852
57862
|
}).strip();
|
|
57853
57863
|
function registeredClientTtlSeconds(client2, configuredTtlSeconds) {
|
|
57854
57864
|
return client2.software_id === OAUTH_DEPLOYMENT_CANARY_SOFTWARE_ID ? Math.min(
|
|
@@ -58270,41 +58280,41 @@ var HIVE_PROMPTS = [
|
|
|
58270
58280
|
}
|
|
58271
58281
|
];
|
|
58272
58282
|
|
|
58273
|
-
// src/services/
|
|
58274
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
58275
|
-
var _unkey = null;
|
|
58283
|
+
// src/services/api-key-service.ts
|
|
58284
|
+
import { createHash as createHash6, randomInt, randomUUID as randomUUID4 } from "crypto";
|
|
58276
58285
|
function getAuthBackendMode() {
|
|
58277
58286
|
const mode = (getEnvVar("HIVE_AUTH_BACKEND") ?? "auto").toLowerCase();
|
|
58278
|
-
if (mode === "
|
|
58279
|
-
|
|
58280
|
-
}
|
|
58287
|
+
if (mode === "hosted" || mode === "unkey") return "hosted";
|
|
58288
|
+
if (mode === "static") return "static";
|
|
58281
58289
|
return "auto";
|
|
58282
58290
|
}
|
|
58283
|
-
function
|
|
58284
|
-
return getAuthBackendMode() === "
|
|
58291
|
+
function isHostedKeysRequired() {
|
|
58292
|
+
return getAuthBackendMode() === "hosted";
|
|
58285
58293
|
}
|
|
58286
|
-
function
|
|
58287
|
-
return
|
|
58294
|
+
function isHostedKeysConfigured() {
|
|
58295
|
+
return getAuthBackendMode() !== "static" && isSupabaseConfigured();
|
|
58288
58296
|
}
|
|
58289
|
-
function
|
|
58290
|
-
return
|
|
58297
|
+
function isLegacyUnkeyConfigured() {
|
|
58298
|
+
return hasEnvVars("UNKEY_ROOT_KEY");
|
|
58291
58299
|
}
|
|
58292
|
-
|
|
58293
|
-
|
|
58294
|
-
|
|
58295
|
-
|
|
58296
|
-
|
|
58297
|
-
|
|
58298
|
-
|
|
58299
|
-
const { Unkey: UnkeyClient } = await import("@unkey/api");
|
|
58300
|
-
_unkey ??= new UnkeyClient({
|
|
58301
|
-
rootKey: getRequiredEnvVar("UNKEY_ROOT_KEY")
|
|
58302
|
-
});
|
|
58303
|
-
}
|
|
58300
|
+
var _unkey = null;
|
|
58301
|
+
function legacyUnkey() {
|
|
58302
|
+
_unkey ??= createFetchClient({
|
|
58303
|
+
baseURL: "https://api.unkey.com/v2",
|
|
58304
|
+
timeout: 5e3,
|
|
58305
|
+
headers: { Authorization: `Bearer ${getEnvVar("UNKEY_ROOT_KEY")}` }
|
|
58306
|
+
});
|
|
58304
58307
|
return _unkey;
|
|
58305
58308
|
}
|
|
58306
|
-
|
|
58307
|
-
|
|
58309
|
+
var KEY_PREFIX = "hive_live_";
|
|
58310
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
58311
|
+
var START_LENGTH = KEY_PREFIX.length + 4;
|
|
58312
|
+
var BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
58313
|
+
function randomBase58(length) {
|
|
58314
|
+
return Array.from({ length }, () => BASE58[randomInt(BASE58.length)]).join("");
|
|
58315
|
+
}
|
|
58316
|
+
function hashKey(key) {
|
|
58317
|
+
return createHash6("sha256").update(key).digest("hex");
|
|
58308
58318
|
}
|
|
58309
58319
|
function normalizeAnalyticsTags(tags) {
|
|
58310
58320
|
const normalized = /* @__PURE__ */ new Set();
|
|
@@ -58317,6 +58327,24 @@ function normalizeAnalyticsTags(tags) {
|
|
|
58317
58327
|
}
|
|
58318
58328
|
return [...normalized];
|
|
58319
58329
|
}
|
|
58330
|
+
function withoutStalePlan(meta2) {
|
|
58331
|
+
if (!meta2) return void 0;
|
|
58332
|
+
const { plan: _stalePlan, ...rest } = meta2;
|
|
58333
|
+
return rest;
|
|
58334
|
+
}
|
|
58335
|
+
var VERIFY_CACHE_TTL_MS = 3e4;
|
|
58336
|
+
var VERIFY_CACHE_MAX = 1e4;
|
|
58337
|
+
var verifyCache = /* @__PURE__ */ new Map();
|
|
58338
|
+
function cacheVerified(keyHash, result2) {
|
|
58339
|
+
if (verifyCache.size >= VERIFY_CACHE_MAX) {
|
|
58340
|
+
const oldest = verifyCache.keys().next().value;
|
|
58341
|
+
if (oldest !== void 0) verifyCache.delete(oldest);
|
|
58342
|
+
}
|
|
58343
|
+
verifyCache.set(keyHash, {
|
|
58344
|
+
result: result2,
|
|
58345
|
+
expiresAt: Date.now() + VERIFY_CACHE_TTL_MS
|
|
58346
|
+
});
|
|
58347
|
+
}
|
|
58320
58348
|
async function getPlan(planId) {
|
|
58321
58349
|
const supabase = getSupabaseAdmin();
|
|
58322
58350
|
const { data, error } = await supabase.from("plans").select("*").eq("id", planId).single();
|
|
@@ -58325,32 +58353,10 @@ async function getPlan(planId) {
|
|
|
58325
58353
|
}
|
|
58326
58354
|
return data;
|
|
58327
58355
|
}
|
|
58328
|
-
var KEYS_PAGE_LIMIT = 100;
|
|
58329
|
-
var KEYS_MAX_PAGES = 100;
|
|
58330
|
-
async function listAllUserKeysRaw(userId) {
|
|
58331
|
-
const apiId = getApiId();
|
|
58332
|
-
const all = [];
|
|
58333
|
-
let cursor;
|
|
58334
|
-
for (let page = 0; page < KEYS_MAX_PAGES; page += 1) {
|
|
58335
|
-
const unkey = await getUnkey();
|
|
58336
|
-
const result2 = await unkey.apis.listKeys({
|
|
58337
|
-
apiId,
|
|
58338
|
-
externalId: userId,
|
|
58339
|
-
limit: KEYS_PAGE_LIMIT,
|
|
58340
|
-
revalidateKeysCache: true,
|
|
58341
|
-
...cursor ? { cursor } : {}
|
|
58342
|
-
});
|
|
58343
|
-
const keys = Array.isArray(result2.result.data) ? result2.result.data : [];
|
|
58344
|
-
all.push(...keys);
|
|
58345
|
-
const pagination = result2.result.pagination;
|
|
58346
|
-
if (!pagination?.hasMore || !pagination.cursor) break;
|
|
58347
|
-
cursor = pagination.cursor;
|
|
58348
|
-
}
|
|
58349
|
-
return all;
|
|
58350
|
-
}
|
|
58351
58356
|
async function countActiveUserKeys(userId) {
|
|
58352
|
-
const
|
|
58353
|
-
|
|
58357
|
+
const { count, error } = await getSupabaseAdmin().from("api_keys").select("id", { count: "exact", head: true }).eq("user_id", userId).eq("enabled", true);
|
|
58358
|
+
if (error) throw new Error(`Counting API keys failed: ${error.message}`);
|
|
58359
|
+
return count ?? 0;
|
|
58354
58360
|
}
|
|
58355
58361
|
var KEY_CREATION_LEASE_TTL_SECONDS = 120;
|
|
58356
58362
|
var KEY_CREATION_LEASE_WAIT_MS = 1e4;
|
|
@@ -58406,82 +58412,114 @@ async function createApiKey(opts) {
|
|
|
58406
58412
|
subject_signing_secret: subjectSigningSecret
|
|
58407
58413
|
} : {}
|
|
58408
58414
|
};
|
|
58409
|
-
const
|
|
58410
|
-
const
|
|
58411
|
-
|
|
58412
|
-
|
|
58415
|
+
const key = KEY_PREFIX + randomBase58(33);
|
|
58416
|
+
const keyId = `key_${randomBase58(16)}`;
|
|
58417
|
+
const { error } = await getSupabaseAdmin().from("api_keys").insert({
|
|
58418
|
+
id: keyId,
|
|
58419
|
+
user_id: opts.userId,
|
|
58413
58420
|
name: opts.name,
|
|
58414
|
-
|
|
58415
|
-
|
|
58416
|
-
meta: meta2
|
|
58417
|
-
enabled: true
|
|
58421
|
+
start: key.slice(0, START_LENGTH),
|
|
58422
|
+
key_hash: hashKey(key),
|
|
58423
|
+
meta: meta2
|
|
58418
58424
|
});
|
|
58419
|
-
if (
|
|
58420
|
-
secureLogger.error("
|
|
58421
|
-
|
|
58425
|
+
if (error) {
|
|
58426
|
+
secureLogger.error("API key insert failed", error, {
|
|
58427
|
+
userId: opts.userId
|
|
58422
58428
|
});
|
|
58423
58429
|
throw new Error("Failed to create API key");
|
|
58424
58430
|
}
|
|
58425
|
-
return {
|
|
58426
|
-
keyId: result2.data.keyId,
|
|
58427
|
-
key: result2.data.key,
|
|
58428
|
-
subjectSigningSecret
|
|
58429
|
-
};
|
|
58431
|
+
return { keyId, key, subjectSigningSecret };
|
|
58430
58432
|
} finally {
|
|
58431
58433
|
await releaseKeyCreationLease(opts.userId, leaseToken);
|
|
58432
58434
|
}
|
|
58433
58435
|
}
|
|
58434
|
-
async function
|
|
58436
|
+
async function verifyLegacyUnkeyKey(rawKey, keyHash, analyticsTags) {
|
|
58435
58437
|
const tags = normalizeAnalyticsTags(analyticsTags);
|
|
58436
|
-
const
|
|
58437
|
-
const result2 = await unkey.keys.verifyKey({
|
|
58438
|
+
const { data: body } = await legacyUnkey().post("/keys.verifyKey", {
|
|
58438
58439
|
key: rawKey,
|
|
58439
58440
|
...tags.length > 0 ? { tags } : {}
|
|
58440
58441
|
});
|
|
58441
|
-
|
|
58442
|
-
|
|
58443
|
-
|
|
58444
|
-
|
|
58445
|
-
|
|
58442
|
+
const d = body?.data;
|
|
58443
|
+
if (!d) throw new Error("Unkey verifyKey answered without a result");
|
|
58444
|
+
if (!d.valid) return { valid: false, code: d.code ?? "UNKNOWN" };
|
|
58445
|
+
const userId = d.identity?.externalId;
|
|
58446
|
+
if (!d.keyId || !userId || !UUID_PATTERN.test(userId)) {
|
|
58447
|
+
return { valid: false, code: "NOT_FOUND" };
|
|
58448
|
+
}
|
|
58449
|
+
const { data: enabled, error } = await getSupabaseAdmin().rpc(
|
|
58450
|
+
"migrate_unkey_api_key",
|
|
58451
|
+
{
|
|
58452
|
+
p_id: d.keyId,
|
|
58453
|
+
p_user_id: userId,
|
|
58454
|
+
p_key_hash: keyHash,
|
|
58455
|
+
p_name: d.name ?? "Unnamed",
|
|
58456
|
+
p_start: rawKey.slice(0, START_LENGTH),
|
|
58457
|
+
p_meta: withoutStalePlan(d.meta) ?? {}
|
|
58458
|
+
}
|
|
58459
|
+
);
|
|
58460
|
+
if (error) {
|
|
58461
|
+
throw new Error(`Recording a legacy API key failed: ${error.message}`);
|
|
58462
|
+
}
|
|
58463
|
+
if (enabled !== true) {
|
|
58464
|
+
return { valid: false, code: "DISABLED", keyId: d.keyId };
|
|
58446
58465
|
}
|
|
58447
|
-
const d = result2.data;
|
|
58448
58466
|
return {
|
|
58449
|
-
valid:
|
|
58450
|
-
code:
|
|
58467
|
+
valid: true,
|
|
58468
|
+
code: "VALID",
|
|
58451
58469
|
keyId: d.keyId,
|
|
58452
|
-
userId
|
|
58470
|
+
userId,
|
|
58453
58471
|
name: d.name,
|
|
58454
|
-
|
|
58455
|
-
meta: d.meta ?? void 0
|
|
58472
|
+
meta: withoutStalePlan(d.meta)
|
|
58456
58473
|
};
|
|
58457
58474
|
}
|
|
58475
|
+
async function verifyApiKey(rawKey, analyticsTags = []) {
|
|
58476
|
+
const keyHash = hashKey(rawKey);
|
|
58477
|
+
const cached = verifyCache.get(keyHash);
|
|
58478
|
+
if (cached && cached.expiresAt > Date.now()) return cached.result;
|
|
58479
|
+
const { data: row, error } = await getSupabaseAdmin().from("api_keys").select("id, user_id, name, meta, enabled").eq("key_hash", keyHash).maybeSingle();
|
|
58480
|
+
if (error) throw new Error(`API key lookup failed: ${error.message}`);
|
|
58481
|
+
let result2;
|
|
58482
|
+
if (row) {
|
|
58483
|
+
result2 = row.enabled ? {
|
|
58484
|
+
valid: true,
|
|
58485
|
+
code: "VALID",
|
|
58486
|
+
keyId: row.id,
|
|
58487
|
+
userId: row.user_id,
|
|
58488
|
+
name: row.name,
|
|
58489
|
+
meta: row.meta ?? void 0
|
|
58490
|
+
} : { valid: false, code: "DISABLED", keyId: row.id };
|
|
58491
|
+
} else if (isLegacyUnkeyConfigured()) {
|
|
58492
|
+
result2 = await verifyLegacyUnkeyKey(rawKey, keyHash, analyticsTags);
|
|
58493
|
+
} else {
|
|
58494
|
+
result2 = { valid: false, code: "NOT_FOUND" };
|
|
58495
|
+
}
|
|
58496
|
+
if (result2.valid) cacheVerified(keyHash, result2);
|
|
58497
|
+
return result2;
|
|
58498
|
+
}
|
|
58458
58499
|
async function listKeys(userId) {
|
|
58459
|
-
const
|
|
58460
|
-
if (keys
|
|
58461
|
-
return
|
|
58462
|
-
keyId: k.
|
|
58500
|
+
const { data, error } = await getSupabaseAdmin().from("api_keys").select("id, name, start, enabled, meta, created_at").eq("user_id", userId).order("created_at", { ascending: true });
|
|
58501
|
+
if (error) throw new Error(`Listing API keys failed: ${error.message}`);
|
|
58502
|
+
return (data ?? []).map((k) => ({
|
|
58503
|
+
keyId: k.id,
|
|
58463
58504
|
name: k.name ?? "Unnamed",
|
|
58464
58505
|
prefix: k.start ?? "",
|
|
58465
|
-
createdAt:
|
|
58506
|
+
createdAt: new Date(k.created_at).toISOString(),
|
|
58466
58507
|
enabled: k.enabled ?? true,
|
|
58467
|
-
|
|
58468
|
-
|
|
58469
|
-
meta: withoutStalePlan(
|
|
58470
|
-
sanitizeKeyMeta(k.meta ?? void 0)
|
|
58471
|
-
)
|
|
58508
|
+
externalId: userId,
|
|
58509
|
+
meta: withoutStalePlan(sanitizeKeyMeta(k.meta ?? void 0))
|
|
58472
58510
|
}));
|
|
58473
58511
|
}
|
|
58474
|
-
function withoutStalePlan(meta2) {
|
|
58475
|
-
if (!meta2) return void 0;
|
|
58476
|
-
const { plan: _stalePlan, ...rest } = meta2;
|
|
58477
|
-
return rest;
|
|
58478
|
-
}
|
|
58479
58512
|
async function revokeKey(keyId) {
|
|
58480
|
-
const
|
|
58481
|
-
|
|
58482
|
-
|
|
58483
|
-
|
|
58484
|
-
|
|
58513
|
+
const { data, error } = await getSupabaseAdmin().from("api_keys").update({ enabled: false }).eq("id", keyId).select("key_hash, source").maybeSingle();
|
|
58514
|
+
if (error) throw new Error(`Revoking API key failed: ${error.message}`);
|
|
58515
|
+
if (data?.key_hash) verifyCache.delete(data.key_hash);
|
|
58516
|
+
if (data?.source === "unkey" && isLegacyUnkeyConfigured()) {
|
|
58517
|
+
await legacyUnkey().post("/keys.updateKey", { keyId, enabled: false }).catch(
|
|
58518
|
+
(err) => secureLogger.error("Unkey disable failed; the key stays revoked in Hive", err, {
|
|
58519
|
+
keyId
|
|
58520
|
+
})
|
|
58521
|
+
);
|
|
58522
|
+
}
|
|
58485
58523
|
}
|
|
58486
58524
|
|
|
58487
58525
|
// src/health/mcpProtocol.ts
|
|
@@ -58491,28 +58529,28 @@ function getStaticApiKeys() {
|
|
|
58491
58529
|
function getHttpMcpAuthReadiness() {
|
|
58492
58530
|
const backend = getAuthBackendMode();
|
|
58493
58531
|
const staticKeyCount = getStaticApiKeys().length;
|
|
58494
|
-
if (
|
|
58495
|
-
if (!
|
|
58532
|
+
if (isHostedKeysRequired()) {
|
|
58533
|
+
if (!isHostedKeysConfigured()) {
|
|
58496
58534
|
return {
|
|
58497
58535
|
status: "missing_key",
|
|
58498
58536
|
backend,
|
|
58499
58537
|
configured: false,
|
|
58500
|
-
detail: "
|
|
58538
|
+
detail: "Hosted API key authentication is selected but SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY is missing."
|
|
58501
58539
|
};
|
|
58502
58540
|
}
|
|
58503
58541
|
return {
|
|
58504
58542
|
status: "ok",
|
|
58505
58543
|
backend,
|
|
58506
58544
|
configured: true,
|
|
58507
|
-
detail: "
|
|
58545
|
+
detail: "Hosted API key authentication is configured for HTTP MCP."
|
|
58508
58546
|
};
|
|
58509
58547
|
}
|
|
58510
|
-
if (
|
|
58548
|
+
if (isHostedKeysConfigured()) {
|
|
58511
58549
|
return {
|
|
58512
58550
|
status: "ok",
|
|
58513
58551
|
backend,
|
|
58514
58552
|
configured: true,
|
|
58515
|
-
detail: "
|
|
58553
|
+
detail: "Hosted API key authentication is configured for HTTP MCP."
|
|
58516
58554
|
};
|
|
58517
58555
|
}
|
|
58518
58556
|
if (staticKeyCount > 0) {
|
|
@@ -58527,7 +58565,7 @@ function getHttpMcpAuthReadiness() {
|
|
|
58527
58565
|
status: "missing_key",
|
|
58528
58566
|
backend,
|
|
58529
58567
|
configured: false,
|
|
58530
|
-
detail: "HTTP MCP authentication is not configured. Set
|
|
58568
|
+
detail: "HTTP MCP authentication is not configured. Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY for hosted keys, or HIVE_AUTH_BACKEND=static with HIVE_API_KEYS."
|
|
58531
58569
|
};
|
|
58532
58570
|
}
|
|
58533
58571
|
async function timedCheck(name, fn) {
|
|
@@ -58912,7 +58950,7 @@ async function runMcpProtocolHealth(options = {}) {
|
|
|
58912
58950
|
}
|
|
58913
58951
|
|
|
58914
58952
|
// src/health/oauthLifecycle.ts
|
|
58915
|
-
import { createHash as
|
|
58953
|
+
import { createHash as createHash8, randomBytes as randomBytes3 } from "crypto";
|
|
58916
58954
|
|
|
58917
58955
|
// src/auth/oauth/provider.ts
|
|
58918
58956
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -59288,10 +59326,10 @@ function isHiveOAuthAccessToken(token) {
|
|
|
59288
59326
|
}
|
|
59289
59327
|
|
|
59290
59328
|
// src/auth/oauth/store.ts
|
|
59291
|
-
import { createHash as
|
|
59329
|
+
import { createHash as createHash7 } from "crypto";
|
|
59292
59330
|
var REVOKED_FAMILY_TTL_SECONDS = 7776e3;
|
|
59293
59331
|
function digest(value) {
|
|
59294
|
-
return
|
|
59332
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
59295
59333
|
}
|
|
59296
59334
|
function parseJson(raw) {
|
|
59297
59335
|
if (!raw) return void 0;
|
|
@@ -59700,7 +59738,7 @@ var OAUTH_LIFECYCLE_CHECK_NAMES = [
|
|
|
59700
59738
|
"token_revocation",
|
|
59701
59739
|
"connected_app_cleanup"
|
|
59702
59740
|
];
|
|
59703
|
-
var
|
|
59741
|
+
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
59704
59742
|
function elapsed(started) {
|
|
59705
59743
|
return Math.max(0, Date.now() - started);
|
|
59706
59744
|
}
|
|
@@ -59743,7 +59781,7 @@ async function operationRejects(operation) {
|
|
|
59743
59781
|
}
|
|
59744
59782
|
async function issueCanaryFamily(args) {
|
|
59745
59783
|
const verifier = randomBytes3(48).toString("base64url");
|
|
59746
|
-
const challenge =
|
|
59784
|
+
const challenge = createHash8("sha256").update(verifier).digest("base64url");
|
|
59747
59785
|
let consentLocation;
|
|
59748
59786
|
const response = {
|
|
59749
59787
|
redirect(status, location) {
|
|
@@ -59863,7 +59901,7 @@ async function runOAuthLifecycleHealth(overrides = {}) {
|
|
|
59863
59901
|
}
|
|
59864
59902
|
const userStarted = Date.now();
|
|
59865
59903
|
const canaryUserId = dependencies.canaryUserId;
|
|
59866
|
-
if (!canaryUserId || !
|
|
59904
|
+
if (!canaryUserId || !UUID_PATTERN2.test(canaryUserId)) {
|
|
59867
59905
|
checks.push(
|
|
59868
59906
|
check(
|
|
59869
59907
|
"canary_identity",
|
|
@@ -60055,7 +60093,7 @@ async function runOAuthLifecycleHealth(overrides = {}) {
|
|
|
60055
60093
|
import Coingecko4 from "@coingecko/coingecko-typescript";
|
|
60056
60094
|
|
|
60057
60095
|
// src/tools/goplus/goplusClient.ts
|
|
60058
|
-
import { createHash as
|
|
60096
|
+
import { createHash as createHash9 } from "crypto";
|
|
60059
60097
|
function parsePositiveInteger(value, fallback) {
|
|
60060
60098
|
const parsed = Number.parseInt(value || "", 10);
|
|
60061
60099
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
@@ -60149,7 +60187,7 @@ var GoPlusClient = class {
|
|
|
60149
60187
|
const time = Math.floor(Date.now() / 1e3);
|
|
60150
60188
|
const timeStr = time.toString();
|
|
60151
60189
|
const signInput = this.appKey + timeStr + this.appSecret;
|
|
60152
|
-
const sign =
|
|
60190
|
+
const sign = createHash9("sha1").update(signInput).digest("hex");
|
|
60153
60191
|
secureLogger.info("GoPlus: requesting access token", {
|
|
60154
60192
|
appKeyLength: this.appKey.length,
|
|
60155
60193
|
appSecretLength: this.appSecret.length,
|
|
@@ -66033,32 +66071,32 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66033
66071
|
const taskToolsetCatalogEntries = TASK_TOOLSETS.map(
|
|
66034
66072
|
(toolset) => toolsetCatalogEntry(toolset, providerByToolName)
|
|
66035
66073
|
);
|
|
66036
|
-
const searchToolsSchema =
|
|
66037
|
-
query:
|
|
66074
|
+
const searchToolsSchema = z3.object({
|
|
66075
|
+
query: z3.string().max(512).optional().describe(
|
|
66038
66076
|
"Search text matched against tool name, title, category, provider, and summary."
|
|
66039
66077
|
),
|
|
66040
|
-
provider:
|
|
66078
|
+
provider: z3.string().max(128).optional().describe(
|
|
66041
66079
|
"Optional provider filter such as CoinGecko, Tenderly, Helius, GoPlus, CCXT, Alchemy, DeFiLlama, Hyperliquid, or Open Data Fetch."
|
|
66042
66080
|
),
|
|
66043
|
-
category:
|
|
66044
|
-
limit:
|
|
66045
|
-
cursor:
|
|
66046
|
-
toolset_id:
|
|
66081
|
+
category: z3.string().max(128).optional().describe("Optional category filter, for example Portfolio & Wallet."),
|
|
66082
|
+
limit: z3.number().int().min(1).max(MAX_SEARCH_LIMIT).optional().describe(`Maximum tools to return. Default ${DEFAULT_SEARCH_LIMIT}.`),
|
|
66083
|
+
cursor: z3.string().optional().describe("Pagination cursor from the previous response."),
|
|
66084
|
+
toolset_id: z3.string().max(100).optional().describe(
|
|
66047
66085
|
"Optional exact canonical task toolset id. Use this after an initial compact result to inspect one workflow."
|
|
66048
66086
|
),
|
|
66049
|
-
route_id:
|
|
66087
|
+
route_id: z3.string().max(100).optional().describe(
|
|
66050
66088
|
"Optional exact task-shaped route id. Use the matched route's ordered calls and conditional fallbacks instead of choosing from the coverage catalog."
|
|
66051
66089
|
),
|
|
66052
|
-
evidence_phase:
|
|
66090
|
+
evidence_phase: z3.string().max(100).optional().describe(
|
|
66053
66091
|
`Optional exact workflow evidence phase. Supported values: ${CANONICAL_EVIDENCE_PHASES.join(", ")}.`
|
|
66054
66092
|
),
|
|
66055
|
-
detail:
|
|
66093
|
+
detail: z3.enum(["compact", "standard", "full"]).optional().describe(
|
|
66056
66094
|
"Toolset detail level. Defaults to compact. Use full only when the task output schema is needed."
|
|
66057
66095
|
),
|
|
66058
|
-
toolset_limit:
|
|
66096
|
+
toolset_limit: z3.number().int().min(1).max(MAX_TOOLSET_LIMIT).optional().describe(
|
|
66059
66097
|
`Maximum matching task toolsets to return. Default ${DEFAULT_TOOLSET_LIMIT}, max ${MAX_TOOLSET_LIMIT}.`
|
|
66060
66098
|
),
|
|
66061
|
-
toolset_cursor:
|
|
66099
|
+
toolset_cursor: z3.string().optional().describe("Pagination cursor for task toolset matches.")
|
|
66062
66100
|
});
|
|
66063
66101
|
const searchToolsTool = {
|
|
66064
66102
|
metadata: {
|
|
@@ -66192,9 +66230,9 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66192
66230
|
});
|
|
66193
66231
|
}
|
|
66194
66232
|
};
|
|
66195
|
-
const getEndpointSchema =
|
|
66196
|
-
endpoint:
|
|
66197
|
-
endpoint_name:
|
|
66233
|
+
const getEndpointSchema = z3.object({
|
|
66234
|
+
endpoint: z3.string().optional().describe("The name of the endpoint to get the schema for."),
|
|
66235
|
+
endpoint_name: z3.string().optional().describe(
|
|
66198
66236
|
"Alias for 'endpoint', accepted for symmetry with invoke_api_endpoint. Provide one of the two."
|
|
66199
66237
|
)
|
|
66200
66238
|
});
|
|
@@ -66272,12 +66310,12 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66272
66310
|
});
|
|
66273
66311
|
}
|
|
66274
66312
|
};
|
|
66275
|
-
const invokeEndpointSchema =
|
|
66276
|
-
endpoint_name:
|
|
66277
|
-
endpoint:
|
|
66313
|
+
const invokeEndpointSchema = z3.object({
|
|
66314
|
+
endpoint_name: z3.string().optional().describe("The name of the endpoint to invoke."),
|
|
66315
|
+
endpoint: z3.string().optional().describe(
|
|
66278
66316
|
"Alias for 'endpoint_name', accepted by both root invokers. Provide one of the two."
|
|
66279
66317
|
),
|
|
66280
|
-
args:
|
|
66318
|
+
args: z3.record(z3.string(), z3.any()).optional().describe(
|
|
66281
66319
|
"The arguments to pass to the endpoint. This must match the schema returned by the `get_api_endpoint_schema` tool. You may also pass arguments as flat top-level keys alongside endpoint_name."
|
|
66282
66320
|
)
|
|
66283
66321
|
}).passthrough();
|
|
@@ -66348,9 +66386,9 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66348
66386
|
},
|
|
66349
66387
|
handler: async (client2, args) => invokeWithPolicy(STATEFUL_WRITE_ENDPOINT_INVOKER, client2, args)
|
|
66350
66388
|
};
|
|
66351
|
-
const validateTaskResultSchema =
|
|
66352
|
-
task_toolset_id:
|
|
66353
|
-
result:
|
|
66389
|
+
const validateTaskResultSchema = z3.object({
|
|
66390
|
+
task_toolset_id: z3.string().describe("Canonical task toolset id returned by search_tools."),
|
|
66391
|
+
result: z3.record(z3.string(), z3.any()).describe(
|
|
66354
66392
|
"The proposed task result envelope. Each receipt.calls entry must be copied exactly from a material call's _hive object."
|
|
66355
66393
|
)
|
|
66356
66394
|
});
|
|
@@ -66642,10 +66680,10 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66642
66680
|
}
|
|
66643
66681
|
};
|
|
66644
66682
|
const categoryTools = ToolRegistry.map((category, categoryIndex) => {
|
|
66645
|
-
const categorySchema =
|
|
66646
|
-
search:
|
|
66647
|
-
limit:
|
|
66648
|
-
cursor:
|
|
66683
|
+
const categorySchema = z3.object({
|
|
66684
|
+
search: z3.string().optional().describe("Ignored; retained for 1.2.0 compatibility."),
|
|
66685
|
+
limit: z3.number().int().optional().describe("Ignored; retained for 1.2.0 compatibility."),
|
|
66686
|
+
cursor: z3.string().optional().describe("Ignored; retained for 1.2.0 compatibility.")
|
|
66649
66687
|
});
|
|
66650
66688
|
const categoryEndpointName = category.name;
|
|
66651
66689
|
const categoryPath = CategoryEndpoints[categoryIndex] ?? "";
|
|
@@ -66724,7 +66762,7 @@ function dynamicTools(endpoints, options = {}) {
|
|
|
66724
66762
|
}
|
|
66725
66763
|
|
|
66726
66764
|
// src/utils/jsonSchemaToZod.ts
|
|
66727
|
-
import { z as
|
|
66765
|
+
import { z as z4 } from "zod";
|
|
66728
66766
|
var TOP_LEVEL_COMBINATORS = /* @__PURE__ */ new Set([
|
|
66729
66767
|
"allOf",
|
|
66730
66768
|
"anyOf",
|
|
@@ -66806,10 +66844,10 @@ function zodPath(field) {
|
|
|
66806
66844
|
});
|
|
66807
66845
|
}
|
|
66808
66846
|
function jsonSchemaToZodInputSchema(schema) {
|
|
66809
|
-
const base =
|
|
66847
|
+
const base = z4.fromJSONSchema(
|
|
66810
66848
|
zodBaseSchema(schema)
|
|
66811
66849
|
);
|
|
66812
|
-
if (!(base instanceof
|
|
66850
|
+
if (!(base instanceof z4.ZodObject)) {
|
|
66813
66851
|
throw new Error("Tool input schema must compile to a Zod object");
|
|
66814
66852
|
}
|
|
66815
66853
|
const properties = schema.properties ?? {};
|
|
@@ -66856,34 +66894,34 @@ function jsonSchemaToZodShape(schema) {
|
|
|
66856
66894
|
return shape;
|
|
66857
66895
|
}
|
|
66858
66896
|
function jsonSchemaToZodObject(schema, options = {}) {
|
|
66859
|
-
const objectSchema =
|
|
66897
|
+
const objectSchema = z4.object(jsonSchemaToZodShape(schema));
|
|
66860
66898
|
return options.passthrough ? objectSchema.passthrough() : objectSchema;
|
|
66861
66899
|
}
|
|
66862
66900
|
function buildZodType(prop) {
|
|
66863
66901
|
const type = prop.type;
|
|
66864
66902
|
const enumValues = prop.enum;
|
|
66865
66903
|
if (enumValues && enumValues.length > 0) {
|
|
66866
|
-
return
|
|
66904
|
+
return z4.enum(enumValues);
|
|
66867
66905
|
}
|
|
66868
66906
|
switch (type) {
|
|
66869
66907
|
case "string":
|
|
66870
|
-
return
|
|
66908
|
+
return z4.string();
|
|
66871
66909
|
case "number":
|
|
66872
66910
|
case "integer":
|
|
66873
|
-
return
|
|
66911
|
+
return z4.number();
|
|
66874
66912
|
case "boolean":
|
|
66875
|
-
return
|
|
66913
|
+
return z4.boolean();
|
|
66876
66914
|
case "array":
|
|
66877
|
-
return
|
|
66915
|
+
return z4.array(z4.unknown());
|
|
66878
66916
|
case "object":
|
|
66879
|
-
return
|
|
66917
|
+
return z4.record(z4.string(), z4.unknown());
|
|
66880
66918
|
default:
|
|
66881
|
-
return
|
|
66919
|
+
return z4.unknown();
|
|
66882
66920
|
}
|
|
66883
66921
|
}
|
|
66884
66922
|
|
|
66885
66923
|
// src/mcpServer.ts
|
|
66886
|
-
|
|
66924
|
+
loadEnvFile();
|
|
66887
66925
|
var ROOT_META_TOOL_COUNT = getRootVisibleToolCount();
|
|
66888
66926
|
var ROOT_VISIBLE_TOOL_ORDER = [
|
|
66889
66927
|
"get_token_price",
|
|
@@ -67629,12 +67667,6 @@ var HiveMCPServer = class {
|
|
|
67629
67667
|
"/api/health/toolsets/quick",
|
|
67630
67668
|
"/api/health/toolsets/history"
|
|
67631
67669
|
],
|
|
67632
|
-
unkeyAnalyticsTags: [
|
|
67633
|
-
"service=hive",
|
|
67634
|
-
"transport=rest",
|
|
67635
|
-
"route=<route>",
|
|
67636
|
-
"endpoint=<tool_name>"
|
|
67637
|
-
],
|
|
67638
67670
|
mcpToolCallLogFields: [
|
|
67639
67671
|
"tool",
|
|
67640
67672
|
"success",
|
|
@@ -67811,14 +67843,6 @@ function createHiveMcpServer(scope, options) {
|
|
|
67811
67843
|
}
|
|
67812
67844
|
|
|
67813
67845
|
export {
|
|
67814
|
-
getEnvVar,
|
|
67815
|
-
getCsvEnv,
|
|
67816
|
-
getNodeEnv,
|
|
67817
|
-
isProduction,
|
|
67818
|
-
getPort,
|
|
67819
|
-
getRateLimitMax,
|
|
67820
|
-
getCredentialedRateLimitMax,
|
|
67821
|
-
getCorsAllowedOrigins,
|
|
67822
67846
|
isSupabaseConfigured,
|
|
67823
67847
|
getSupabaseAdmin,
|
|
67824
67848
|
getUserPlanId,
|
|
@@ -67881,8 +67905,8 @@ export {
|
|
|
67881
67905
|
OAUTH_CLIENT_REDIRECT_PROFILES,
|
|
67882
67906
|
MAX_DCR_CLIENT_METADATA_BYTES,
|
|
67883
67907
|
buildAuthCompatibility,
|
|
67884
|
-
|
|
67885
|
-
|
|
67908
|
+
isHostedKeysRequired,
|
|
67909
|
+
isHostedKeysConfigured,
|
|
67886
67910
|
createApiKey,
|
|
67887
67911
|
verifyApiKey,
|
|
67888
67912
|
listKeys,
|