@guiie/buda-mcp 1.2.2 → 1.4.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/CHANGELOG.md +68 -0
- package/PUBLISH_CHECKLIST.md +71 -63
- package/README.md +4 -4
- package/dist/http.js +39 -0
- package/dist/index.js +29 -0
- package/dist/tools/arbitrage.d.ts +35 -0
- package/dist/tools/arbitrage.d.ts.map +1 -0
- package/dist/tools/arbitrage.js +142 -0
- package/dist/tools/balances.d.ts.map +1 -1
- package/dist/tools/balances.js +24 -4
- package/dist/tools/calculate_position_size.d.ts +48 -0
- package/dist/tools/calculate_position_size.d.ts.map +1 -0
- package/dist/tools/calculate_position_size.js +111 -0
- package/dist/tools/compare_markets.d.ts.map +1 -1
- package/dist/tools/compare_markets.js +11 -10
- package/dist/tools/dead_mans_switch.d.ts +84 -0
- package/dist/tools/dead_mans_switch.d.ts.map +1 -0
- package/dist/tools/dead_mans_switch.js +236 -0
- package/dist/tools/market_sentiment.d.ts +30 -0
- package/dist/tools/market_sentiment.d.ts.map +1 -0
- package/dist/tools/market_sentiment.js +104 -0
- package/dist/tools/market_summary.d.ts +43 -0
- package/dist/tools/market_summary.d.ts.map +1 -0
- package/dist/tools/market_summary.js +81 -0
- package/dist/tools/markets.d.ts.map +1 -1
- package/dist/tools/markets.js +4 -2
- package/dist/tools/orderbook.d.ts.map +1 -1
- package/dist/tools/orderbook.js +14 -4
- package/dist/tools/orders.d.ts.map +1 -1
- package/dist/tools/orders.js +41 -3
- package/dist/tools/price_history.d.ts.map +1 -1
- package/dist/tools/price_history.js +5 -43
- package/dist/tools/simulate_order.d.ts +45 -0
- package/dist/tools/simulate_order.d.ts.map +1 -0
- package/dist/tools/simulate_order.js +139 -0
- package/dist/tools/spread.d.ts.map +1 -1
- package/dist/tools/spread.js +10 -8
- package/dist/tools/technical_indicators.d.ts +39 -0
- package/dist/tools/technical_indicators.d.ts.map +1 -0
- package/dist/tools/technical_indicators.js +223 -0
- package/dist/tools/ticker.d.ts.map +1 -1
- package/dist/tools/ticker.js +24 -3
- package/dist/tools/trades.d.ts.map +1 -1
- package/dist/tools/trades.js +17 -3
- package/dist/tools/volume.d.ts.map +1 -1
- package/dist/tools/volume.js +21 -3
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +23 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +68 -0
- package/marketplace/README.md +1 -1
- package/marketplace/claude-listing.md +60 -14
- package/marketplace/gemini-tools.json +183 -9
- package/marketplace/openapi.yaml +335 -119
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/http.ts +44 -0
- package/src/index.ts +34 -0
- package/src/tools/arbitrage.ts +202 -0
- package/src/tools/balances.ts +27 -4
- package/src/tools/calculate_position_size.ts +141 -0
- package/src/tools/compare_markets.ts +11 -10
- package/src/tools/dead_mans_switch.ts +314 -0
- package/src/tools/market_sentiment.ts +141 -0
- package/src/tools/market_summary.ts +124 -0
- package/src/tools/markets.ts +4 -2
- package/src/tools/orderbook.ts +15 -4
- package/src/tools/orders.ts +45 -4
- package/src/tools/price_history.ts +5 -57
- package/src/tools/simulate_order.ts +182 -0
- package/src/tools/spread.ts +10 -8
- package/src/tools/technical_indicators.ts +282 -0
- package/src/tools/ticker.ts +27 -3
- package/src/tools/trades.ts +18 -3
- package/src/tools/volume.ts +24 -3
- package/src/types.ts +12 -0
- package/src/utils.ts +73 -0
- package/test/unit.ts +758 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { BudaApiError } from "../client.js";
|
|
3
|
+
import { CACHE_TTL } from "../cache.js";
|
|
4
|
+
import { validateMarketId } from "../validation.js";
|
|
5
|
+
export const toolSchema = {
|
|
6
|
+
name: "get_market_sentiment",
|
|
7
|
+
description: "Computes a composite sentiment score (−100 to +100) for a Buda.com market based on " +
|
|
8
|
+
"24h price variation (40%), volume vs 7-day average (35%), and bid/ask spread vs baseline (25%). " +
|
|
9
|
+
"Returns a score, a label (bearish/neutral/bullish), and a full component breakdown. " +
|
|
10
|
+
"Example: 'Is the BTC-CLP market currently bullish or bearish?'",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
market_id: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "Market ID (e.g. 'BTC-CLP', 'ETH-BTC', 'BTC-USDT').",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
required: ["market_id"],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
function clamp(value, min, max) {
|
|
23
|
+
return Math.min(max, Math.max(min, value));
|
|
24
|
+
}
|
|
25
|
+
function isStablecoinPair(marketId) {
|
|
26
|
+
return /-(USDT|USDC|DAI|TUSD)$/i.test(marketId);
|
|
27
|
+
}
|
|
28
|
+
export async function handleMarketSentiment({ market_id }, client, cache) {
|
|
29
|
+
const validationError = validateMarketId(market_id);
|
|
30
|
+
if (validationError) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const id = market_id.toLowerCase();
|
|
38
|
+
const [tickerData, volumeData] = await Promise.all([
|
|
39
|
+
cache.getOrFetch(`ticker:${id}`, CACHE_TTL.TICKER, () => client.get(`/markets/${id}/ticker`)),
|
|
40
|
+
client.get(`/markets/${id}/volume`),
|
|
41
|
+
]);
|
|
42
|
+
const ticker = tickerData.ticker;
|
|
43
|
+
const vol = volumeData.volume;
|
|
44
|
+
const bid = parseFloat(ticker.max_bid[0]);
|
|
45
|
+
const ask = parseFloat(ticker.min_ask[0]);
|
|
46
|
+
const priceVariation24h = parseFloat(ticker.price_variation_24h);
|
|
47
|
+
const ask24h = parseFloat(vol.ask_volume_24h[0]);
|
|
48
|
+
const bid24h = parseFloat(vol.bid_volume_24h[0]);
|
|
49
|
+
const ask7d = parseFloat(vol.ask_volume_7d[0]);
|
|
50
|
+
const bid7d = parseFloat(vol.bid_volume_7d[0]);
|
|
51
|
+
const spreadPct = ask > 0 ? ((ask - bid) / ask) * 100 : 0;
|
|
52
|
+
const spreadBaseline = isStablecoinPair(market_id) ? 0.3 : 1.0;
|
|
53
|
+
const volume24h = ask24h + bid24h;
|
|
54
|
+
const volume7d = ask7d + bid7d;
|
|
55
|
+
const volumeRatio = volume7d > 0 ? (volume24h * 7) / volume7d : 1;
|
|
56
|
+
// Price component: ±5% daily change → ±100 on this sub-score
|
|
57
|
+
const priceRaw = clamp(priceVariation24h * 2000, -100, 100);
|
|
58
|
+
const priceScore = parseFloat((priceRaw * 0.4).toFixed(4));
|
|
59
|
+
// Volume component: ratio vs 7d daily average
|
|
60
|
+
const volumeRaw = clamp((volumeRatio - 1) * 100, -100, 100);
|
|
61
|
+
const volumeScore = parseFloat((volumeRaw * 0.35).toFixed(4));
|
|
62
|
+
// Spread component: tighter spread is bullish
|
|
63
|
+
const spreadRaw = clamp((1 - spreadPct / spreadBaseline) * 100, -100, 100);
|
|
64
|
+
const spreadScore = parseFloat((spreadRaw * 0.25).toFixed(4));
|
|
65
|
+
const score = parseFloat((priceScore + volumeScore + spreadScore).toFixed(1));
|
|
66
|
+
const label = score < -20 ? "bearish" : score > 20 ? "bullish" : "neutral";
|
|
67
|
+
const result = {
|
|
68
|
+
market_id: ticker.market_id,
|
|
69
|
+
score,
|
|
70
|
+
label,
|
|
71
|
+
component_breakdown: {
|
|
72
|
+
price_variation_24h_pct: parseFloat((priceVariation24h * 100).toFixed(4)),
|
|
73
|
+
volume_ratio: parseFloat(volumeRatio.toFixed(4)),
|
|
74
|
+
spread_pct: parseFloat(spreadPct.toFixed(4)),
|
|
75
|
+
spread_baseline_pct: spreadBaseline,
|
|
76
|
+
price_score: priceScore,
|
|
77
|
+
volume_score: volumeScore,
|
|
78
|
+
spread_score: spreadScore,
|
|
79
|
+
},
|
|
80
|
+
data_timestamp: new Date().toISOString(),
|
|
81
|
+
disclaimer: "Sentiment is derived from market microstructure data only. Not investment advice.",
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const msg = err instanceof BudaApiError
|
|
89
|
+
? { error: err.message, code: err.status, path: err.path }
|
|
90
|
+
: { error: String(err), code: "UNKNOWN" };
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
93
|
+
isError: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function register(server, client, cache) {
|
|
98
|
+
server.tool(toolSchema.name, toolSchema.description, {
|
|
99
|
+
market_id: z
|
|
100
|
+
.string()
|
|
101
|
+
.describe("Market ID (e.g. 'BTC-CLP', 'ETH-BTC', 'BTC-USDT')."),
|
|
102
|
+
}, (args) => handleMarketSentiment(args, client, cache));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=market_sentiment.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BudaClient } from "../client.js";
|
|
3
|
+
import { MemoryCache } from "../cache.js";
|
|
4
|
+
export declare const toolSchema: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: "object";
|
|
9
|
+
properties: {
|
|
10
|
+
market_id: {
|
|
11
|
+
type: string;
|
|
12
|
+
description: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
required: string[];
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export interface MarketSummaryResult {
|
|
19
|
+
market_id: string;
|
|
20
|
+
last_price: number;
|
|
21
|
+
last_price_currency: string;
|
|
22
|
+
bid: number;
|
|
23
|
+
ask: number;
|
|
24
|
+
spread_pct: number;
|
|
25
|
+
volume_24h: number;
|
|
26
|
+
volume_24h_currency: string;
|
|
27
|
+
price_change_24h: number;
|
|
28
|
+
price_change_7d: number;
|
|
29
|
+
liquidity_rating: "high" | "medium" | "low";
|
|
30
|
+
}
|
|
31
|
+
interface MarketSummaryInput {
|
|
32
|
+
market_id: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function handleMarketSummary({ market_id }: MarketSummaryInput, client: BudaClient, cache: MemoryCache): Promise<{
|
|
35
|
+
content: Array<{
|
|
36
|
+
type: "text";
|
|
37
|
+
text: string;
|
|
38
|
+
}>;
|
|
39
|
+
isError?: boolean;
|
|
40
|
+
}>;
|
|
41
|
+
export declare function register(server: McpServer, client: BudaClient, cache: MemoryCache): void;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=market_summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"market_summary.d.ts","sourceRoot":"","sources":["../../src/tools/market_summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAKrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAkBtB,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CAC7C;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,mBAAmB,CACvC,EAAE,SAAS,EAAE,EAAE,kBAAkB,EACjC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA4DhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAWxF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { BudaApiError } from "../client.js";
|
|
3
|
+
import { CACHE_TTL } from "../cache.js";
|
|
4
|
+
import { validateMarketId } from "../validation.js";
|
|
5
|
+
import { flattenAmount, getLiquidityRating } from "../utils.js";
|
|
6
|
+
export const toolSchema = {
|
|
7
|
+
name: "get_market_summary",
|
|
8
|
+
description: "One-call summary of everything relevant about a market: last price, best bid/ask, spread %, " +
|
|
9
|
+
"24h volume, 24h and 7d price change, and a liquidity_rating ('high' / 'medium' / 'low' based on " +
|
|
10
|
+
"spread thresholds: < 0.3% = high, 0.3–1% = medium, > 1% = low). All prices and volumes are floats. " +
|
|
11
|
+
"Best first tool to call when a user asks about any specific market. " +
|
|
12
|
+
"Example: 'Give me a complete overview of the BTC-CLP market right now.'",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
market_id: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Market ID (e.g. 'BTC-CLP', 'ETH-COP', 'BTC-PEN').",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ["market_id"],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export async function handleMarketSummary({ market_id }, client, cache) {
|
|
25
|
+
try {
|
|
26
|
+
const validationError = validateMarketId(market_id);
|
|
27
|
+
if (validationError) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const id = market_id.toLowerCase();
|
|
34
|
+
// Fetch ticker and volume in parallel
|
|
35
|
+
const [tickerData, volumeData] = await Promise.all([
|
|
36
|
+
cache.getOrFetch(`ticker:${id}`, CACHE_TTL.TICKER, () => client.get(`/markets/${id}/ticker`)),
|
|
37
|
+
client.get(`/markets/${id}/volume`),
|
|
38
|
+
]);
|
|
39
|
+
const t = tickerData.ticker;
|
|
40
|
+
const v = volumeData.volume;
|
|
41
|
+
const lastPrice = flattenAmount(t.last_price);
|
|
42
|
+
const bid = parseFloat(t.max_bid[0]);
|
|
43
|
+
const ask = parseFloat(t.min_ask[0]);
|
|
44
|
+
const volume24h = flattenAmount(v.ask_volume_24h);
|
|
45
|
+
const spreadAbs = ask - bid;
|
|
46
|
+
const spreadPct = ask > 0 ? parseFloat(((spreadAbs / ask) * 100).toFixed(4)) : 0;
|
|
47
|
+
const result = {
|
|
48
|
+
market_id: t.market_id,
|
|
49
|
+
last_price: lastPrice.value,
|
|
50
|
+
last_price_currency: lastPrice.currency,
|
|
51
|
+
bid,
|
|
52
|
+
ask,
|
|
53
|
+
spread_pct: spreadPct,
|
|
54
|
+
volume_24h: volume24h.value,
|
|
55
|
+
volume_24h_currency: volume24h.currency,
|
|
56
|
+
price_change_24h: parseFloat((parseFloat(t.price_variation_24h) * 100).toFixed(4)),
|
|
57
|
+
price_change_7d: parseFloat((parseFloat(t.price_variation_7d) * 100).toFixed(4)),
|
|
58
|
+
liquidity_rating: getLiquidityRating(spreadPct),
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const msg = err instanceof BudaApiError
|
|
66
|
+
? { error: err.message, code: err.status, path: err.path }
|
|
67
|
+
: { error: String(err), code: "UNKNOWN" };
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
70
|
+
isError: true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function register(server, client, cache) {
|
|
75
|
+
server.tool(toolSchema.name, toolSchema.description, {
|
|
76
|
+
market_id: z
|
|
77
|
+
.string()
|
|
78
|
+
.describe("Market ID (e.g. 'BTC-CLP', 'ETH-COP', 'BTC-PEN')."),
|
|
79
|
+
}, (args) => handleMarketSummary(args, client, cache));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=market_summary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/tools/markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/tools/markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;CAgBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAsDxF"}
|
package/dist/tools/markets.js
CHANGED
|
@@ -4,8 +4,10 @@ import { CACHE_TTL } from "../cache.js";
|
|
|
4
4
|
import { validateMarketId } from "../validation.js";
|
|
5
5
|
export const toolSchema = {
|
|
6
6
|
name: "get_markets",
|
|
7
|
-
description: "
|
|
8
|
-
"
|
|
7
|
+
description: "Lists all available trading pairs on Buda.com, or returns details for a specific market " +
|
|
8
|
+
"(base/quote currencies, taker/maker fees as decimals, minimum order size in base currency, " +
|
|
9
|
+
"and fee discount tiers). Omit market_id to get all ~26 markets at once. " +
|
|
10
|
+
"Example: 'What is the taker fee and minimum order size for BTC-CLP?'",
|
|
9
11
|
inputSchema: {
|
|
10
12
|
type: "object",
|
|
11
13
|
properties: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.d.ts","sourceRoot":"","sources":["../../src/tools/orderbook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"orderbook.d.ts","sourceRoot":"","sources":["../../src/tools/orderbook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;CAqBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAgExF"}
|
package/dist/tools/orderbook.js
CHANGED
|
@@ -4,8 +4,10 @@ import { CACHE_TTL } from "../cache.js";
|
|
|
4
4
|
import { validateMarketId } from "../validation.js";
|
|
5
5
|
export const toolSchema = {
|
|
6
6
|
name: "get_orderbook",
|
|
7
|
-
description: "
|
|
8
|
-
"
|
|
7
|
+
description: "Returns the current order book for a Buda.com market as typed objects with float price and amount fields. " +
|
|
8
|
+
"Bids are sorted highest-price first; asks lowest-price first. " +
|
|
9
|
+
"Prices are in the quote currency; amounts are in the base currency. " +
|
|
10
|
+
"Example: 'What are the top 5 buy and sell orders for BTC-CLP right now?'",
|
|
9
11
|
inputSchema: {
|
|
10
12
|
type: "object",
|
|
11
13
|
properties: {
|
|
@@ -44,9 +46,17 @@ export function register(server, client, cache) {
|
|
|
44
46
|
const id = market_id.toLowerCase();
|
|
45
47
|
const data = await cache.getOrFetch(`orderbook:${id}`, CACHE_TTL.ORDERBOOK, () => client.get(`/markets/${id}/order_book`));
|
|
46
48
|
const book = data.order_book;
|
|
49
|
+
const bids = limit ? book.bids.slice(0, limit) : book.bids;
|
|
50
|
+
const asks = limit ? book.asks.slice(0, limit) : book.asks;
|
|
47
51
|
const result = {
|
|
48
|
-
bids:
|
|
49
|
-
|
|
52
|
+
bids: bids.map(([price, amount]) => ({
|
|
53
|
+
price: parseFloat(price),
|
|
54
|
+
amount: parseFloat(amount),
|
|
55
|
+
})),
|
|
56
|
+
asks: asks.map(([price, amount]) => ({
|
|
57
|
+
price: parseFloat(price),
|
|
58
|
+
amount: parseFloat(amount),
|
|
59
|
+
})),
|
|
50
60
|
bid_count: book.bids.length,
|
|
51
61
|
ask_count: book.asks.length,
|
|
52
62
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../../src/tools/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../../src/tools/orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA+BtB,CAAC;AAMF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAsGpE"}
|
package/dist/tools/orders.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
3
|
import { validateMarketId } from "../validation.js";
|
|
4
|
+
import { flattenAmount } from "../utils.js";
|
|
4
5
|
export const toolSchema = {
|
|
5
6
|
name: "get_orders",
|
|
6
|
-
description: "
|
|
7
|
-
"
|
|
7
|
+
description: "Returns orders for a given Buda.com market as flat typed objects. All monetary amounts are floats " +
|
|
8
|
+
"with separate _currency fields (e.g. amount + amount_currency). Filterable by state: pending, " +
|
|
9
|
+
"active, traded, canceled. Supports pagination via per and page. " +
|
|
10
|
+
"Requires BUDA_API_KEY and BUDA_API_SECRET. " +
|
|
11
|
+
"Example: 'Show my open limit orders on BTC-CLP.'",
|
|
8
12
|
inputSchema: {
|
|
9
13
|
type: "object",
|
|
10
14
|
properties: {
|
|
@@ -28,6 +32,9 @@ export const toolSchema = {
|
|
|
28
32
|
required: ["market_id"],
|
|
29
33
|
},
|
|
30
34
|
};
|
|
35
|
+
function flattenAmountField(amount) {
|
|
36
|
+
return flattenAmount(amount);
|
|
37
|
+
}
|
|
31
38
|
export function register(server, client) {
|
|
32
39
|
server.tool(toolSchema.name, toolSchema.description, {
|
|
33
40
|
market_id: z
|
|
@@ -68,11 +75,42 @@ export function register(server, client) {
|
|
|
68
75
|
if (page !== undefined)
|
|
69
76
|
params.page = page;
|
|
70
77
|
const data = await client.get(`/markets/${market_id.toLowerCase()}/orders`, Object.keys(params).length > 0 ? params : undefined);
|
|
78
|
+
const orders = data.orders.map((o) => {
|
|
79
|
+
const amount = flattenAmountField(o.amount);
|
|
80
|
+
const originalAmount = flattenAmountField(o.original_amount);
|
|
81
|
+
const tradedAmount = flattenAmountField(o.traded_amount);
|
|
82
|
+
const totalExchanged = flattenAmountField(o.total_exchanged);
|
|
83
|
+
const paidFee = flattenAmountField(o.paid_fee);
|
|
84
|
+
const limitPrice = o.limit ? flattenAmountField(o.limit) : null;
|
|
85
|
+
return {
|
|
86
|
+
id: o.id,
|
|
87
|
+
type: o.type,
|
|
88
|
+
state: o.state,
|
|
89
|
+
created_at: o.created_at,
|
|
90
|
+
market_id: o.market_id,
|
|
91
|
+
fee_currency: o.fee_currency,
|
|
92
|
+
price_type: o.price_type,
|
|
93
|
+
order_type: o.order_type,
|
|
94
|
+
client_id: o.client_id,
|
|
95
|
+
limit_price: limitPrice ? limitPrice.value : null,
|
|
96
|
+
limit_price_currency: limitPrice ? limitPrice.currency : null,
|
|
97
|
+
amount: amount.value,
|
|
98
|
+
amount_currency: amount.currency,
|
|
99
|
+
original_amount: originalAmount.value,
|
|
100
|
+
original_amount_currency: originalAmount.currency,
|
|
101
|
+
traded_amount: tradedAmount.value,
|
|
102
|
+
traded_amount_currency: tradedAmount.currency,
|
|
103
|
+
total_exchanged: totalExchanged.value,
|
|
104
|
+
total_exchanged_currency: totalExchanged.currency,
|
|
105
|
+
paid_fee: paidFee.value,
|
|
106
|
+
paid_fee_currency: paidFee.currency,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
71
109
|
return {
|
|
72
110
|
content: [
|
|
73
111
|
{
|
|
74
112
|
type: "text",
|
|
75
|
-
text: JSON.stringify({ orders
|
|
113
|
+
text: JSON.stringify({ orders, meta: data.meta }, null, 2),
|
|
76
114
|
},
|
|
77
115
|
],
|
|
78
116
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"price_history.d.ts","sourceRoot":"","sources":["../../src/tools/price_history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"price_history.d.ts","sourceRoot":"","sources":["../../src/tools/price_history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA4BtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAiFzF"}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BudaApiError } from "../client.js";
|
|
3
3
|
import { validateMarketId } from "../validation.js";
|
|
4
|
-
|
|
5
|
-
"1h": 60 * 60 * 1000,
|
|
6
|
-
"4h": 4 * 60 * 60 * 1000,
|
|
7
|
-
"1d": 24 * 60 * 60 * 1000,
|
|
8
|
-
};
|
|
4
|
+
import { aggregateTradesToCandles } from "../utils.js";
|
|
9
5
|
export const toolSchema = {
|
|
10
6
|
name: "get_price_history",
|
|
11
7
|
description: "IMPORTANT: Candles are aggregated client-side from raw trades (Buda has no native candlestick " +
|
|
12
8
|
"endpoint) — fetching more trades via the 'limit' parameter gives deeper history but slower " +
|
|
13
|
-
"responses. Returns OHLCV (open/high/low/close
|
|
14
|
-
"Candle timestamps are UTC bucket boundaries
|
|
15
|
-
"
|
|
9
|
+
"responses. Returns OHLCV candles (open/high/low/close as floats in quote currency; volume as float " +
|
|
10
|
+
"in base currency) for periods 1h, 4h, or 1d. Candle timestamps are UTC bucket boundaries. " +
|
|
11
|
+
"Example: 'Show me the hourly BTC-CLP price chart for the past 24 hours.'",
|
|
16
12
|
inputSchema: {
|
|
17
13
|
type: "object",
|
|
18
14
|
properties: {
|
|
@@ -73,41 +69,7 @@ export function register(server, client, _cache) {
|
|
|
73
69
|
],
|
|
74
70
|
};
|
|
75
71
|
}
|
|
76
|
-
|
|
77
|
-
// and close = last chronological price within each candle bucket.
|
|
78
|
-
const sortedEntries = [...entries].sort(([a], [b]) => parseInt(a, 10) - parseInt(b, 10));
|
|
79
|
-
const periodMs = PERIOD_MS[period];
|
|
80
|
-
const buckets = new Map();
|
|
81
|
-
for (const [tsMs, amount, price, _direction] of sortedEntries) {
|
|
82
|
-
const ts = parseInt(tsMs, 10);
|
|
83
|
-
const bucketStart = Math.floor(ts / periodMs) * periodMs;
|
|
84
|
-
const p = parseFloat(price);
|
|
85
|
-
const v = parseFloat(amount);
|
|
86
|
-
if (!buckets.has(bucketStart)) {
|
|
87
|
-
buckets.set(bucketStart, {
|
|
88
|
-
time: new Date(bucketStart).toISOString(),
|
|
89
|
-
open: price,
|
|
90
|
-
high: price,
|
|
91
|
-
low: price,
|
|
92
|
-
close: price,
|
|
93
|
-
volume: amount,
|
|
94
|
-
trade_count: 1,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
const candle = buckets.get(bucketStart);
|
|
99
|
-
if (p > parseFloat(candle.high))
|
|
100
|
-
candle.high = price;
|
|
101
|
-
if (p < parseFloat(candle.low))
|
|
102
|
-
candle.low = price;
|
|
103
|
-
candle.close = price;
|
|
104
|
-
candle.volume = (parseFloat(candle.volume) + v).toFixed(8);
|
|
105
|
-
candle.trade_count++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const candles = Array.from(buckets.entries())
|
|
109
|
-
.sort(([a], [b]) => a - b)
|
|
110
|
-
.map(([, candle]) => candle);
|
|
72
|
+
const candles = aggregateTradesToCandles(entries, period);
|
|
111
73
|
const result = {
|
|
112
74
|
market_id: market_id.toUpperCase(),
|
|
113
75
|
period,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BudaClient } from "../client.js";
|
|
3
|
+
import { MemoryCache } from "../cache.js";
|
|
4
|
+
export declare const toolSchema: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: "object";
|
|
9
|
+
properties: {
|
|
10
|
+
market_id: {
|
|
11
|
+
type: string;
|
|
12
|
+
description: string;
|
|
13
|
+
};
|
|
14
|
+
side: {
|
|
15
|
+
type: string;
|
|
16
|
+
description: string;
|
|
17
|
+
};
|
|
18
|
+
amount: {
|
|
19
|
+
type: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
price: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
required: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
type SimulateOrderArgs = {
|
|
31
|
+
market_id: string;
|
|
32
|
+
side: "buy" | "sell";
|
|
33
|
+
amount: number;
|
|
34
|
+
price?: number;
|
|
35
|
+
};
|
|
36
|
+
export declare function handleSimulateOrder(args: SimulateOrderArgs, client: BudaClient, cache: MemoryCache): Promise<{
|
|
37
|
+
content: Array<{
|
|
38
|
+
type: "text";
|
|
39
|
+
text: string;
|
|
40
|
+
}>;
|
|
41
|
+
isError?: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
export declare function register(server: McpServer, client: BudaClient, cache: MemoryCache): void;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=simulate_order.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulate_order.d.ts","sourceRoot":"","sources":["../../src/tools/simulate_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA+BtB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAyGhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAuBxF"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { BudaApiError } from "../client.js";
|
|
3
|
+
import { CACHE_TTL } from "../cache.js";
|
|
4
|
+
import { validateMarketId } from "../validation.js";
|
|
5
|
+
export const toolSchema = {
|
|
6
|
+
name: "simulate_order",
|
|
7
|
+
description: "Simulates a buy or sell order on Buda.com using live ticker data — no order is placed. " +
|
|
8
|
+
"Returns estimated fill price, fee, total cost, and slippage vs mid-price. " +
|
|
9
|
+
"Omit 'price' for a market order simulation; supply 'price' for a limit order simulation. " +
|
|
10
|
+
"All outputs are labelled simulation: true — this tool never places a real order. " +
|
|
11
|
+
"Example: 'How much would it cost to buy 0.01 BTC on BTC-CLP right now?'",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
market_id: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "Market ID (e.g. 'BTC-CLP', 'ETH-BTC').",
|
|
18
|
+
},
|
|
19
|
+
side: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "'buy' or 'sell'.",
|
|
22
|
+
},
|
|
23
|
+
amount: {
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "Order size in base currency (e.g. BTC for BTC-CLP).",
|
|
26
|
+
},
|
|
27
|
+
price: {
|
|
28
|
+
type: "number",
|
|
29
|
+
description: "Limit price in quote currency. Omit for a market order simulation.",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ["market_id", "side", "amount"],
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
export async function handleSimulateOrder(args, client, cache) {
|
|
36
|
+
const { market_id, side, amount, price } = args;
|
|
37
|
+
const validationError = validateMarketId(market_id);
|
|
38
|
+
if (validationError) {
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const id = market_id.toLowerCase();
|
|
46
|
+
const [tickerData, marketData] = await Promise.all([
|
|
47
|
+
cache.getOrFetch(`ticker:${id}`, CACHE_TTL.TICKER, () => client.get(`/markets/${id}/ticker`)),
|
|
48
|
+
cache.getOrFetch(`market:${id}`, CACHE_TTL.MARKETS, () => client.get(`/markets/${id}`)),
|
|
49
|
+
]);
|
|
50
|
+
const ticker = tickerData.ticker;
|
|
51
|
+
const market = marketData.market;
|
|
52
|
+
const minAsk = parseFloat(ticker.min_ask[0]);
|
|
53
|
+
const maxBid = parseFloat(ticker.max_bid[0]);
|
|
54
|
+
const quoteCurrency = ticker.min_ask[1];
|
|
55
|
+
if (isNaN(minAsk) || isNaN(maxBid) || minAsk <= 0 || maxBid <= 0) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: JSON.stringify({
|
|
61
|
+
error: "Unable to simulate: invalid or zero bid/ask values in ticker.",
|
|
62
|
+
code: "INVALID_TICKER",
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
isError: true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const mid = (minAsk + maxBid) / 2;
|
|
70
|
+
const takerFeeRate = parseFloat(market.taker_fee);
|
|
71
|
+
const orderTypeAssumed = price !== undefined ? "limit" : "market";
|
|
72
|
+
let estimatedFillPrice;
|
|
73
|
+
if (orderTypeAssumed === "market") {
|
|
74
|
+
estimatedFillPrice = side === "buy" ? minAsk : maxBid;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Limit order: fill at provided price if it crosses the spread, otherwise at limit price
|
|
78
|
+
if (side === "buy") {
|
|
79
|
+
estimatedFillPrice = price >= minAsk ? minAsk : price;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
estimatedFillPrice = price <= maxBid ? maxBid : price;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const grossValue = amount * estimatedFillPrice;
|
|
86
|
+
const feeAmount = parseFloat((grossValue * takerFeeRate).toFixed(8));
|
|
87
|
+
const totalCost = side === "buy"
|
|
88
|
+
? parseFloat((grossValue + feeAmount).toFixed(8))
|
|
89
|
+
: parseFloat((grossValue - feeAmount).toFixed(8));
|
|
90
|
+
const slippageVsMidPct = parseFloat((((estimatedFillPrice - mid) / mid) * 100).toFixed(4));
|
|
91
|
+
const result = {
|
|
92
|
+
simulation: true,
|
|
93
|
+
market_id: ticker.market_id,
|
|
94
|
+
side,
|
|
95
|
+
amount,
|
|
96
|
+
order_type_assumed: orderTypeAssumed,
|
|
97
|
+
estimated_fill_price: parseFloat(estimatedFillPrice.toFixed(2)),
|
|
98
|
+
price_currency: quoteCurrency,
|
|
99
|
+
fee_amount: feeAmount,
|
|
100
|
+
fee_currency: quoteCurrency,
|
|
101
|
+
fee_rate_pct: parseFloat((takerFeeRate * 100).toFixed(3)),
|
|
102
|
+
total_cost: totalCost,
|
|
103
|
+
slippage_vs_mid_pct: slippageVsMidPct,
|
|
104
|
+
mid_price: parseFloat(mid.toFixed(2)),
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const msg = err instanceof BudaApiError
|
|
112
|
+
? { error: err.message, code: err.status, path: err.path }
|
|
113
|
+
: { error: String(err), code: "UNKNOWN" };
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: JSON.stringify(msg) }],
|
|
116
|
+
isError: true,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export function register(server, client, cache) {
|
|
121
|
+
server.tool(toolSchema.name, toolSchema.description, {
|
|
122
|
+
market_id: z
|
|
123
|
+
.string()
|
|
124
|
+
.describe("Market ID (e.g. 'BTC-CLP', 'ETH-BTC')."),
|
|
125
|
+
side: z
|
|
126
|
+
.enum(["buy", "sell"])
|
|
127
|
+
.describe("'buy' or 'sell'."),
|
|
128
|
+
amount: z
|
|
129
|
+
.number()
|
|
130
|
+
.positive()
|
|
131
|
+
.describe("Order size in base currency (e.g. BTC for BTC-CLP)."),
|
|
132
|
+
price: z
|
|
133
|
+
.number()
|
|
134
|
+
.positive()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe("Limit price in quote currency. Omit for a market order simulation."),
|
|
137
|
+
}, (args) => handleSimulateOrder(args, client, cache));
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=simulate_order.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/tools/spread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/tools/spread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AAIrD,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAiBtB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAuExF"}
|