@runonflux/flux-cloud-mcp 0.1.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/LICENSE +21 -0
- package/README.md +178 -0
- package/dist/chain.d.ts +71 -0
- package/dist/chain.js +144 -0
- package/dist/chain.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/deploy.d.ts +111 -0
- package/dist/deploy.js +216 -0
- package/dist/deploy.js.map +1 -0
- package/dist/docs.d.ts +5 -0
- package/dist/docs.js +164 -0
- package/dist/docs.js.map +1 -0
- package/dist/enterprise.d.ts +29 -0
- package/dist/enterprise.js +45 -0
- package/dist/enterprise.js.map +1 -0
- package/dist/fluxapi.d.ts +71 -0
- package/dist/fluxapi.js +165 -0
- package/dist/fluxapi.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +44 -0
- package/dist/keys.js +79 -0
- package/dist/keys.js.map +1 -0
- package/dist/pricing.d.ts +93 -0
- package/dist/pricing.js +192 -0
- package/dist/pricing.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +877 -0
- package/dist/server.js.map +1 -0
- package/dist/spec.d.ts +144 -0
- package/dist/spec.js +312 -0
- package/dist/spec.js.map +1 -0
- package/package.json +69 -0
package/dist/fluxapi.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FluxOS HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* Every FluxOS response is `{ status: 'success' | 'error', data }`; `unwrap`
|
|
5
|
+
* turns the error shape into a thrown Error with the node's message.
|
|
6
|
+
*
|
|
7
|
+
* POST bodies are sent as text/plain, never application/json. FluxOS installs
|
|
8
|
+
* `express.json()` globally, but the handlers this server needs
|
|
9
|
+
* (/apps/appregister, /apps/appupdate, /apps/calculatefiatandfluxprice,
|
|
10
|
+
* /apps/verifyapp*specifications, /apps/getpublickey) read the raw request
|
|
11
|
+
* stream themselves. With a JSON content type the middleware has already
|
|
12
|
+
* consumed the stream, the handler's 'end' listener never fires and the
|
|
13
|
+
* request hangs until a gateway 504. The payload is still JSON text.
|
|
14
|
+
*/
|
|
15
|
+
export class FluxApiError extends Error {
|
|
16
|
+
endpoint;
|
|
17
|
+
constructor(message, endpoint) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.endpoint = endpoint;
|
|
20
|
+
this.name = 'FluxApiError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function unwrap(payload, endpoint) {
|
|
24
|
+
const response = payload;
|
|
25
|
+
if (response && response.status === 'success')
|
|
26
|
+
return response.data;
|
|
27
|
+
if (response && response.status === 'error') {
|
|
28
|
+
const data = response.data;
|
|
29
|
+
const message = typeof data === 'string' ? data : (data?.message ?? data?.name ?? 'unknown FluxOS error');
|
|
30
|
+
throw new FluxApiError(`${endpoint}: ${message}`, endpoint);
|
|
31
|
+
}
|
|
32
|
+
throw new FluxApiError(`${endpoint}: unexpected response ${JSON.stringify(payload).slice(0, 300)}`, endpoint);
|
|
33
|
+
}
|
|
34
|
+
export function sessionHeader(session) {
|
|
35
|
+
return JSON.stringify(session);
|
|
36
|
+
}
|
|
37
|
+
export class FluxClient {
|
|
38
|
+
baseUrl;
|
|
39
|
+
defaultTimeoutMs;
|
|
40
|
+
constructor(baseUrl, defaultTimeoutMs = 60000) {
|
|
41
|
+
this.baseUrl = baseUrl;
|
|
42
|
+
this.defaultTimeoutMs = defaultTimeoutMs;
|
|
43
|
+
}
|
|
44
|
+
async raw(method, pathname, options = {}) {
|
|
45
|
+
const headers = {};
|
|
46
|
+
let body;
|
|
47
|
+
if (options.body !== undefined) {
|
|
48
|
+
headers['Content-Type'] = 'text/plain';
|
|
49
|
+
body = typeof options.body === 'string' ? options.body : JSON.stringify(options.body);
|
|
50
|
+
}
|
|
51
|
+
if (options.session)
|
|
52
|
+
headers.zelidauth = sessionHeader(options.session);
|
|
53
|
+
const url = `${this.baseUrl}${pathname}`;
|
|
54
|
+
let response;
|
|
55
|
+
try {
|
|
56
|
+
response = await fetch(url, {
|
|
57
|
+
method,
|
|
58
|
+
headers,
|
|
59
|
+
...(body === undefined ? {} : { body }),
|
|
60
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? this.defaultTimeoutMs),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new FluxApiError(`${url}: ${error.message}`, pathname);
|
|
65
|
+
}
|
|
66
|
+
const text = await response.text();
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new FluxApiError(`${url}: HTTP ${response.status} ${text.slice(0, 200)}`, pathname);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(text);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new FluxApiError(`${url}: non-JSON response ${text.slice(0, 200)}`, pathname);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async get(pathname, options = {}) {
|
|
78
|
+
return unwrap(await this.raw('GET', pathname, options), pathname);
|
|
79
|
+
}
|
|
80
|
+
async post(pathname, body, options = {}) {
|
|
81
|
+
return unwrap(await this.raw('POST', pathname, { ...options, body }), pathname);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** FluxOS refuses registrations on nodes with fewer peers than this. */
|
|
85
|
+
export const MIN_OUTGOING_PEERS = 8;
|
|
86
|
+
export const MIN_INCOMING_PEERS = 4;
|
|
87
|
+
export async function listNodeEndpoints(api) {
|
|
88
|
+
const nodes = await api.get('/daemon/viewdeterministiczelnodelist', {
|
|
89
|
+
timeoutMs: 120000,
|
|
90
|
+
});
|
|
91
|
+
return nodes
|
|
92
|
+
.filter((node) => node.ip && node.network === 'ipv4')
|
|
93
|
+
.map((node) => {
|
|
94
|
+
const [ip, port] = node.ip.split(':');
|
|
95
|
+
return { endpoint: `http://${ip}:${port ?? '16127'}`, ip: ip ?? '', tier: node.tier };
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
export async function nodeHealth(node) {
|
|
99
|
+
const [outgoing, incoming, info] = await Promise.all([
|
|
100
|
+
node.get('/flux/connectedpeersinfo', { timeoutMs: 12000 }),
|
|
101
|
+
node.get('/flux/incomingconnectionsinfo', { timeoutMs: 12000 }),
|
|
102
|
+
node
|
|
103
|
+
.get('/flux/info', { timeoutMs: 12000 })
|
|
104
|
+
.catch(() => undefined),
|
|
105
|
+
]);
|
|
106
|
+
return {
|
|
107
|
+
outgoing: outgoing.length,
|
|
108
|
+
incoming: incoming.length,
|
|
109
|
+
ok: outgoing.length >= MIN_OUTGOING_PEERS && incoming.length >= MIN_INCOMING_PEERS,
|
|
110
|
+
arcaneVersion: info?.flux?.arcaneVersion,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function shuffle(list) {
|
|
114
|
+
const copy = [...list];
|
|
115
|
+
for (let i = copy.length - 1; i > 0; i -= 1) {
|
|
116
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
117
|
+
const a = copy[i];
|
|
118
|
+
copy[i] = copy[j];
|
|
119
|
+
copy[j] = a;
|
|
120
|
+
}
|
|
121
|
+
return copy;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Probe random nodes until `count` of them meet the peer thresholds. With
|
|
125
|
+
* `arcane` only ArcaneOS nodes qualify: they alone hold the key that
|
|
126
|
+
* decrypts enterprise specifications, so only they can validate or accept one.
|
|
127
|
+
*/
|
|
128
|
+
export async function findHealthyNodes(api, count, options = {}) {
|
|
129
|
+
const { arcane = false, batchSize = 12, maxProbes = 240, log = () => { } } = options;
|
|
130
|
+
const pool = shuffle(await listNodeEndpoints(api));
|
|
131
|
+
const healthy = [];
|
|
132
|
+
let probed = 0;
|
|
133
|
+
while (healthy.length < count && probed < Math.min(maxProbes, pool.length)) {
|
|
134
|
+
const batch = pool.slice(probed, probed + batchSize);
|
|
135
|
+
probed += batch.length;
|
|
136
|
+
const results = await Promise.all(batch.map(async (candidate) => {
|
|
137
|
+
const client = new FluxClient(candidate.endpoint);
|
|
138
|
+
try {
|
|
139
|
+
const health = await nodeHealth(client);
|
|
140
|
+
if (!health.ok)
|
|
141
|
+
return undefined;
|
|
142
|
+
if (arcane && !health.arcaneVersion)
|
|
143
|
+
return undefined;
|
|
144
|
+
return { ...candidate, client, health };
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
}));
|
|
150
|
+
for (const result of results)
|
|
151
|
+
if (result)
|
|
152
|
+
healthy.push(result);
|
|
153
|
+
log(`probed ${probed} nodes, ${healthy.length} usable`);
|
|
154
|
+
}
|
|
155
|
+
if (!healthy.length) {
|
|
156
|
+
throw new Error(`No ${arcane ? 'ArcaneOS ' : ''}FluxOS node with enough peers found after probing ${probed} candidates`);
|
|
157
|
+
}
|
|
158
|
+
return healthy.slice(0, count);
|
|
159
|
+
}
|
|
160
|
+
/** `http://ip:port` for an app instance reported by /apps/location. */
|
|
161
|
+
export function instanceEndpoint(ip) {
|
|
162
|
+
const [host, port] = ip.split(':');
|
|
163
|
+
return `http://${host}:${port ?? '16127'}`;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=fluxapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fluxapi.js","sourceRoot":"","sources":["../src/fluxapi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAeH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAGnB;IAFlB,YACE,OAAe,EACC,QAAgB;QAEhC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,aAAQ,GAAR,QAAQ,CAAQ;QAGhC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,MAAM,CAAI,OAAgB,EAAE,QAAgB;IAC1D,MAAM,QAAQ,GAAG,OAAsC,CAAC;IACxD,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;IACpE,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAA8B,CAAC;QACrD,MAAM,OAAO,GACX,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,IAAI,IAAI,sBAAsB,CAAC,CAAC;QAC5F,MAAM,IAAI,YAAY,CAAC,GAAG,QAAQ,KAAK,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,IAAI,YAAY,CACpB,GAAG,QAAQ,yBAAyB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAC3E,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAQD,MAAM,OAAO,UAAU;IAEH;IACC;IAFnB,YACkB,OAAe,EACd,mBAAmB,KAAK;QADzB,YAAO,GAAP,OAAO,CAAQ;QACd,qBAAgB,GAAhB,gBAAgB,CAAQ;IACxC,CAAC;IAEJ,KAAK,CAAC,GAAG,CACP,MAAsB,EACtB,QAAgB,EAChB,UAA0B,EAAE;QAE5B,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,IAAI,IAAwB,CAAC;QAC7B,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC;YACvC,IAAI,GAAG,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxF,CAAC;QACD,IAAI,OAAO,CAAC,OAAO;YAAE,OAAO,CAAC,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAExE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;QACzC,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC1B,MAAM;gBACN,OAAO;gBACP,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;gBACvC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAAC;aACxE,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,YAAY,CAAC,GAAG,GAAG,KAAM,KAAe,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,YAAY,CAAC,GAAG,GAAG,UAAU,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,YAAY,CAAC,GAAG,GAAG,uBAAuB,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,QAAgB,EAAE,UAA0B,EAAE;QACzD,OAAO,MAAM,CAAI,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,QAAgB,EAAE,IAAa,EAAE,UAA0B,EAAE;QACzE,OAAO,MAAM,CAAI,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrF,CAAC;CACF;AAyBD,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAe;IACrD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAsB,sCAAsC,EAAE;QACvF,SAAS,EAAE,MAAM;KAClB,CAAC,CAAC;IACH,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC;SACpD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,IAAI,IAAI,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACxF,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAgB;IAC/C,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnD,IAAI,CAAC,GAAG,CAAY,0BAA0B,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACrE,IAAI,CAAC,GAAG,CAAY,+BAA+B,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC1E,IAAI;aACD,GAAG,CAAwC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;aAC9E,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;KAC1B,CAAC,CAAC;IACH,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,MAAM;QACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM;QACzB,EAAE,EAAE,QAAQ,CAAC,MAAM,IAAI,kBAAkB,IAAI,QAAQ,CAAC,MAAM,IAAI,kBAAkB;QAClF,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAI,IAAS;IAC3B,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAM,CAAC;QACvB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAM,CAAC;QACvB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAe,EACf,KAAa,EACb,UAKI,EAAE;IAEN,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,SAAS,GAAG,EAAE,EAAE,SAAS,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,EAAE,GAAG,OAAO,CAAC;IACpF,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,OAAO,CAAC,MAAM,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;gBACxC,IAAI,CAAC,MAAM,CAAC,EAAE;oBAAE,OAAO,SAAS,CAAC;gBACjC,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa;oBAAE,OAAO,SAAS,CAAC;gBACtD,OAAO,EAAE,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/D,GAAG,CAAC,UAAU,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,MAAM,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,qDAAqD,MAAM,aAAa,CACxG,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,UAAU,IAAI,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { loadConfig } from './config.js';
|
|
4
|
+
import { createServer } from './server.js';
|
|
5
|
+
async function main() {
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
const server = createServer(config);
|
|
8
|
+
const transport = new StdioServerTransport();
|
|
9
|
+
await server.connect(transport);
|
|
10
|
+
process.stderr.write(`flux-cloud-mcp ready (api ${config.apiUrl}, keys ${config.ownerWif && config.payerWif ? 'configured' : 'missing'})\n`);
|
|
11
|
+
}
|
|
12
|
+
main().catch((error) => {
|
|
13
|
+
process.stderr.write(`flux-cloud-mcp failed to start: ${error.message}\n`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6BAA6B,MAAM,CAAC,MAAM,UAAU,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK,CACvH,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAoC,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;IACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key material and signatures.
|
|
3
|
+
*
|
|
4
|
+
* Flux ID (ZelID) a Bitcoin-style P2PKH address ("1..."), derived from a
|
|
5
|
+
* secp256k1 key. Owns apps, signs messages and sessions.
|
|
6
|
+
* Payment address a Flux transparent address ("t1...") from a second key.
|
|
7
|
+
* Holds FLUX and pays deployment fees.
|
|
8
|
+
*
|
|
9
|
+
* Both use the same WIF encoding (version byte 0x80), so one WIF can be read
|
|
10
|
+
* as either identity; which role it plays is decided by the caller.
|
|
11
|
+
*/
|
|
12
|
+
export interface Identity {
|
|
13
|
+
wif: string;
|
|
14
|
+
publicKey: string;
|
|
15
|
+
/** Flux ID / ZelID: the app owner address ("1..."). */
|
|
16
|
+
zelid: string;
|
|
17
|
+
/** Flux transparent address ("t1..."), the one that can hold FLUX. */
|
|
18
|
+
fluxAddress: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function identityFromWif(wif: string): Identity;
|
|
21
|
+
export declare function generateIdentity(): Identity;
|
|
22
|
+
/**
|
|
23
|
+
* Standard Bitcoin signed-message signature, base64. This is what FluxOS
|
|
24
|
+
* `signatureVerifier.verifySignature` checks for a "1..." owner.
|
|
25
|
+
*/
|
|
26
|
+
export declare function signMessage(message: string, wif: string): string;
|
|
27
|
+
export declare function verifyMessage(message: string, zelid: string, signature: string): boolean;
|
|
28
|
+
export interface Session {
|
|
29
|
+
zelid: string;
|
|
30
|
+
signature: string;
|
|
31
|
+
loginPhrase: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A self-issued FluxOS session.
|
|
35
|
+
*
|
|
36
|
+
* FluxOS accepts a login phrase it never issued as long as it starts with a
|
|
37
|
+
* 13-digit millisecond timestamp less than 16 hours old, is 40-70 characters
|
|
38
|
+
* long, and is signed by the ZelID (verificationHelperUtils.verifyUserSession).
|
|
39
|
+
* That means one signed phrase authenticates against every node on the
|
|
40
|
+
* network, with no login round-trip and no node affinity.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createSession(ownerWif: string): Session;
|
|
43
|
+
/** The same session for the whole process, re-issued well before it ages out. */
|
|
44
|
+
export declare function currentSession(ownerWif: string): Session;
|
package/dist/keys.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key material and signatures.
|
|
3
|
+
*
|
|
4
|
+
* Flux ID (ZelID) a Bitcoin-style P2PKH address ("1..."), derived from a
|
|
5
|
+
* secp256k1 key. Owns apps, signs messages and sessions.
|
|
6
|
+
* Payment address a Flux transparent address ("t1...") from a second key.
|
|
7
|
+
* Holds FLUX and pays deployment fees.
|
|
8
|
+
*
|
|
9
|
+
* Both use the same WIF encoding (version byte 0x80), so one WIF can be read
|
|
10
|
+
* as either identity; which role it plays is decided by the caller.
|
|
11
|
+
*/
|
|
12
|
+
import { randomBytes } from 'node:crypto';
|
|
13
|
+
import utxolib from '@runonflux/utxo-lib';
|
|
14
|
+
import bitcoinMessage from 'bitcoinjs-message';
|
|
15
|
+
function keyPairFromWif(wif) {
|
|
16
|
+
try {
|
|
17
|
+
return utxolib.ECPair.fromWIF(wif, utxolib.networks.flux);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new Error(`Not a valid WIF private key: ${error.message}`, { cause: error });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function identityFromWif(wif) {
|
|
24
|
+
const flux = keyPairFromWif(wif);
|
|
25
|
+
const bitcoin = utxolib.ECPair.fromWIF(wif, utxolib.networks.bitcoin);
|
|
26
|
+
return {
|
|
27
|
+
wif,
|
|
28
|
+
publicKey: flux.getPublicKeyBuffer().toString('hex'),
|
|
29
|
+
zelid: bitcoin.getAddress(),
|
|
30
|
+
fluxAddress: flux.getAddress(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function generateIdentity() {
|
|
34
|
+
const pair = utxolib.ECPair.makeRandom({ network: utxolib.networks.flux, compressed: true });
|
|
35
|
+
return identityFromWif(pair.toWIF());
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Standard Bitcoin signed-message signature, base64. This is what FluxOS
|
|
39
|
+
* `signatureVerifier.verifySignature` checks for a "1..." owner.
|
|
40
|
+
*/
|
|
41
|
+
export function signMessage(message, wif) {
|
|
42
|
+
const pair = keyPairFromWif(wif);
|
|
43
|
+
return bitcoinMessage.sign(message, pair.d.toBuffer(32), pair.compressed).toString('base64');
|
|
44
|
+
}
|
|
45
|
+
export function verifyMessage(message, zelid, signature) {
|
|
46
|
+
try {
|
|
47
|
+
return bitcoinMessage.verify(message, zelid, signature);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A self-issued FluxOS session.
|
|
55
|
+
*
|
|
56
|
+
* FluxOS accepts a login phrase it never issued as long as it starts with a
|
|
57
|
+
* 13-digit millisecond timestamp less than 16 hours old, is 40-70 characters
|
|
58
|
+
* long, and is signed by the ZelID (verificationHelperUtils.verifyUserSession).
|
|
59
|
+
* That means one signed phrase authenticates against every node on the
|
|
60
|
+
* network, with no login round-trip and no node affinity.
|
|
61
|
+
*/
|
|
62
|
+
export function createSession(ownerWif) {
|
|
63
|
+
const identity = identityFromWif(ownerWif);
|
|
64
|
+
const loginPhrase = `${Date.now()}${randomBytes(16).toString('hex')}`;
|
|
65
|
+
return { zelid: identity.zelid, signature: signMessage(loginPhrase, ownerWif), loginPhrase };
|
|
66
|
+
}
|
|
67
|
+
const SESSION_TTL_MS = 8 * 60 * 60 * 1000;
|
|
68
|
+
let cachedSession;
|
|
69
|
+
/** The same session for the whole process, re-issued well before it ages out. */
|
|
70
|
+
export function currentSession(ownerWif) {
|
|
71
|
+
if (cachedSession &&
|
|
72
|
+
cachedSession.wif === ownerWif &&
|
|
73
|
+
Date.now() - cachedSession.issuedAt < SESSION_TTL_MS) {
|
|
74
|
+
return cachedSession.session;
|
|
75
|
+
}
|
|
76
|
+
cachedSession = { session: createSession(ownerWif), wif: ownerWif, issuedAt: Date.now() };
|
|
77
|
+
return cachedSession.session;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=keys.js.map
|
package/dist/keys.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing.
|
|
3
|
+
*
|
|
4
|
+
* Flux Cloud has two price tables and this server deliberately quotes only one:
|
|
5
|
+
*
|
|
6
|
+
* USD table what Flux Cloud (home.runonflux.io) charges. Per-resource USD
|
|
7
|
+
* rates, a $0.99 minimum, hardware and term discounts, converted
|
|
8
|
+
* to FLUX at market rate with a 5% discount for paying in FLUX.
|
|
9
|
+
* Served by every node at POST /apps/calculatefiatandfluxprice.
|
|
10
|
+
* THIS IS THE PRICE.
|
|
11
|
+
*
|
|
12
|
+
* chain table what consensus enforces as the bare minimum for a message to
|
|
13
|
+
* be accepted (messageVerifier.js). It has no USD floor and is
|
|
14
|
+
* several times lower. It is used here only as a safety guard
|
|
15
|
+
* before broadcasting a payment, never shown as a quote.
|
|
16
|
+
*/
|
|
17
|
+
import type { FluxClient } from './fluxapi.js';
|
|
18
|
+
import type { AppSpec } from './spec.js';
|
|
19
|
+
export interface UsdRates {
|
|
20
|
+
cpu: number;
|
|
21
|
+
ram: number;
|
|
22
|
+
hdd: number;
|
|
23
|
+
minPrice: number;
|
|
24
|
+
port: number;
|
|
25
|
+
scope: number;
|
|
26
|
+
staticip: number;
|
|
27
|
+
fluxmultiplier: number;
|
|
28
|
+
multiplier: number;
|
|
29
|
+
minUSDPrice: number;
|
|
30
|
+
}
|
|
31
|
+
/** Bundled fallback, identical to ZelBack/config/default.js `usdprice` (Sept 2026). */
|
|
32
|
+
export declare const DEFAULT_USD_RATES: UsdRates;
|
|
33
|
+
export interface ChainPriceInterval {
|
|
34
|
+
height: number;
|
|
35
|
+
cpu: number;
|
|
36
|
+
ram: number;
|
|
37
|
+
hdd: number;
|
|
38
|
+
minPrice: number;
|
|
39
|
+
port: number;
|
|
40
|
+
scope: number;
|
|
41
|
+
staticip: number;
|
|
42
|
+
}
|
|
43
|
+
export interface DeploymentInformation {
|
|
44
|
+
price: ChainPriceInterval[];
|
|
45
|
+
address: string;
|
|
46
|
+
minimumInstances?: number;
|
|
47
|
+
maximumInstances?: number;
|
|
48
|
+
minBlocksAllowance?: number;
|
|
49
|
+
maxBlocksAllowance?: number;
|
|
50
|
+
blocksLasting?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface Quote {
|
|
53
|
+
/** The price, in US dollars, for the whole term. */
|
|
54
|
+
usd: number;
|
|
55
|
+
/** FLUX to send for the whole term, at market rate, with the pay-in-FLUX discount applied. */
|
|
56
|
+
flux: number;
|
|
57
|
+
/** Discount in percent for paying with FLUX rather than card. */
|
|
58
|
+
fluxDiscountPercent: number | string;
|
|
59
|
+
/** Term length in blocks and in network months. */
|
|
60
|
+
expireBlocks: number;
|
|
61
|
+
months: number;
|
|
62
|
+
usdPerMonth: number;
|
|
63
|
+
/** FLUX/USD market rate implied by the quote. */
|
|
64
|
+
fluxUsdRate: number | null;
|
|
65
|
+
source: 'flux-cloud' | 'local-estimate';
|
|
66
|
+
}
|
|
67
|
+
/** Live USD quote from the network, for a registration or an update of an existing app. */
|
|
68
|
+
export declare function quoteFromNetwork(api: FluxClient, spec: AppSpec): Promise<Quote>;
|
|
69
|
+
export declare function fetchUsdRates(statsUrl: string): Promise<UsdRates>;
|
|
70
|
+
/** FLUX price in USD, the way FluxOS derives it: BTC/USD from the rates service times FLUX/BTC. */
|
|
71
|
+
export declare function fetchFluxUsdRate(ratesUrl: string): Promise<number>;
|
|
72
|
+
/**
|
|
73
|
+
* Monthly USD price of a specification, mirroring appPricePerMonth() with the
|
|
74
|
+
* USD table. Per-instance price is a third of the resource total (one
|
|
75
|
+
* instance of three), then multiplied out to the instance count.
|
|
76
|
+
*/
|
|
77
|
+
export declare function usdPerMonth(spec: AppSpec, rates?: UsdRates): number;
|
|
78
|
+
/**
|
|
79
|
+
* Local mirror of the Flux Cloud USD price for a NEW registration, used for
|
|
80
|
+
* instant what-if estimates and to sanity check the network's answer. It does
|
|
81
|
+
* not know about update credits or marketplace multipliers, so the network
|
|
82
|
+
* quote stays authoritative.
|
|
83
|
+
*/
|
|
84
|
+
export declare function estimateUsd(spec: AppSpec, rates?: UsdRates): number;
|
|
85
|
+
export declare function estimateQuote(spec: AppSpec, rates: UsdRates, fluxUsdRate: number): Quote;
|
|
86
|
+
export declare function chainInterval(table: ChainPriceInterval[], height: number): ChainPriceInterval;
|
|
87
|
+
/**
|
|
88
|
+
* The minimum FLUX consensus will accept for this message at `height`
|
|
89
|
+
* (messageVerifier.js). For updates the network additionally credits the
|
|
90
|
+
* unused part of the previous term, so the true minimum is lower still; using
|
|
91
|
+
* the registration formula errs on the safe side.
|
|
92
|
+
*/
|
|
93
|
+
export declare function consensusMinimumFlux(spec: AppSpec, table: ChainPriceInterval[], height: number): number;
|
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing.
|
|
3
|
+
*
|
|
4
|
+
* Flux Cloud has two price tables and this server deliberately quotes only one:
|
|
5
|
+
*
|
|
6
|
+
* USD table what Flux Cloud (home.runonflux.io) charges. Per-resource USD
|
|
7
|
+
* rates, a $0.99 minimum, hardware and term discounts, converted
|
|
8
|
+
* to FLUX at market rate with a 5% discount for paying in FLUX.
|
|
9
|
+
* Served by every node at POST /apps/calculatefiatandfluxprice.
|
|
10
|
+
* THIS IS THE PRICE.
|
|
11
|
+
*
|
|
12
|
+
* chain table what consensus enforces as the bare minimum for a message to
|
|
13
|
+
* be accepted (messageVerifier.js). It has no USD floor and is
|
|
14
|
+
* several times lower. It is used here only as a safety guard
|
|
15
|
+
* before broadcasting a payment, never shown as a quote.
|
|
16
|
+
*/
|
|
17
|
+
import { BLOCKS_PER_MONTH, isPortEnterprise, totalResources } from './spec.js';
|
|
18
|
+
/** Bundled fallback, identical to ZelBack/config/default.js `usdprice` (Sept 2026). */
|
|
19
|
+
export const DEFAULT_USD_RATES = {
|
|
20
|
+
cpu: 0.15,
|
|
21
|
+
ram: 0.05,
|
|
22
|
+
hdd: 0.02,
|
|
23
|
+
minPrice: 0.01,
|
|
24
|
+
port: 2,
|
|
25
|
+
scope: 4,
|
|
26
|
+
staticip: 2,
|
|
27
|
+
fluxmultiplier: 0.95,
|
|
28
|
+
multiplier: 1,
|
|
29
|
+
minUSDPrice: 0.99,
|
|
30
|
+
};
|
|
31
|
+
/** Live USD quote from the network, for a registration or an update of an existing app. */
|
|
32
|
+
export async function quoteFromNetwork(api, spec) {
|
|
33
|
+
const price = await api.post('/apps/calculatefiatandfluxprice', spec, { timeoutMs: 60000 });
|
|
34
|
+
const months = spec.expire / BLOCKS_PER_MONTH;
|
|
35
|
+
const usd = Number(price.usd);
|
|
36
|
+
const flux = Number(price.flux);
|
|
37
|
+
const discount = typeof price.fluxDiscount === 'number' ? price.fluxDiscount : 0;
|
|
38
|
+
const rate = flux > 0 && usd > 0 ? (usd / flux) * (1 - discount / 100) : null;
|
|
39
|
+
return {
|
|
40
|
+
usd,
|
|
41
|
+
flux,
|
|
42
|
+
fluxDiscountPercent: price.fluxDiscount,
|
|
43
|
+
expireBlocks: spec.expire,
|
|
44
|
+
months: round2(months),
|
|
45
|
+
usdPerMonth: months > 0 ? round2(usd / months) : usd,
|
|
46
|
+
fluxUsdRate: rate === null ? null : Number(rate.toFixed(4)),
|
|
47
|
+
source: 'flux-cloud',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export async function fetchUsdRates(statsUrl) {
|
|
51
|
+
try {
|
|
52
|
+
const response = await fetch(`${statsUrl}/apps/getappspecsusdprice`, {
|
|
53
|
+
signal: AbortSignal.timeout(10000),
|
|
54
|
+
});
|
|
55
|
+
const payload = (await response.json());
|
|
56
|
+
if (payload.status === 'success' && payload.data && payload.data.cpu)
|
|
57
|
+
return payload.data;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// fall through to the bundled table
|
|
61
|
+
}
|
|
62
|
+
return DEFAULT_USD_RATES;
|
|
63
|
+
}
|
|
64
|
+
/** FLUX price in USD, the way FluxOS derives it: BTC/USD from the rates service times FLUX/BTC. */
|
|
65
|
+
export async function fetchFluxUsdRate(ratesUrl) {
|
|
66
|
+
const response = await fetch(`${ratesUrl}/rates`, { signal: AbortSignal.timeout(10000) });
|
|
67
|
+
const payload = (await response.json());
|
|
68
|
+
const usd = payload[0]?.find((rate) => rate.code === 'USD');
|
|
69
|
+
const fluxInBtc = payload[1]?.FLUX;
|
|
70
|
+
if (!usd || fluxInBtc === undefined)
|
|
71
|
+
throw new Error('Rates service returned no FLUX/USD rate');
|
|
72
|
+
return usd.rate * fluxInBtc;
|
|
73
|
+
}
|
|
74
|
+
function round2(value) {
|
|
75
|
+
return Math.round(value * 100) / 100;
|
|
76
|
+
}
|
|
77
|
+
function ceil2(value) {
|
|
78
|
+
return Math.ceil(value * 100) / 100;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Monthly USD price of a specification, mirroring appPricePerMonth() with the
|
|
82
|
+
* USD table. Per-instance price is a third of the resource total (one
|
|
83
|
+
* instance of three), then multiplied out to the instance count.
|
|
84
|
+
*/
|
|
85
|
+
export function usdPerMonth(spec, rates = DEFAULT_USD_RATES) {
|
|
86
|
+
const res = totalResources(spec);
|
|
87
|
+
const enterprisePorts = spec.compose.flatMap((c) => c.ports.filter(isPortEnterprise)).length;
|
|
88
|
+
let total = res.cpu * rates.cpu * 10 + (res.ram * rates.ram) / 100 + res.hdd * rates.hdd;
|
|
89
|
+
if (spec.nodes.length || spec.enterprise)
|
|
90
|
+
total += rates.scope;
|
|
91
|
+
if (spec.staticip)
|
|
92
|
+
total += rates.staticip;
|
|
93
|
+
total += enterprisePorts * rates.port;
|
|
94
|
+
let price = ceil2(total / 3);
|
|
95
|
+
const extra = spec.instances - 1;
|
|
96
|
+
if (extra > 0) {
|
|
97
|
+
if (price < 0.5 && extra > 2)
|
|
98
|
+
price += extra * 0.5;
|
|
99
|
+
else
|
|
100
|
+
price = (Math.ceil(price * extra * 100) + Math.ceil(price * 100)) / 100;
|
|
101
|
+
}
|
|
102
|
+
if (price < rates.minUSDPrice)
|
|
103
|
+
price = Number(rates.minUSDPrice.toFixed(2));
|
|
104
|
+
return price;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Local mirror of the Flux Cloud USD price for a NEW registration, used for
|
|
108
|
+
* instant what-if estimates and to sanity check the network's answer. It does
|
|
109
|
+
* not know about update credits or marketplace multipliers, so the network
|
|
110
|
+
* quote stays authoritative.
|
|
111
|
+
*/
|
|
112
|
+
export function estimateUsd(spec, rates = DEFAULT_USD_RATES) {
|
|
113
|
+
const months = spec.expire / BLOCKS_PER_MONTH;
|
|
114
|
+
let price = Number((usdPerMonth(spec, rates) * months).toFixed(2));
|
|
115
|
+
const res = totalResources(spec);
|
|
116
|
+
if (spec.instances < 4) {
|
|
117
|
+
if (res.cpu < 3 && res.ram < 6000 && res.hdd < 150)
|
|
118
|
+
price *= 0.8;
|
|
119
|
+
else if (res.cpu < 7 && res.ram < 29000 && res.hdd < 370)
|
|
120
|
+
price *= 0.9;
|
|
121
|
+
}
|
|
122
|
+
if (spec.compose.some((c) => c.containerData.includes('g:')))
|
|
123
|
+
price *= 0.8;
|
|
124
|
+
price = Number((price * rates.multiplier).toFixed(2));
|
|
125
|
+
if (price < rates.minUSDPrice)
|
|
126
|
+
price = rates.minUSDPrice;
|
|
127
|
+
if (months >= 9)
|
|
128
|
+
price *= 0.88;
|
|
129
|
+
else if (months >= 6)
|
|
130
|
+
price *= 0.94;
|
|
131
|
+
else if (months >= 3)
|
|
132
|
+
price *= 0.97;
|
|
133
|
+
price = Number(price.toFixed(2));
|
|
134
|
+
if (price < rates.minUSDPrice)
|
|
135
|
+
price = rates.minUSDPrice;
|
|
136
|
+
return price;
|
|
137
|
+
}
|
|
138
|
+
export function estimateQuote(spec, rates, fluxUsdRate) {
|
|
139
|
+
const usd = estimateUsd(spec, rates);
|
|
140
|
+
const months = spec.expire / BLOCKS_PER_MONTH;
|
|
141
|
+
return {
|
|
142
|
+
usd,
|
|
143
|
+
flux: round2((usd / fluxUsdRate) * rates.fluxmultiplier),
|
|
144
|
+
fluxDiscountPercent: round2(100 - rates.fluxmultiplier * 100),
|
|
145
|
+
expireBlocks: spec.expire,
|
|
146
|
+
months: round2(months),
|
|
147
|
+
usdPerMonth: months > 0 ? round2(usd / months) : usd,
|
|
148
|
+
fluxUsdRate: Number(fluxUsdRate.toFixed(4)),
|
|
149
|
+
source: 'local-estimate',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Consensus floor. Guard only; never quoted.
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
export function chainInterval(table, height) {
|
|
156
|
+
const applicable = table.filter((entry) => entry.height < height);
|
|
157
|
+
const last = applicable[applicable.length - 1];
|
|
158
|
+
if (!last)
|
|
159
|
+
throw new Error(`No chain price interval applies at height ${height}`);
|
|
160
|
+
return last;
|
|
161
|
+
}
|
|
162
|
+
function chainPerMonth(spec, interval) {
|
|
163
|
+
const res = totalResources(spec);
|
|
164
|
+
const enterprisePorts = spec.compose.flatMap((c) => c.ports.filter(isPortEnterprise)).length;
|
|
165
|
+
let total = res.cpu * interval.cpu * 10 + (res.ram * interval.ram) / 100 + res.hdd * interval.hdd;
|
|
166
|
+
if (spec.nodes.length || spec.enterprise)
|
|
167
|
+
total += interval.scope;
|
|
168
|
+
if (spec.staticip)
|
|
169
|
+
total += interval.staticip;
|
|
170
|
+
total += enterprisePorts * interval.port;
|
|
171
|
+
let price = ceil2(total / 3);
|
|
172
|
+
const extra = spec.instances - 1;
|
|
173
|
+
if (extra > 0) {
|
|
174
|
+
if (price < 0.5 && extra > 2)
|
|
175
|
+
price += extra * 0.5;
|
|
176
|
+
else
|
|
177
|
+
price = (Math.ceil(price * extra * 100) + Math.ceil(price * 100)) / 100;
|
|
178
|
+
}
|
|
179
|
+
return price;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The minimum FLUX consensus will accept for this message at `height`
|
|
183
|
+
* (messageVerifier.js). For updates the network additionally credits the
|
|
184
|
+
* unused part of the previous term, so the true minimum is lower still; using
|
|
185
|
+
* the registration formula errs on the safe side.
|
|
186
|
+
*/
|
|
187
|
+
export function consensusMinimumFlux(spec, table, height) {
|
|
188
|
+
const interval = chainInterval(table, height);
|
|
189
|
+
const required = ceil2(chainPerMonth(spec, interval) * (spec.expire / BLOCKS_PER_MONTH));
|
|
190
|
+
return Math.max(required, interval.minPrice);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Flux Cloud MCP server: tools, resources and prompts.
|
|
3
|
+
*
|
|
4
|
+
* Every price shown to an agent is the Flux Cloud USD price. The consensus
|
|
5
|
+
* minimum is never surfaced as a quote.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import type { Config } from './config.js';
|
|
9
|
+
import { walletFromConfig } from './deploy.js';
|
|
10
|
+
export declare const SERVER_NAME = "flux-cloud";
|
|
11
|
+
export declare const SERVER_VERSION = "0.1.0";
|
|
12
|
+
export declare function createServer(config: Config): McpServer;
|
|
13
|
+
export { walletFromConfig };
|