cocoon-sdk 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/README.md +160 -0
- package/dist/index.cjs +2634 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +462 -0
- package/dist/index.d.ts +462 -0
- package/dist/index.js +2588 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2634 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
APIError: () => APIError,
|
|
34
|
+
AuthenticationError: () => AuthenticationError,
|
|
35
|
+
Cocoon: () => Cocoon,
|
|
36
|
+
CocoonError: () => CocoonError,
|
|
37
|
+
ConnectionError: () => ConnectionError,
|
|
38
|
+
FileAttestationProvider: () => FileAttestationProvider,
|
|
39
|
+
ProtocolError: () => ProtocolError,
|
|
40
|
+
StaticAttestationProvider: () => StaticAttestationProvider,
|
|
41
|
+
Stream: () => Stream,
|
|
42
|
+
TimeoutError: () => TimeoutError
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
|
+
|
|
46
|
+
// src/core/protocol/session.ts
|
|
47
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
48
|
+
var import_node_events2 = require("events");
|
|
49
|
+
|
|
50
|
+
// src/core/protocol/connection.ts
|
|
51
|
+
var net = __toESM(require("net"), 1);
|
|
52
|
+
var tls = __toESM(require("tls"), 1);
|
|
53
|
+
var import_node_events = require("events");
|
|
54
|
+
|
|
55
|
+
// src/core/error.ts
|
|
56
|
+
var CocoonError = class extends Error {
|
|
57
|
+
constructor(message) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "CocoonError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ConnectionError = class extends CocoonError {
|
|
63
|
+
constructor(message, cause) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.cause = cause;
|
|
66
|
+
this.name = "ConnectionError";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var ProtocolError = class extends CocoonError {
|
|
70
|
+
constructor(message, code) {
|
|
71
|
+
super(message);
|
|
72
|
+
this.code = code;
|
|
73
|
+
this.name = "ProtocolError";
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var APIError = class extends CocoonError {
|
|
77
|
+
constructor(message, statusCode, errorBody) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.statusCode = statusCode;
|
|
80
|
+
this.errorBody = errorBody;
|
|
81
|
+
this.name = "APIError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var AuthenticationError = class extends CocoonError {
|
|
85
|
+
constructor(message, code) {
|
|
86
|
+
super(message);
|
|
87
|
+
this.code = code;
|
|
88
|
+
this.name = "AuthenticationError";
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var TimeoutError = class extends CocoonError {
|
|
92
|
+
constructor(message = "Request timed out") {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = "TimeoutError";
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/core/protocol/pow.ts
|
|
99
|
+
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
100
|
+
var POW_CHALLENGE_MAGIC = 1099829905;
|
|
101
|
+
var POW_RESPONSE_MAGIC = 25326361;
|
|
102
|
+
var POW_CHALLENGE_SIZE = 24;
|
|
103
|
+
var POW_RESPONSE_SIZE = 12;
|
|
104
|
+
var MAX_DIFFICULTY = 32;
|
|
105
|
+
function parsePowChallenge(data) {
|
|
106
|
+
if (data.length < POW_CHALLENGE_SIZE) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`PoW challenge too short: ${data.length} bytes, expected ${POW_CHALLENGE_SIZE}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const magic = data.readUInt32LE(0);
|
|
112
|
+
if (magic !== POW_CHALLENGE_MAGIC) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Invalid PoW magic: 0x${magic.toString(16)}, expected 0x${POW_CHALLENGE_MAGIC.toString(16)}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
const difficultyBits = data.readInt32LE(4);
|
|
118
|
+
if (difficultyBits < 0 || difficultyBits > MAX_DIFFICULTY) {
|
|
119
|
+
throw new Error(`PoW difficulty out of range: ${difficultyBits}`);
|
|
120
|
+
}
|
|
121
|
+
const salt = Buffer.alloc(16);
|
|
122
|
+
data.copy(salt, 0, 8, 24);
|
|
123
|
+
return { difficultyBits, salt };
|
|
124
|
+
}
|
|
125
|
+
function checkPow(hash, difficultyBits) {
|
|
126
|
+
let remaining = difficultyBits;
|
|
127
|
+
for (let i = 7; i >= 0 && remaining > 0; i--) {
|
|
128
|
+
const byte = hash[i];
|
|
129
|
+
if (remaining >= 8) {
|
|
130
|
+
if (byte !== 0) return false;
|
|
131
|
+
remaining -= 8;
|
|
132
|
+
} else {
|
|
133
|
+
const mask = 255 << 8 - remaining;
|
|
134
|
+
if ((byte & mask) !== 0) return false;
|
|
135
|
+
remaining = 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
function solvePow(challenge) {
|
|
141
|
+
const { difficultyBits, salt } = challenge;
|
|
142
|
+
if (difficultyBits === 0) return 0n;
|
|
143
|
+
const input = Buffer.alloc(24);
|
|
144
|
+
salt.copy(input, 0);
|
|
145
|
+
for (let nonce = 0n; ; nonce++) {
|
|
146
|
+
input.writeBigUInt64LE(nonce, 16);
|
|
147
|
+
const hash = import_node_crypto.default.createHash("sha256").update(input).digest();
|
|
148
|
+
if (checkPow(hash, difficultyBits)) {
|
|
149
|
+
return nonce;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function buildPowResponse(nonce) {
|
|
154
|
+
const buf = Buffer.alloc(POW_RESPONSE_SIZE);
|
|
155
|
+
buf.writeUInt32LE(POW_RESPONSE_MAGIC, 0);
|
|
156
|
+
buf.writeBigUInt64LE(nonce, 4);
|
|
157
|
+
return buf;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/core/protocol/connection.ts
|
|
161
|
+
var CocoonConnection = class extends import_node_events.EventEmitter {
|
|
162
|
+
socket = null;
|
|
163
|
+
rawSocket = null;
|
|
164
|
+
outSeqno = 0;
|
|
165
|
+
inSeqno = 0;
|
|
166
|
+
readBuffer = Buffer.alloc(0);
|
|
167
|
+
connected = false;
|
|
168
|
+
destroyed = false;
|
|
169
|
+
host;
|
|
170
|
+
port;
|
|
171
|
+
useTls;
|
|
172
|
+
timeout;
|
|
173
|
+
tlsCert;
|
|
174
|
+
tlsKey;
|
|
175
|
+
constructor(options) {
|
|
176
|
+
super();
|
|
177
|
+
this.host = options.host;
|
|
178
|
+
this.port = options.port;
|
|
179
|
+
this.useTls = options.useTls ?? true;
|
|
180
|
+
this.timeout = options.timeout ?? 12e4;
|
|
181
|
+
this.tlsCert = options.tlsCert;
|
|
182
|
+
this.tlsKey = options.tlsKey;
|
|
183
|
+
}
|
|
184
|
+
async connect() {
|
|
185
|
+
if (this.connected) return;
|
|
186
|
+
if (this.useTls) {
|
|
187
|
+
await this.connectWithPowAndTls();
|
|
188
|
+
} else {
|
|
189
|
+
await this.connectPlainTcp();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Connect with PoW challenge + TLS upgrade (default for Cocoon proxies).
|
|
194
|
+
*/
|
|
195
|
+
async connectWithPowAndTls() {
|
|
196
|
+
const rawSocket = await this.rawTcpConnect();
|
|
197
|
+
this.rawSocket = rawSocket;
|
|
198
|
+
try {
|
|
199
|
+
await this.handlePow(rawSocket);
|
|
200
|
+
this.socket = await this.upgradeTls(rawSocket);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
rawSocket.destroy();
|
|
203
|
+
this.rawSocket = null;
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
this.connected = true;
|
|
207
|
+
this.setupSocketHandlers(this.socket);
|
|
208
|
+
this.emit("ready");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Connect with plain TCP (no PoW, no TLS).
|
|
212
|
+
*/
|
|
213
|
+
async connectPlainTcp() {
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
const onConnect = () => {
|
|
216
|
+
this.connected = true;
|
|
217
|
+
this.setupSocketHandlers(this.socket);
|
|
218
|
+
this.emit("ready");
|
|
219
|
+
resolve();
|
|
220
|
+
};
|
|
221
|
+
const onError = (err) => {
|
|
222
|
+
reject(
|
|
223
|
+
new ConnectionError(
|
|
224
|
+
`Failed to connect to ${this.host}:${this.port}: ${err.message}`,
|
|
225
|
+
err
|
|
226
|
+
)
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
this.socket = net.connect({ host: this.host, port: this.port }, onConnect);
|
|
230
|
+
this.socket.setTimeout(this.timeout);
|
|
231
|
+
this.socket.once("error", onError);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
rawTcpConnect() {
|
|
235
|
+
return new Promise((resolve, reject) => {
|
|
236
|
+
const sock = net.connect({ host: this.host, port: this.port }, () => {
|
|
237
|
+
sock.removeListener("error", onError);
|
|
238
|
+
resolve(sock);
|
|
239
|
+
});
|
|
240
|
+
sock.setTimeout(this.timeout);
|
|
241
|
+
const onError = (err) => {
|
|
242
|
+
reject(
|
|
243
|
+
new ConnectionError(
|
|
244
|
+
`Failed to connect to ${this.host}:${this.port}: ${err.message}`,
|
|
245
|
+
err
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
sock.once("error", onError);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
handlePow(sock) {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
let powBuffer = Buffer.alloc(0);
|
|
255
|
+
const timer = setTimeout(() => {
|
|
256
|
+
sock.removeListener("data", onData);
|
|
257
|
+
reject(new ConnectionError("Timeout waiting for PoW challenge"));
|
|
258
|
+
}, 3e4);
|
|
259
|
+
const onData = (chunk) => {
|
|
260
|
+
powBuffer = Buffer.concat([powBuffer, chunk]);
|
|
261
|
+
if (powBuffer.length >= 4) {
|
|
262
|
+
const magic = powBuffer.readUInt32LE(0);
|
|
263
|
+
if (magic !== POW_CHALLENGE_MAGIC) {
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
sock.removeListener("data", onData);
|
|
266
|
+
reject(
|
|
267
|
+
new ConnectionError(
|
|
268
|
+
`Unexpected data from proxy (expected PoW challenge): 0x${magic.toString(16)}`
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (powBuffer.length >= POW_CHALLENGE_SIZE) {
|
|
275
|
+
clearTimeout(timer);
|
|
276
|
+
sock.removeListener("data", onData);
|
|
277
|
+
try {
|
|
278
|
+
const challenge = parsePowChallenge(powBuffer);
|
|
279
|
+
const nonce = solvePow(challenge);
|
|
280
|
+
const response = buildPowResponse(nonce);
|
|
281
|
+
sock.write(response, (err) => {
|
|
282
|
+
if (err) {
|
|
283
|
+
reject(new ConnectionError(`Failed to send PoW response: ${err.message}`, err));
|
|
284
|
+
} else {
|
|
285
|
+
resolve();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
} catch (err) {
|
|
289
|
+
reject(
|
|
290
|
+
new ConnectionError(
|
|
291
|
+
`PoW failed: ${err instanceof Error ? err.message : err}`,
|
|
292
|
+
err instanceof Error ? err : void 0
|
|
293
|
+
)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
sock.on("data", onData);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
upgradeTls(rawSocket) {
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
const tlsOptions = {
|
|
304
|
+
socket: rawSocket,
|
|
305
|
+
rejectUnauthorized: false
|
|
306
|
+
// Cocoon uses custom TDX attestation, not standard CA
|
|
307
|
+
};
|
|
308
|
+
if (this.tlsCert) tlsOptions.cert = this.tlsCert;
|
|
309
|
+
if (this.tlsKey) tlsOptions.key = this.tlsKey;
|
|
310
|
+
const tlsSocket = tls.connect(tlsOptions);
|
|
311
|
+
const timer = setTimeout(() => {
|
|
312
|
+
cleanup(() => reject(new ConnectionError("TLS handshake timeout")));
|
|
313
|
+
}, this.timeout);
|
|
314
|
+
const cleanup = (next) => {
|
|
315
|
+
clearTimeout(timer);
|
|
316
|
+
tlsSocket.removeListener("secureConnect", onSecureConnect);
|
|
317
|
+
tlsSocket.removeListener("error", onError);
|
|
318
|
+
tlsSocket.removeListener("close", onClose);
|
|
319
|
+
if (next) next();
|
|
320
|
+
};
|
|
321
|
+
const onSecureConnect = () => {
|
|
322
|
+
cleanup(() => resolve(tlsSocket));
|
|
323
|
+
};
|
|
324
|
+
const onError = (err) => {
|
|
325
|
+
cleanup(() => reject(new ConnectionError(`TLS handshake failed: ${err.message}`, err)));
|
|
326
|
+
};
|
|
327
|
+
const onClose = () => {
|
|
328
|
+
cleanup(() => reject(new ConnectionError("TLS socket closed before handshake completed")));
|
|
329
|
+
};
|
|
330
|
+
tlsSocket.once("secureConnect", onSecureConnect);
|
|
331
|
+
tlsSocket.once("error", onError);
|
|
332
|
+
tlsSocket.once("close", onClose);
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
setupSocketHandlers(sock) {
|
|
336
|
+
sock.setTimeout(this.timeout);
|
|
337
|
+
sock.on("data", (data) => this.onData(data));
|
|
338
|
+
sock.on("close", () => this.onClose());
|
|
339
|
+
sock.on("timeout", () => {
|
|
340
|
+
this.destroy(new ConnectionError("Connection timed out"));
|
|
341
|
+
});
|
|
342
|
+
sock.on("error", (err) => {
|
|
343
|
+
if (this.connected) {
|
|
344
|
+
this.destroy(new ConnectionError(`Socket error: ${err.message}`, err));
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Send a framed packet: [4b size][4b seqno][payload]
|
|
350
|
+
*/
|
|
351
|
+
send(payload) {
|
|
352
|
+
if (!this.socket || this.destroyed) {
|
|
353
|
+
throw new ConnectionError("Not connected");
|
|
354
|
+
}
|
|
355
|
+
const frame = Buffer.alloc(8 + payload.length);
|
|
356
|
+
frame.writeUInt32LE(payload.length, 0);
|
|
357
|
+
frame.writeInt32LE(this.outSeqno, 4);
|
|
358
|
+
payload.copy(frame, 8);
|
|
359
|
+
this.outSeqno++;
|
|
360
|
+
this.socket.write(frame);
|
|
361
|
+
}
|
|
362
|
+
destroy(error) {
|
|
363
|
+
if (this.destroyed) return;
|
|
364
|
+
this.destroyed = true;
|
|
365
|
+
this.connected = false;
|
|
366
|
+
if (this.socket) {
|
|
367
|
+
this.socket.destroy();
|
|
368
|
+
this.socket = null;
|
|
369
|
+
}
|
|
370
|
+
if (this.rawSocket) {
|
|
371
|
+
this.rawSocket.destroy();
|
|
372
|
+
this.rawSocket = null;
|
|
373
|
+
}
|
|
374
|
+
this.emit("close", error);
|
|
375
|
+
}
|
|
376
|
+
get isConnected() {
|
|
377
|
+
return this.connected && !this.destroyed;
|
|
378
|
+
}
|
|
379
|
+
onData(chunk) {
|
|
380
|
+
this.readBuffer = Buffer.concat([this.readBuffer, chunk]);
|
|
381
|
+
this.processFrames();
|
|
382
|
+
}
|
|
383
|
+
processFrames() {
|
|
384
|
+
while (this.readBuffer.length >= 8) {
|
|
385
|
+
const size = this.readBuffer.readUInt32LE(0);
|
|
386
|
+
if (size > 1 << 24 || size < 0) {
|
|
387
|
+
this.destroy(new ConnectionError(`Invalid frame size: ${size}`));
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const totalFrameSize = 8 + size;
|
|
391
|
+
if (this.readBuffer.length < totalFrameSize) {
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
const seqno = this.readBuffer.readInt32LE(4);
|
|
395
|
+
if (seqno !== this.inSeqno) {
|
|
396
|
+
this.destroy(
|
|
397
|
+
new ConnectionError(`Sequence number mismatch: expected ${this.inSeqno}, got ${seqno}`)
|
|
398
|
+
);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const payload = Buffer.alloc(size);
|
|
402
|
+
this.readBuffer.copy(payload, 0, 8, totalFrameSize);
|
|
403
|
+
this.readBuffer = this.readBuffer.subarray(totalFrameSize);
|
|
404
|
+
this.inSeqno++;
|
|
405
|
+
this.emit("frame", payload);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
onClose() {
|
|
409
|
+
if (!this.destroyed) {
|
|
410
|
+
this.destroy();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// src/core/tl/schema.ts
|
|
416
|
+
var crc32Table = new Uint32Array(256);
|
|
417
|
+
for (let i = 0; i < 256; i++) {
|
|
418
|
+
let c = i;
|
|
419
|
+
for (let j = 0; j < 8; j++) {
|
|
420
|
+
if (c & 1) {
|
|
421
|
+
c = 3988292384 ^ c >>> 1;
|
|
422
|
+
} else {
|
|
423
|
+
c = c >>> 1;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
crc32Table[i] = c;
|
|
427
|
+
}
|
|
428
|
+
function crc32(str) {
|
|
429
|
+
const bytes = Buffer.from(str, "utf-8");
|
|
430
|
+
let crc = 4294967295;
|
|
431
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
432
|
+
crc = crc32Table[(crc ^ bytes[i]) & 255] ^ crc >>> 8;
|
|
433
|
+
}
|
|
434
|
+
return (crc ^ 4294967295) >>> 0;
|
|
435
|
+
}
|
|
436
|
+
function tlId(definition) {
|
|
437
|
+
return crc32(definition.trim());
|
|
438
|
+
}
|
|
439
|
+
var TL_SCHEMA = {
|
|
440
|
+
// --- TCP Layer ---
|
|
441
|
+
"tcp.ping": {
|
|
442
|
+
id: tlId("tcp.ping id:long = tcp.Packet"),
|
|
443
|
+
fields: [{ name: "id", type: "long" }]
|
|
444
|
+
},
|
|
445
|
+
"tcp.pong": {
|
|
446
|
+
id: tlId("tcp.pong id:long = tcp.Packet"),
|
|
447
|
+
fields: [{ name: "id", type: "long" }]
|
|
448
|
+
},
|
|
449
|
+
"tcp.packet": {
|
|
450
|
+
id: tlId("tcp.packet data:bytes = tcp.Packet"),
|
|
451
|
+
fields: [{ name: "data", type: "bytes" }]
|
|
452
|
+
},
|
|
453
|
+
"tcp.queryAnswer": {
|
|
454
|
+
id: tlId("tcp.queryAnswer id:long data:bytes = tcp.Packet"),
|
|
455
|
+
fields: [
|
|
456
|
+
{ name: "id", type: "long" },
|
|
457
|
+
{ name: "data", type: "bytes" }
|
|
458
|
+
]
|
|
459
|
+
},
|
|
460
|
+
"tcp.queryError": {
|
|
461
|
+
id: tlId("tcp.queryError id:long code:int message:string = tcp.Packet"),
|
|
462
|
+
fields: [
|
|
463
|
+
{ name: "id", type: "long" },
|
|
464
|
+
{ name: "code", type: "int" },
|
|
465
|
+
{ name: "message", type: "string" }
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
"tcp.query": {
|
|
469
|
+
id: tlId("tcp.query id:long data:bytes = tcp.Packet"),
|
|
470
|
+
fields: [
|
|
471
|
+
{ name: "id", type: "long" },
|
|
472
|
+
{ name: "data", type: "bytes" }
|
|
473
|
+
]
|
|
474
|
+
},
|
|
475
|
+
"tcp.connected": {
|
|
476
|
+
id: tlId("tcp.connected id:long = tcp.Packet"),
|
|
477
|
+
fields: [{ name: "id", type: "long" }]
|
|
478
|
+
},
|
|
479
|
+
"tcp.connect": {
|
|
480
|
+
id: tlId("tcp.connect id:long = tcp.Packet"),
|
|
481
|
+
fields: [{ name: "id", type: "long" }]
|
|
482
|
+
},
|
|
483
|
+
// --- Tokens ---
|
|
484
|
+
tokensUsed: {
|
|
485
|
+
id: tlId(
|
|
486
|
+
"tokensUsed prompt_tokens_used:long cached_tokens_used:long completion_tokens_used:long reasoning_tokens_used:long total_tokens_used:long = TokensUsed"
|
|
487
|
+
),
|
|
488
|
+
fields: [
|
|
489
|
+
{ name: "promptTokensUsed", type: "long" },
|
|
490
|
+
{ name: "cachedTokensUsed", type: "long" },
|
|
491
|
+
{ name: "completionTokensUsed", type: "long" },
|
|
492
|
+
{ name: "reasoningTokensUsed", type: "long" },
|
|
493
|
+
{ name: "totalTokensUsed", type: "long" }
|
|
494
|
+
]
|
|
495
|
+
},
|
|
496
|
+
// --- Client/Proxy Params ---
|
|
497
|
+
// worker.params has explicit ID: #869c73ed
|
|
498
|
+
"worker.params": {
|
|
499
|
+
id: 2258400237,
|
|
500
|
+
fields: [
|
|
501
|
+
{ name: "flags", type: "int" },
|
|
502
|
+
{ name: "workerOwnerAddress", type: "string" },
|
|
503
|
+
{ name: "model", type: "string" },
|
|
504
|
+
{ name: "coefficient", type: "int" },
|
|
505
|
+
{ name: "isTest", type: "Bool", flag: { field: "flags", bit: 0 } },
|
|
506
|
+
{ name: "proxyCnt", type: "int", flag: { field: "flags", bit: 0 } },
|
|
507
|
+
{ name: "maxActiveRequests", type: "int", flag: { field: "flags", bit: 0 } },
|
|
508
|
+
{ name: "minProtoVersion", type: "int", flag: { field: "flags", bit: 1 } },
|
|
509
|
+
{ name: "maxProtoVersion", type: "int", flag: { field: "flags", bit: 1 } }
|
|
510
|
+
]
|
|
511
|
+
},
|
|
512
|
+
// proxy.params has explicit ID: #d5c5609f
|
|
513
|
+
"proxy.params": {
|
|
514
|
+
id: 3586482335,
|
|
515
|
+
fields: [
|
|
516
|
+
{ name: "flags", type: "int" },
|
|
517
|
+
{ name: "proxyPublicKey", type: "int256" },
|
|
518
|
+
{ name: "proxyOwnerAddress", type: "string" },
|
|
519
|
+
{ name: "proxyScAddress", type: "string" },
|
|
520
|
+
{ name: "isTest", type: "Bool", flag: { field: "flags", bit: 0 } },
|
|
521
|
+
{ name: "protoVersion", type: "int", flag: { field: "flags", bit: 1 } }
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
// client.params has explicit ID: #40fdca64
|
|
525
|
+
"client.params": {
|
|
526
|
+
id: 1090374244,
|
|
527
|
+
fields: [
|
|
528
|
+
{ name: "flags", type: "int" },
|
|
529
|
+
{ name: "clientOwnerAddress", type: "string" },
|
|
530
|
+
{ name: "isTest", type: "Bool", flag: { field: "flags", bit: 0 } },
|
|
531
|
+
{ name: "minProtoVersion", type: "int", flag: { field: "flags", bit: 1 } },
|
|
532
|
+
{ name: "maxProtoVersion", type: "int", flag: { field: "flags", bit: 1 } }
|
|
533
|
+
]
|
|
534
|
+
},
|
|
535
|
+
// --- Auth ---
|
|
536
|
+
"client.proxyConnectionAuthShort": {
|
|
537
|
+
id: tlId(
|
|
538
|
+
"client.proxyConnectionAuthShort secret_hash:int256 nonce:long = client.ProxyConnectionAuth"
|
|
539
|
+
),
|
|
540
|
+
fields: [
|
|
541
|
+
{ name: "secretHash", type: "int256" },
|
|
542
|
+
{ name: "nonce", type: "long" }
|
|
543
|
+
]
|
|
544
|
+
},
|
|
545
|
+
"client.proxyConnectionAuthLong": {
|
|
546
|
+
id: tlId("client.proxyConnectionAuthLong nonce:long = client.ProxyConnectionAuth"),
|
|
547
|
+
fields: [{ name: "nonce", type: "long" }]
|
|
548
|
+
},
|
|
549
|
+
// --- Signed Payment ---
|
|
550
|
+
"proxy.signedPayment": {
|
|
551
|
+
id: tlId("proxy.signedPayment data:bytes = proxy.SignedPayment"),
|
|
552
|
+
fields: [{ name: "data", type: "bytes" }]
|
|
553
|
+
},
|
|
554
|
+
"proxy.signedPaymentEmpty": {
|
|
555
|
+
id: tlId("proxy.signedPaymentEmpty = proxy.SignedPayment"),
|
|
556
|
+
fields: []
|
|
557
|
+
},
|
|
558
|
+
// --- Connected To Proxy ---
|
|
559
|
+
"client.connectedToProxy": {
|
|
560
|
+
id: tlId(
|
|
561
|
+
"client.connectedToProxy params:proxy.params client_sc_address:string auth:client.ProxyConnectionAuth signed_payment:proxy.SignedPayment = client.ConnectedToProxy"
|
|
562
|
+
),
|
|
563
|
+
fields: [
|
|
564
|
+
{ name: "params", type: { ref: "proxy.params" } },
|
|
565
|
+
{ name: "clientScAddress", type: "string" },
|
|
566
|
+
{ name: "auth", type: { ref: "client.ProxyConnectionAuth" } },
|
|
567
|
+
{ name: "signedPayment", type: { ref: "proxy.SignedPayment" } }
|
|
568
|
+
]
|
|
569
|
+
},
|
|
570
|
+
// --- Auth Responses ---
|
|
571
|
+
"client.authorizationWithProxySuccess": {
|
|
572
|
+
id: tlId(
|
|
573
|
+
"client.authorizationWithProxySuccess signed_payment:proxy.SignedPayment tokens_committed_to_db:long max_tokens:long = client.AuthorizationWithProxy"
|
|
574
|
+
),
|
|
575
|
+
fields: [
|
|
576
|
+
{ name: "signedPayment", type: { ref: "proxy.SignedPayment" } },
|
|
577
|
+
{ name: "tokensCommittedToDb", type: "long" },
|
|
578
|
+
{ name: "maxTokens", type: "long" }
|
|
579
|
+
]
|
|
580
|
+
},
|
|
581
|
+
"client.authorizationWithProxyFailed": {
|
|
582
|
+
id: tlId(
|
|
583
|
+
"client.authorizationWithProxyFailed error_code:int error:string = client.AuthorizationWithProxy"
|
|
584
|
+
),
|
|
585
|
+
fields: [
|
|
586
|
+
{ name: "errorCode", type: "int" },
|
|
587
|
+
{ name: "error", type: "string" }
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
// --- Query Final Info ---
|
|
591
|
+
"client.queryFinalInfo": {
|
|
592
|
+
id: tlId(
|
|
593
|
+
"client.queryFinalInfo flags:# tokens_used:tokensUsed worker_debug:flags.0?string proxy_debug:flags.0?string proxy_start_time:flags.1?double proxy_end_time:flags.1?double worker_start_time:flags.1?double worker_end_time:flags.1?double = client.QueryFinalInfo"
|
|
594
|
+
),
|
|
595
|
+
fields: [
|
|
596
|
+
{ name: "flags", type: "int" },
|
|
597
|
+
{ name: "tokensUsed", type: { ref: "tokensUsed" } },
|
|
598
|
+
{ name: "workerDebug", type: "string", flag: { field: "flags", bit: 0 } },
|
|
599
|
+
{ name: "proxyDebug", type: "string", flag: { field: "flags", bit: 0 } },
|
|
600
|
+
{ name: "proxyStartTime", type: "double", flag: { field: "flags", bit: 1 } },
|
|
601
|
+
{ name: "proxyEndTime", type: "double", flag: { field: "flags", bit: 1 } },
|
|
602
|
+
{ name: "workerStartTime", type: "double", flag: { field: "flags", bit: 1 } },
|
|
603
|
+
{ name: "workerEndTime", type: "double", flag: { field: "flags", bit: 1 } }
|
|
604
|
+
]
|
|
605
|
+
},
|
|
606
|
+
// --- Query Answer Ex variants ---
|
|
607
|
+
// Legacy variants (still sent by some proxy paths):
|
|
608
|
+
"client.queryAnswer": {
|
|
609
|
+
id: tlId(
|
|
610
|
+
"client.queryAnswer answer:bytes is_completed:Bool request_id:int256 request_tokens_used:tokensUsed = client.QueryAnswer"
|
|
611
|
+
),
|
|
612
|
+
fields: [
|
|
613
|
+
{ name: "answer", type: "bytes" },
|
|
614
|
+
{ name: "isCompleted", type: "Bool" },
|
|
615
|
+
{ name: "requestId", type: "int256" },
|
|
616
|
+
{ name: "requestTokensUsed", type: { ref: "tokensUsed" } }
|
|
617
|
+
]
|
|
618
|
+
},
|
|
619
|
+
"client.queryAnswerError": {
|
|
620
|
+
id: tlId(
|
|
621
|
+
"client.queryAnswerError error_code:int error:string request_id:int256 request_tokens_used:tokensUsed = client.QueryAnswer"
|
|
622
|
+
),
|
|
623
|
+
fields: [
|
|
624
|
+
{ name: "errorCode", type: "int" },
|
|
625
|
+
{ name: "error", type: "string" },
|
|
626
|
+
{ name: "requestId", type: "int256" },
|
|
627
|
+
{ name: "requestTokensUsed", type: { ref: "tokensUsed" } }
|
|
628
|
+
]
|
|
629
|
+
},
|
|
630
|
+
"client.queryAnswerPart": {
|
|
631
|
+
id: tlId(
|
|
632
|
+
"client.queryAnswerPart answer:bytes is_completed:Bool request_id:int256 request_tokens_used:tokensUsed = client.QueryAnswerPart"
|
|
633
|
+
),
|
|
634
|
+
fields: [
|
|
635
|
+
{ name: "answer", type: "bytes" },
|
|
636
|
+
{ name: "isCompleted", type: "Bool" },
|
|
637
|
+
{ name: "requestId", type: "int256" },
|
|
638
|
+
{ name: "requestTokensUsed", type: { ref: "tokensUsed" } }
|
|
639
|
+
]
|
|
640
|
+
},
|
|
641
|
+
"client.queryAnswerPartError": {
|
|
642
|
+
id: tlId(
|
|
643
|
+
"client.queryAnswerPartError error_code:int error:string request_id:int256 request_tokens_used:tokensUsed = client.QueryAnswerPart"
|
|
644
|
+
),
|
|
645
|
+
fields: [
|
|
646
|
+
{ name: "errorCode", type: "int" },
|
|
647
|
+
{ name: "error", type: "string" },
|
|
648
|
+
{ name: "requestId", type: "int256" },
|
|
649
|
+
{ name: "requestTokensUsed", type: { ref: "tokensUsed" } }
|
|
650
|
+
]
|
|
651
|
+
},
|
|
652
|
+
"client.queryAnswerEx": {
|
|
653
|
+
id: tlId(
|
|
654
|
+
"client.queryAnswerEx request_id:int256 answer:bytes flags:# final_info:flags.0?client.queryFinalInfo = client.QueryAnswerEx"
|
|
655
|
+
),
|
|
656
|
+
fields: [
|
|
657
|
+
{ name: "requestId", type: "int256" },
|
|
658
|
+
{ name: "answer", type: "bytes" },
|
|
659
|
+
{ name: "flags", type: "int" },
|
|
660
|
+
{
|
|
661
|
+
name: "finalInfo",
|
|
662
|
+
type: { ref: "client.queryFinalInfo" },
|
|
663
|
+
flag: { field: "flags", bit: 0 }
|
|
664
|
+
}
|
|
665
|
+
]
|
|
666
|
+
},
|
|
667
|
+
"client.queryAnswerErrorEx": {
|
|
668
|
+
id: tlId(
|
|
669
|
+
"client.queryAnswerErrorEx request_id:int256 error_code:int error:string flags:# final_info:flags.0?client.queryFinalInfo = client.QueryAnswerEx"
|
|
670
|
+
),
|
|
671
|
+
fields: [
|
|
672
|
+
{ name: "requestId", type: "int256" },
|
|
673
|
+
{ name: "errorCode", type: "int" },
|
|
674
|
+
{ name: "error", type: "string" },
|
|
675
|
+
{ name: "flags", type: "int" },
|
|
676
|
+
{
|
|
677
|
+
name: "finalInfo",
|
|
678
|
+
type: { ref: "client.queryFinalInfo" },
|
|
679
|
+
flag: { field: "flags", bit: 0 }
|
|
680
|
+
}
|
|
681
|
+
]
|
|
682
|
+
},
|
|
683
|
+
"client.queryAnswerPartEx": {
|
|
684
|
+
id: tlId(
|
|
685
|
+
"client.queryAnswerPartEx request_id:int256 answer:bytes flags:# final_info:flags.0?client.queryFinalInfo = client.QueryAnswerEx"
|
|
686
|
+
),
|
|
687
|
+
fields: [
|
|
688
|
+
{ name: "requestId", type: "int256" },
|
|
689
|
+
{ name: "answer", type: "bytes" },
|
|
690
|
+
{ name: "flags", type: "int" },
|
|
691
|
+
{
|
|
692
|
+
name: "finalInfo",
|
|
693
|
+
type: { ref: "client.queryFinalInfo" },
|
|
694
|
+
flag: { field: "flags", bit: 0 }
|
|
695
|
+
}
|
|
696
|
+
]
|
|
697
|
+
},
|
|
698
|
+
// --- Worker Types V2 ---
|
|
699
|
+
// client.workerInstanceV2 has explicit ID: #3ea93d00
|
|
700
|
+
"client.workerInstanceV2": {
|
|
701
|
+
id: 1051278592,
|
|
702
|
+
fields: [
|
|
703
|
+
{ name: "flags", type: "int" },
|
|
704
|
+
{ name: "coefficient", type: "int" },
|
|
705
|
+
{ name: "activeRequests", type: "int" },
|
|
706
|
+
{ name: "maxActiveRequests", type: "int" }
|
|
707
|
+
]
|
|
708
|
+
},
|
|
709
|
+
"client.workerTypeV2": {
|
|
710
|
+
// NOTE: Telegram TL canonical CRC for vector fields uses "vector T" syntax.
|
|
711
|
+
// Equivalent canonical form:
|
|
712
|
+
// "client.workerTypeV2 name:string workers:vector client.workerInstanceV2 = client.WorkerTypeV2"
|
|
713
|
+
id: 2994569623,
|
|
714
|
+
fields: [
|
|
715
|
+
{ name: "name", type: "string" },
|
|
716
|
+
{ name: "workers", type: { vector: { ref: "client.workerInstanceV2" }, bare: true } }
|
|
717
|
+
]
|
|
718
|
+
},
|
|
719
|
+
"client.workerTypesV2": {
|
|
720
|
+
// Canonical form:
|
|
721
|
+
// "client.workerTypesV2 types:vector client.workerTypeV2 = client.WorkerTypesV2"
|
|
722
|
+
id: 217111655,
|
|
723
|
+
fields: [{ name: "types", type: { vector: { ref: "client.workerTypeV2" }, bare: true } }]
|
|
724
|
+
},
|
|
725
|
+
// --- Payment ---
|
|
726
|
+
"client.paymentStatus": {
|
|
727
|
+
id: tlId(
|
|
728
|
+
"client.paymentStatus signed_payment:proxy.SignedPayment db_tokens:long max_tokens:long = client.PaymentStatus"
|
|
729
|
+
),
|
|
730
|
+
fields: [
|
|
731
|
+
{ name: "signedPayment", type: { ref: "proxy.SignedPayment" } },
|
|
732
|
+
{ name: "dbTokens", type: "long" },
|
|
733
|
+
{ name: "maxTokens", type: "long" }
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
// Payment request from proxy to client (may be sent during query flow).
|
|
737
|
+
"proxy.clientRequestPayment": {
|
|
738
|
+
id: tlId(
|
|
739
|
+
"proxy.clientRequestPayment request_id:int256 signed_payment:proxy.SignedPayment db_tokens:long max_tokens:long request_tokens:long = proxy.WorkerRequestPayment"
|
|
740
|
+
),
|
|
741
|
+
fields: [
|
|
742
|
+
{ name: "requestId", type: "int256" },
|
|
743
|
+
{ name: "signedPayment", type: { ref: "proxy.SignedPayment" } },
|
|
744
|
+
{ name: "dbTokens", type: "long" },
|
|
745
|
+
{ name: "maxTokens", type: "long" },
|
|
746
|
+
{ name: "requestTokens", type: "long" }
|
|
747
|
+
]
|
|
748
|
+
},
|
|
749
|
+
"client.refund": {
|
|
750
|
+
id: tlId("client.refund data:bytes = client.Refund"),
|
|
751
|
+
fields: [{ name: "data", type: "bytes" }]
|
|
752
|
+
},
|
|
753
|
+
"client.refundRejected": {
|
|
754
|
+
id: tlId("client.refundRejected active_queries:long = client.Refund"),
|
|
755
|
+
fields: [{ name: "activeQueries", type: "long" }]
|
|
756
|
+
},
|
|
757
|
+
// --- HTTP ---
|
|
758
|
+
"http.header": {
|
|
759
|
+
id: tlId("http.header name:string value:string = http.Header"),
|
|
760
|
+
fields: [
|
|
761
|
+
{ name: "name", type: "string" },
|
|
762
|
+
{ name: "value", type: "string" }
|
|
763
|
+
]
|
|
764
|
+
},
|
|
765
|
+
"http.response": {
|
|
766
|
+
// Canonical vector form for CRC:
|
|
767
|
+
// "http.response http_version:string status_code:int reason:string headers:vector http.header payload:bytes = http.Response"
|
|
768
|
+
id: 483443755,
|
|
769
|
+
fields: [
|
|
770
|
+
{ name: "httpVersion", type: "string" },
|
|
771
|
+
{ name: "statusCode", type: "int" },
|
|
772
|
+
{ name: "reason", type: "string" },
|
|
773
|
+
{ name: "headers", type: { vector: { ref: "http.header" }, bare: true } },
|
|
774
|
+
{ name: "payload", type: "bytes" }
|
|
775
|
+
]
|
|
776
|
+
},
|
|
777
|
+
"http.request": {
|
|
778
|
+
// Canonical vector form for CRC:
|
|
779
|
+
// "http.request method:string url:string http_version:string headers:vector http.header payload:bytes = http.Response"
|
|
780
|
+
id: 1195978213,
|
|
781
|
+
fields: [
|
|
782
|
+
{ name: "method", type: "string" },
|
|
783
|
+
{ name: "url", type: "string" },
|
|
784
|
+
{ name: "httpVersion", type: "string" },
|
|
785
|
+
{ name: "headers", type: { vector: { ref: "http.header" }, bare: true } },
|
|
786
|
+
{ name: "payload", type: "bytes" }
|
|
787
|
+
],
|
|
788
|
+
isFunction: true
|
|
789
|
+
},
|
|
790
|
+
// --- Root Config ---
|
|
791
|
+
"rootConfig.registeredProxy": {
|
|
792
|
+
id: tlId("rootConfig.registeredProxy seqno:int address:string = rootConfig.RegisteredProxy"),
|
|
793
|
+
fields: [
|
|
794
|
+
{ name: "seqno", type: "int" },
|
|
795
|
+
{ name: "address", type: "string" }
|
|
796
|
+
]
|
|
797
|
+
},
|
|
798
|
+
// --- Functions ---
|
|
799
|
+
"client.connectToProxy": {
|
|
800
|
+
id: tlId(
|
|
801
|
+
"client.connectToProxy params:client.params min_config_version:int = client.ConnectedToProxy"
|
|
802
|
+
),
|
|
803
|
+
fields: [
|
|
804
|
+
{ name: "params", type: { ref: "client.params" } },
|
|
805
|
+
{ name: "minConfigVersion", type: "int" }
|
|
806
|
+
],
|
|
807
|
+
isFunction: true
|
|
808
|
+
},
|
|
809
|
+
"client.authorizeWithProxyShort": {
|
|
810
|
+
id: tlId("client.authorizeWithProxyShort data:bytes = client.AuthorizationWithProxy"),
|
|
811
|
+
fields: [{ name: "data", type: "bytes" }],
|
|
812
|
+
isFunction: true
|
|
813
|
+
},
|
|
814
|
+
"client.authorizeWithProxyLong": {
|
|
815
|
+
id: tlId("client.authorizeWithProxyLong = client.AuthorizationWithProxy"),
|
|
816
|
+
fields: [],
|
|
817
|
+
isFunction: true
|
|
818
|
+
},
|
|
819
|
+
"client.runQueryEx": {
|
|
820
|
+
id: tlId(
|
|
821
|
+
"client.runQueryEx model_name:string query:bytes max_coefficient:int max_tokens:int timeout:double request_id:int256 min_config_version:int flags:# enable_debug:flags.0?Bool = client.QueryAnswerEx"
|
|
822
|
+
),
|
|
823
|
+
fields: [
|
|
824
|
+
{ name: "modelName", type: "string" },
|
|
825
|
+
{ name: "query", type: "bytes" },
|
|
826
|
+
{ name: "maxCoefficient", type: "int" },
|
|
827
|
+
{ name: "maxTokens", type: "int" },
|
|
828
|
+
{ name: "timeout", type: "double" },
|
|
829
|
+
{ name: "requestId", type: "int256" },
|
|
830
|
+
{ name: "minConfigVersion", type: "int" },
|
|
831
|
+
{ name: "flags", type: "int" },
|
|
832
|
+
{ name: "enableDebug", type: "Bool", flag: { field: "flags", bit: 0 } }
|
|
833
|
+
],
|
|
834
|
+
isFunction: true
|
|
835
|
+
},
|
|
836
|
+
"client.getWorkerTypesV2": {
|
|
837
|
+
id: tlId("client.getWorkerTypesV2 = client.WorkerTypesV2"),
|
|
838
|
+
fields: [],
|
|
839
|
+
isFunction: true
|
|
840
|
+
},
|
|
841
|
+
"client.updatePaymentStatus": {
|
|
842
|
+
id: tlId("client.updatePaymentStatus = client.PaymentStatus"),
|
|
843
|
+
fields: [],
|
|
844
|
+
isFunction: true
|
|
845
|
+
},
|
|
846
|
+
"client.requestRefund": {
|
|
847
|
+
id: tlId("client.requestRefund = client.Refund"),
|
|
848
|
+
fields: [],
|
|
849
|
+
isFunction: true
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
var CONSTRUCTOR_ID_MAP = /* @__PURE__ */ new Map();
|
|
853
|
+
for (const [name, def] of Object.entries(TL_SCHEMA)) {
|
|
854
|
+
CONSTRUCTOR_ID_MAP.set(def.id, name);
|
|
855
|
+
}
|
|
856
|
+
var POLYMORPHIC_TYPES = {
|
|
857
|
+
"tcp.Packet": [
|
|
858
|
+
"tcp.ping",
|
|
859
|
+
"tcp.pong",
|
|
860
|
+
"tcp.packet",
|
|
861
|
+
"tcp.queryAnswer",
|
|
862
|
+
"tcp.queryError",
|
|
863
|
+
"tcp.query",
|
|
864
|
+
"tcp.connected",
|
|
865
|
+
"tcp.connect"
|
|
866
|
+
],
|
|
867
|
+
"client.ProxyConnectionAuth": [
|
|
868
|
+
"client.proxyConnectionAuthShort",
|
|
869
|
+
"client.proxyConnectionAuthLong"
|
|
870
|
+
],
|
|
871
|
+
"proxy.SignedPayment": ["proxy.signedPayment", "proxy.signedPaymentEmpty"],
|
|
872
|
+
"client.AuthorizationWithProxy": [
|
|
873
|
+
"client.authorizationWithProxySuccess",
|
|
874
|
+
"client.authorizationWithProxyFailed"
|
|
875
|
+
],
|
|
876
|
+
"client.QueryAnswerEx": [
|
|
877
|
+
"client.queryAnswerEx",
|
|
878
|
+
"client.queryAnswerErrorEx",
|
|
879
|
+
"client.queryAnswerPartEx"
|
|
880
|
+
],
|
|
881
|
+
"client.Refund": ["client.refund", "client.refundRejected"]
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/core/tl/serializer.ts
|
|
885
|
+
var VECTOR_ID = 481674261;
|
|
886
|
+
var BOOL_TRUE_ID = 2574415285;
|
|
887
|
+
var BOOL_FALSE_ID = 3162085175;
|
|
888
|
+
var TLSerializer = class {
|
|
889
|
+
buffers = [];
|
|
890
|
+
totalLength = 0;
|
|
891
|
+
writeInt(value) {
|
|
892
|
+
const buf = Buffer.alloc(4);
|
|
893
|
+
buf.writeInt32LE(value, 0);
|
|
894
|
+
this.push(buf);
|
|
895
|
+
}
|
|
896
|
+
writeUInt(value) {
|
|
897
|
+
const buf = Buffer.alloc(4);
|
|
898
|
+
buf.writeUInt32LE(value, 0);
|
|
899
|
+
this.push(buf);
|
|
900
|
+
}
|
|
901
|
+
writeLong(value) {
|
|
902
|
+
const buf = Buffer.alloc(8);
|
|
903
|
+
buf.writeBigInt64LE(value, 0);
|
|
904
|
+
this.push(buf);
|
|
905
|
+
}
|
|
906
|
+
writeDouble(value) {
|
|
907
|
+
const buf = Buffer.alloc(8);
|
|
908
|
+
buf.writeDoubleLE(value, 0);
|
|
909
|
+
this.push(buf);
|
|
910
|
+
}
|
|
911
|
+
writeInt128(value) {
|
|
912
|
+
if (value.length !== 16) throw new Error(`int128 must be 16 bytes, got ${value.length}`);
|
|
913
|
+
this.push(value);
|
|
914
|
+
}
|
|
915
|
+
writeInt256(value) {
|
|
916
|
+
if (value.length !== 32) throw new Error(`int256 must be 32 bytes, got ${value.length}`);
|
|
917
|
+
this.push(value);
|
|
918
|
+
}
|
|
919
|
+
writeBytes(value) {
|
|
920
|
+
let headerLen;
|
|
921
|
+
if (value.length < 254) {
|
|
922
|
+
const header = Buffer.alloc(1);
|
|
923
|
+
header[0] = value.length;
|
|
924
|
+
this.push(header);
|
|
925
|
+
headerLen = 1;
|
|
926
|
+
} else {
|
|
927
|
+
const header = Buffer.alloc(4);
|
|
928
|
+
header[0] = 254;
|
|
929
|
+
header[1] = value.length & 255;
|
|
930
|
+
header[2] = value.length >> 8 & 255;
|
|
931
|
+
header[3] = value.length >> 16 & 255;
|
|
932
|
+
this.push(header);
|
|
933
|
+
headerLen = 4;
|
|
934
|
+
}
|
|
935
|
+
this.push(value);
|
|
936
|
+
const totalLen = headerLen + value.length;
|
|
937
|
+
const padding = (4 - totalLen % 4) % 4;
|
|
938
|
+
if (padding > 0) {
|
|
939
|
+
this.push(Buffer.alloc(padding));
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
writeString(value) {
|
|
943
|
+
this.writeBytes(Buffer.from(value, "utf-8"));
|
|
944
|
+
}
|
|
945
|
+
writeBool(value) {
|
|
946
|
+
this.writeUInt(value ? BOOL_TRUE_ID : BOOL_FALSE_ID);
|
|
947
|
+
}
|
|
948
|
+
writeVector(items, itemType, bare = false) {
|
|
949
|
+
if (!bare) {
|
|
950
|
+
this.writeUInt(VECTOR_ID);
|
|
951
|
+
}
|
|
952
|
+
this.writeInt(items.length);
|
|
953
|
+
for (const item of items) {
|
|
954
|
+
this.writeField(item, itemType);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
writeConstructorId(id) {
|
|
958
|
+
this.writeUInt(id);
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Serialize a TL object by its _type, writing constructor ID + fields.
|
|
962
|
+
* boxed=true writes the constructor ID prefix.
|
|
963
|
+
*/
|
|
964
|
+
writeObject(obj, boxed = true) {
|
|
965
|
+
const typeName = obj["_type"];
|
|
966
|
+
if (!typeName) throw new Error("TL object must have _type field");
|
|
967
|
+
const schema = TL_SCHEMA[typeName];
|
|
968
|
+
if (!schema) throw new Error(`Unknown TL type: ${typeName}`);
|
|
969
|
+
if (boxed) {
|
|
970
|
+
this.writeConstructorId(schema.id);
|
|
971
|
+
}
|
|
972
|
+
this.writeFields(obj, schema);
|
|
973
|
+
}
|
|
974
|
+
writeFields(obj, schema) {
|
|
975
|
+
const flagValues = {};
|
|
976
|
+
for (const field of schema.fields) {
|
|
977
|
+
if (field.type === "int" && field.name.toLowerCase().includes("flag")) {
|
|
978
|
+
const isFlags = schema.fields.some((f) => f.flag?.field === field.name);
|
|
979
|
+
if (isFlags) {
|
|
980
|
+
let flags = 0;
|
|
981
|
+
for (const f of schema.fields) {
|
|
982
|
+
if (f.flag?.field === field.name && obj[f.name] !== void 0 && obj[f.name] !== null) {
|
|
983
|
+
flags |= 1 << f.flag.bit;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
flagValues[field.name] = flags;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
for (const field of schema.fields) {
|
|
991
|
+
if (field.name in flagValues) {
|
|
992
|
+
this.writeInt(flagValues[field.name]);
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (field.flag) {
|
|
996
|
+
const flagVal = flagValues[field.flag.field] ?? obj[field.flag.field] ?? 0;
|
|
997
|
+
if (!(flagVal & 1 << field.flag.bit)) {
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
const value = obj[field.name];
|
|
1002
|
+
this.writeField(value, field.type);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
writeField(value, type) {
|
|
1006
|
+
if (typeof type === "string") {
|
|
1007
|
+
switch (type) {
|
|
1008
|
+
case "int":
|
|
1009
|
+
this.writeInt(value);
|
|
1010
|
+
break;
|
|
1011
|
+
case "long":
|
|
1012
|
+
this.writeLong(value);
|
|
1013
|
+
break;
|
|
1014
|
+
case "double":
|
|
1015
|
+
this.writeDouble(value);
|
|
1016
|
+
break;
|
|
1017
|
+
case "int128":
|
|
1018
|
+
this.writeInt128(value);
|
|
1019
|
+
break;
|
|
1020
|
+
case "int256":
|
|
1021
|
+
this.writeInt256(value);
|
|
1022
|
+
break;
|
|
1023
|
+
case "string":
|
|
1024
|
+
this.writeString(value);
|
|
1025
|
+
break;
|
|
1026
|
+
case "bytes":
|
|
1027
|
+
this.writeBytes(value);
|
|
1028
|
+
break;
|
|
1029
|
+
case "Bool":
|
|
1030
|
+
this.writeBool(value);
|
|
1031
|
+
break;
|
|
1032
|
+
case "true":
|
|
1033
|
+
break;
|
|
1034
|
+
default:
|
|
1035
|
+
throw new Error(`Unknown primitive type: ${type}`);
|
|
1036
|
+
}
|
|
1037
|
+
} else if ("vector" in type) {
|
|
1038
|
+
this.writeVector(value, type.vector, Boolean(type.bare));
|
|
1039
|
+
} else if ("ref" in type) {
|
|
1040
|
+
const isPolymorphicRef = type.ref in POLYMORPHIC_TYPES;
|
|
1041
|
+
if (isPolymorphicRef) {
|
|
1042
|
+
this.writeObject(value, true);
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (!(type.ref in TL_SCHEMA)) {
|
|
1046
|
+
throw new Error(`Unknown TL ref type: ${type.ref}`);
|
|
1047
|
+
}
|
|
1048
|
+
const obj = value;
|
|
1049
|
+
const nestedType = obj["_type"];
|
|
1050
|
+
if (nestedType && nestedType !== type.ref) {
|
|
1051
|
+
throw new Error(`Expected nested type ${type.ref}, got ${nestedType}`);
|
|
1052
|
+
}
|
|
1053
|
+
this.writeObject(nestedType ? obj : { ...obj, _type: type.ref }, false);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
push(buf) {
|
|
1057
|
+
this.buffers.push(buf);
|
|
1058
|
+
this.totalLength += buf.length;
|
|
1059
|
+
}
|
|
1060
|
+
toBuffer() {
|
|
1061
|
+
return Buffer.concat(this.buffers, this.totalLength);
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
function serializeTLObject(obj, boxed = true) {
|
|
1065
|
+
const s = new TLSerializer();
|
|
1066
|
+
s.writeObject(obj, boxed);
|
|
1067
|
+
return s.toBuffer();
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/core/tl/deserializer.ts
|
|
1071
|
+
var VECTOR_ID2 = 481674261;
|
|
1072
|
+
var BOOL_TRUE_ID2 = 2574415285;
|
|
1073
|
+
var BOOL_FALSE_ID2 = 3162085175;
|
|
1074
|
+
var TLDeserializer = class {
|
|
1075
|
+
buffer;
|
|
1076
|
+
offset;
|
|
1077
|
+
constructor(buffer) {
|
|
1078
|
+
this.buffer = buffer;
|
|
1079
|
+
this.offset = 0;
|
|
1080
|
+
}
|
|
1081
|
+
get remaining() {
|
|
1082
|
+
return this.buffer.length - this.offset;
|
|
1083
|
+
}
|
|
1084
|
+
readInt() {
|
|
1085
|
+
this.checkRemaining(4);
|
|
1086
|
+
const value = this.buffer.readInt32LE(this.offset);
|
|
1087
|
+
this.offset += 4;
|
|
1088
|
+
return value;
|
|
1089
|
+
}
|
|
1090
|
+
readUInt() {
|
|
1091
|
+
this.checkRemaining(4);
|
|
1092
|
+
const value = this.buffer.readUInt32LE(this.offset);
|
|
1093
|
+
this.offset += 4;
|
|
1094
|
+
return value;
|
|
1095
|
+
}
|
|
1096
|
+
readLong() {
|
|
1097
|
+
this.checkRemaining(8);
|
|
1098
|
+
const value = this.buffer.readBigInt64LE(this.offset);
|
|
1099
|
+
this.offset += 8;
|
|
1100
|
+
return value;
|
|
1101
|
+
}
|
|
1102
|
+
readDouble() {
|
|
1103
|
+
this.checkRemaining(8);
|
|
1104
|
+
const value = this.buffer.readDoubleLE(this.offset);
|
|
1105
|
+
this.offset += 8;
|
|
1106
|
+
return value;
|
|
1107
|
+
}
|
|
1108
|
+
readInt128() {
|
|
1109
|
+
this.checkRemaining(16);
|
|
1110
|
+
const value = Buffer.alloc(16);
|
|
1111
|
+
this.buffer.copy(value, 0, this.offset, this.offset + 16);
|
|
1112
|
+
this.offset += 16;
|
|
1113
|
+
return value;
|
|
1114
|
+
}
|
|
1115
|
+
readInt256() {
|
|
1116
|
+
this.checkRemaining(32);
|
|
1117
|
+
const value = Buffer.alloc(32);
|
|
1118
|
+
this.buffer.copy(value, 0, this.offset, this.offset + 32);
|
|
1119
|
+
this.offset += 32;
|
|
1120
|
+
return value;
|
|
1121
|
+
}
|
|
1122
|
+
readBytes() {
|
|
1123
|
+
this.checkRemaining(1);
|
|
1124
|
+
let length;
|
|
1125
|
+
let headerLen;
|
|
1126
|
+
const firstByte = this.buffer[this.offset];
|
|
1127
|
+
if (firstByte < 254) {
|
|
1128
|
+
length = firstByte;
|
|
1129
|
+
headerLen = 1;
|
|
1130
|
+
this.offset += 1;
|
|
1131
|
+
} else {
|
|
1132
|
+
this.checkRemaining(4);
|
|
1133
|
+
length = this.buffer[this.offset + 1] | this.buffer[this.offset + 2] << 8 | this.buffer[this.offset + 3] << 16;
|
|
1134
|
+
headerLen = 4;
|
|
1135
|
+
this.offset += 4;
|
|
1136
|
+
}
|
|
1137
|
+
this.checkRemaining(length);
|
|
1138
|
+
const value = Buffer.alloc(length);
|
|
1139
|
+
this.buffer.copy(value, 0, this.offset, this.offset + length);
|
|
1140
|
+
this.offset += length;
|
|
1141
|
+
const totalLen = headerLen + length;
|
|
1142
|
+
const padding = (4 - totalLen % 4) % 4;
|
|
1143
|
+
this.offset += padding;
|
|
1144
|
+
return value;
|
|
1145
|
+
}
|
|
1146
|
+
readString() {
|
|
1147
|
+
return this.readBytes().toString("utf-8");
|
|
1148
|
+
}
|
|
1149
|
+
readBool() {
|
|
1150
|
+
const id = this.readUInt();
|
|
1151
|
+
if (id === BOOL_TRUE_ID2) return true;
|
|
1152
|
+
if (id === BOOL_FALSE_ID2) return false;
|
|
1153
|
+
throw new Error(`Invalid Bool constructor ID: 0x${id.toString(16)}`);
|
|
1154
|
+
}
|
|
1155
|
+
readVector(itemType, bare = false) {
|
|
1156
|
+
if (!bare) {
|
|
1157
|
+
const id = this.readUInt();
|
|
1158
|
+
if (id !== VECTOR_ID2) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
`Expected vector constructor ID 0x${VECTOR_ID2.toString(16)}, got 0x${id.toString(16)}`
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
const count = this.readInt();
|
|
1165
|
+
const items = [];
|
|
1166
|
+
for (let i = 0; i < count; i++) {
|
|
1167
|
+
items.push(this.readField(itemType));
|
|
1168
|
+
}
|
|
1169
|
+
return items;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Read a boxed TL object: reads constructor ID, looks up schema, reads fields.
|
|
1173
|
+
*/
|
|
1174
|
+
readObject() {
|
|
1175
|
+
const constructorId = this.readUInt();
|
|
1176
|
+
const typeName = CONSTRUCTOR_ID_MAP.get(constructorId);
|
|
1177
|
+
if (!typeName) {
|
|
1178
|
+
throw new Error(
|
|
1179
|
+
`Unknown TL constructor ID: 0x${constructorId.toString(16).padStart(8, "0")}`
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
const schema = TL_SCHEMA[typeName];
|
|
1183
|
+
return this.readFields(typeName, schema);
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Read fields of a known TL type (without reading constructor ID).
|
|
1187
|
+
*/
|
|
1188
|
+
readObjectBare(typeName) {
|
|
1189
|
+
const schema = TL_SCHEMA[typeName];
|
|
1190
|
+
if (!schema) throw new Error(`Unknown TL type: ${typeName}`);
|
|
1191
|
+
return this.readFields(typeName, schema);
|
|
1192
|
+
}
|
|
1193
|
+
readFields(typeName, schema) {
|
|
1194
|
+
const result = { _type: typeName };
|
|
1195
|
+
const flagValues = {};
|
|
1196
|
+
for (const field of schema.fields) {
|
|
1197
|
+
if (field.flag) {
|
|
1198
|
+
const flagVal = flagValues[field.flag.field] ?? 0;
|
|
1199
|
+
if (!(flagVal & 1 << field.flag.bit)) {
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
const value = this.readField(field.type);
|
|
1204
|
+
result[field.name] = value;
|
|
1205
|
+
if (field.type === "int" && schema.fields.some((f) => f.flag?.field === field.name)) {
|
|
1206
|
+
flagValues[field.name] = value;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return result;
|
|
1210
|
+
}
|
|
1211
|
+
readField(type) {
|
|
1212
|
+
if (typeof type === "string") {
|
|
1213
|
+
switch (type) {
|
|
1214
|
+
case "int":
|
|
1215
|
+
return this.readInt();
|
|
1216
|
+
case "long":
|
|
1217
|
+
return this.readLong();
|
|
1218
|
+
case "double":
|
|
1219
|
+
return this.readDouble();
|
|
1220
|
+
case "int128":
|
|
1221
|
+
return this.readInt128();
|
|
1222
|
+
case "int256":
|
|
1223
|
+
return this.readInt256();
|
|
1224
|
+
case "string":
|
|
1225
|
+
return this.readString();
|
|
1226
|
+
case "bytes":
|
|
1227
|
+
return this.readBytes();
|
|
1228
|
+
case "Bool":
|
|
1229
|
+
return this.readBool();
|
|
1230
|
+
case "true":
|
|
1231
|
+
return true;
|
|
1232
|
+
// Bare true is present by virtue of the flag being set
|
|
1233
|
+
default:
|
|
1234
|
+
throw new Error(`Unknown primitive type: ${type}`);
|
|
1235
|
+
}
|
|
1236
|
+
} else if ("vector" in type) {
|
|
1237
|
+
return this.readVector(type.vector, Boolean(type.bare));
|
|
1238
|
+
} else if ("ref" in type) {
|
|
1239
|
+
if (type.ref in POLYMORPHIC_TYPES) {
|
|
1240
|
+
return this.readObject();
|
|
1241
|
+
}
|
|
1242
|
+
if (type.ref in TL_SCHEMA) {
|
|
1243
|
+
return this.readObjectBare(type.ref);
|
|
1244
|
+
}
|
|
1245
|
+
throw new Error(`Unknown TL ref type: ${type.ref}`);
|
|
1246
|
+
}
|
|
1247
|
+
throw new Error(`Unhandled field type: ${JSON.stringify(type)}`);
|
|
1248
|
+
}
|
|
1249
|
+
checkRemaining(needed) {
|
|
1250
|
+
if (this.offset + needed > this.buffer.length) {
|
|
1251
|
+
throw new Error(
|
|
1252
|
+
`Buffer underflow: need ${needed} bytes at offset ${this.offset}, but only ${this.buffer.length - this.offset} remain`
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
function deserializeTLObject(buffer) {
|
|
1258
|
+
const d = new TLDeserializer(buffer);
|
|
1259
|
+
return d.readObject();
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/core/protocol/handshake.ts
|
|
1263
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
1264
|
+
async function performHandshake(conn, ownerAddress, secretString, configVersion, onLongAuthRequired) {
|
|
1265
|
+
const tcpId = import_node_crypto2.default.randomBytes(8).readBigInt64LE();
|
|
1266
|
+
const tcpConnect = { _type: "tcp.connect", id: tcpId };
|
|
1267
|
+
conn.send(serializeTLObject(tcpConnect));
|
|
1268
|
+
const tcpResponse = await waitForFrame(conn, 3e4);
|
|
1269
|
+
const tcpConnected = deserializeTLObject(tcpResponse);
|
|
1270
|
+
if (tcpConnected._type !== "tcp.connected") {
|
|
1271
|
+
throw new ProtocolError(`Expected tcp.connected, got ${tcpConnected._type}`);
|
|
1272
|
+
}
|
|
1273
|
+
const clientParams = {
|
|
1274
|
+
_type: "client.params",
|
|
1275
|
+
flags: 3,
|
|
1276
|
+
// bit 0 (isTest) + bit 1 (proto versions)
|
|
1277
|
+
clientOwnerAddress: ownerAddress,
|
|
1278
|
+
isTest: false,
|
|
1279
|
+
minProtoVersion: 0,
|
|
1280
|
+
maxProtoVersion: 1
|
|
1281
|
+
};
|
|
1282
|
+
const connectReq = {
|
|
1283
|
+
_type: "client.connectToProxy",
|
|
1284
|
+
params: clientParams,
|
|
1285
|
+
minConfigVersion: configVersion
|
|
1286
|
+
};
|
|
1287
|
+
const queryId = import_node_crypto2.default.randomBytes(8).readBigInt64LE();
|
|
1288
|
+
sendQuery(conn, queryId, serializeTLObject(connectReq));
|
|
1289
|
+
const connectResponseData = await waitForQueryAnswer(
|
|
1290
|
+
conn,
|
|
1291
|
+
queryId,
|
|
1292
|
+
3e4,
|
|
1293
|
+
"connectToProxy response"
|
|
1294
|
+
);
|
|
1295
|
+
const connected = deserializeTLObject(connectResponseData);
|
|
1296
|
+
if (connected._type !== "client.connectedToProxy") {
|
|
1297
|
+
throw new ProtocolError(`Expected client.connectedToProxy, got ${connected._type}`);
|
|
1298
|
+
}
|
|
1299
|
+
const protoVersion = connected.params.protoVersion ?? 0;
|
|
1300
|
+
const auth = connected.auth;
|
|
1301
|
+
let authResult;
|
|
1302
|
+
if (auth._type === "client.proxyConnectionAuthShort") {
|
|
1303
|
+
const ourSecretHash = Buffer.from(import_node_crypto2.default.createHash("sha256").update(secretString).digest());
|
|
1304
|
+
if (ourSecretHash.equals(auth.secretHash)) {
|
|
1305
|
+
const authReq = {
|
|
1306
|
+
_type: "client.authorizeWithProxyShort",
|
|
1307
|
+
data: Buffer.from(secretString, "utf-8")
|
|
1308
|
+
};
|
|
1309
|
+
const authQueryId = import_node_crypto2.default.randomBytes(8).readBigInt64LE();
|
|
1310
|
+
sendQuery(
|
|
1311
|
+
conn,
|
|
1312
|
+
authQueryId,
|
|
1313
|
+
serializeTLObject(authReq)
|
|
1314
|
+
);
|
|
1315
|
+
const authResponseData = await waitForQueryAnswer(
|
|
1316
|
+
conn,
|
|
1317
|
+
authQueryId,
|
|
1318
|
+
3e5,
|
|
1319
|
+
"short auth response"
|
|
1320
|
+
);
|
|
1321
|
+
authResult = deserializeTLObject(authResponseData);
|
|
1322
|
+
} else {
|
|
1323
|
+
authResult = await performLongAuth(
|
|
1324
|
+
conn,
|
|
1325
|
+
connected,
|
|
1326
|
+
auth.nonce,
|
|
1327
|
+
onLongAuthRequired,
|
|
1328
|
+
"Proxy requested long auth because provided SECRET does not match on-chain secret hash"
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
} else {
|
|
1332
|
+
authResult = await performLongAuth(
|
|
1333
|
+
conn,
|
|
1334
|
+
connected,
|
|
1335
|
+
auth.nonce,
|
|
1336
|
+
onLongAuthRequired,
|
|
1337
|
+
"Proxy requires long auth (wallet is not registered for this proxy or SECRET is unavailable)"
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
if (authResult._type === "client.authorizationWithProxyFailed") {
|
|
1341
|
+
throw new AuthenticationError(`Proxy auth failed: ${authResult.error}`, authResult.errorCode);
|
|
1342
|
+
}
|
|
1343
|
+
if (authResult._type !== "client.authorizationWithProxySuccess") {
|
|
1344
|
+
throw new ProtocolError(
|
|
1345
|
+
`Unexpected auth response type: ${authResult._type}`
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
return {
|
|
1349
|
+
proxyParams: connected.params,
|
|
1350
|
+
clientScAddress: connected.clientScAddress,
|
|
1351
|
+
signedPayment: authResult.signedPayment,
|
|
1352
|
+
tokensCommittedToDb: authResult.tokensCommittedToDb,
|
|
1353
|
+
maxTokens: authResult.maxTokens,
|
|
1354
|
+
protoVersion
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
function buildHandshakeCloseError(stage, error) {
|
|
1358
|
+
const suffix = " This usually means RA-TLS/mTLS client credentials were rejected by the proxy.";
|
|
1359
|
+
return new ConnectionError(
|
|
1360
|
+
`Connection closed while waiting for ${stage}.${suffix}`,
|
|
1361
|
+
error
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
async function performLongAuth(conn, connected, nonce, onLongAuthRequired, missingHandlerMessage) {
|
|
1365
|
+
if (!onLongAuthRequired) {
|
|
1366
|
+
throw new AuthenticationError(
|
|
1367
|
+
`${missingHandlerMessage}. Provide SECRET for short auth, or keep automatic long-auth registration enabled`
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
await onLongAuthRequired({
|
|
1371
|
+
nonce,
|
|
1372
|
+
clientScAddress: connected.clientScAddress,
|
|
1373
|
+
proxyParams: connected.params
|
|
1374
|
+
});
|
|
1375
|
+
const authQueryId = import_node_crypto2.default.randomBytes(8).readBigInt64LE();
|
|
1376
|
+
const authReq = { _type: "client.authorizeWithProxyLong" };
|
|
1377
|
+
sendQuery(conn, authQueryId, serializeTLObject(authReq));
|
|
1378
|
+
const authResponseData = await waitForQueryAnswer(
|
|
1379
|
+
conn,
|
|
1380
|
+
authQueryId,
|
|
1381
|
+
3e5,
|
|
1382
|
+
"long auth response"
|
|
1383
|
+
);
|
|
1384
|
+
return deserializeTLObject(authResponseData);
|
|
1385
|
+
}
|
|
1386
|
+
function sendQuery(conn, queryId, data) {
|
|
1387
|
+
const queryObj = {
|
|
1388
|
+
_type: "tcp.query",
|
|
1389
|
+
id: queryId,
|
|
1390
|
+
data
|
|
1391
|
+
};
|
|
1392
|
+
conn.send(serializeTLObject(queryObj));
|
|
1393
|
+
}
|
|
1394
|
+
function waitForFrame(conn, timeoutMs) {
|
|
1395
|
+
return new Promise((resolve, reject) => {
|
|
1396
|
+
const timer = setTimeout(() => cleanup(() => reject(new ConnectionError("Timeout waiting for frame"))), timeoutMs);
|
|
1397
|
+
const cleanup = (next) => {
|
|
1398
|
+
clearTimeout(timer);
|
|
1399
|
+
conn.removeListener("frame", onFrame);
|
|
1400
|
+
conn.removeListener("close", onClose);
|
|
1401
|
+
if (next) next();
|
|
1402
|
+
};
|
|
1403
|
+
const onFrame = (data) => {
|
|
1404
|
+
cleanup(() => resolve(data));
|
|
1405
|
+
};
|
|
1406
|
+
const onClose = (error) => {
|
|
1407
|
+
cleanup(() => reject(buildHandshakeCloseError("handshake frame", error)));
|
|
1408
|
+
};
|
|
1409
|
+
conn.once("frame", onFrame);
|
|
1410
|
+
conn.once("close", onClose);
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
function waitForQueryAnswer(conn, queryId, timeoutMs, stage = "query answer") {
|
|
1414
|
+
return new Promise((resolve, reject) => {
|
|
1415
|
+
const timer = setTimeout(
|
|
1416
|
+
() => cleanup(() => reject(new ConnectionError(`Timeout waiting for ${stage}`))),
|
|
1417
|
+
timeoutMs
|
|
1418
|
+
);
|
|
1419
|
+
const cleanup = (next) => {
|
|
1420
|
+
clearTimeout(timer);
|
|
1421
|
+
conn.removeListener("frame", onFrame);
|
|
1422
|
+
conn.removeListener("close", onClose);
|
|
1423
|
+
if (next) next();
|
|
1424
|
+
};
|
|
1425
|
+
const onClose = (error) => {
|
|
1426
|
+
cleanup(() => reject(buildHandshakeCloseError(stage, error)));
|
|
1427
|
+
};
|
|
1428
|
+
const onFrame = (data) => {
|
|
1429
|
+
let obj;
|
|
1430
|
+
try {
|
|
1431
|
+
obj = deserializeTLObject(data);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
cleanup(
|
|
1434
|
+
() => reject(new ProtocolError(`Failed to deserialize handshake frame: ${String(err)}`))
|
|
1435
|
+
);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (obj["_type"] === "tcp.queryAnswer") {
|
|
1439
|
+
const answerId = obj["id"];
|
|
1440
|
+
if (answerId === queryId) {
|
|
1441
|
+
cleanup(() => resolve(obj["data"]));
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
} else if (obj["_type"] === "tcp.queryError") {
|
|
1445
|
+
const errorId = obj["id"];
|
|
1446
|
+
if (errorId === queryId) {
|
|
1447
|
+
cleanup(
|
|
1448
|
+
() => reject(new ProtocolError(`Query error: ${obj["message"]}`, obj["code"]))
|
|
1449
|
+
);
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
conn.on("frame", onFrame);
|
|
1455
|
+
conn.once("close", onClose);
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// src/core/protocol/session.ts
|
|
1460
|
+
var CocoonSession = class extends import_node_events2.EventEmitter {
|
|
1461
|
+
conn = null;
|
|
1462
|
+
handshakeResult = null;
|
|
1463
|
+
pendingQueries = /* @__PURE__ */ new Map();
|
|
1464
|
+
keepaliveTimer = null;
|
|
1465
|
+
_connected = false;
|
|
1466
|
+
options;
|
|
1467
|
+
constructor(options) {
|
|
1468
|
+
super();
|
|
1469
|
+
this.options = options;
|
|
1470
|
+
}
|
|
1471
|
+
get connected() {
|
|
1472
|
+
return this._connected;
|
|
1473
|
+
}
|
|
1474
|
+
get protoVersion() {
|
|
1475
|
+
return this.handshakeResult?.protoVersion ?? 0;
|
|
1476
|
+
}
|
|
1477
|
+
async connect() {
|
|
1478
|
+
if (this._connected) return;
|
|
1479
|
+
this.conn = new CocoonConnection(this.options);
|
|
1480
|
+
await this.conn.connect();
|
|
1481
|
+
this.handshakeResult = await performHandshake(
|
|
1482
|
+
this.conn,
|
|
1483
|
+
this.options.ownerAddress,
|
|
1484
|
+
this.options.secretString,
|
|
1485
|
+
this.options.configVersion ?? 0,
|
|
1486
|
+
this.options.onLongAuthRequired
|
|
1487
|
+
);
|
|
1488
|
+
this._connected = true;
|
|
1489
|
+
this.conn.on("frame", (data) => this.handleFrame(data));
|
|
1490
|
+
this.conn.on("close", (error) => {
|
|
1491
|
+
this._connected = false;
|
|
1492
|
+
this.cleanup();
|
|
1493
|
+
this.emit("close", error);
|
|
1494
|
+
});
|
|
1495
|
+
this.startKeepalive();
|
|
1496
|
+
}
|
|
1497
|
+
/**
|
|
1498
|
+
* Send a query and wait for the complete answer.
|
|
1499
|
+
*/
|
|
1500
|
+
async sendQuery(modelName, httpRequest, options = {}) {
|
|
1501
|
+
if (!this.conn || !this._connected) {
|
|
1502
|
+
throw new ConnectionError("Not connected");
|
|
1503
|
+
}
|
|
1504
|
+
const requestId = import_node_crypto3.default.randomBytes(32);
|
|
1505
|
+
const timeout = options.timeout ?? this.options.timeout ?? 12e4;
|
|
1506
|
+
const queryPayload = serializeTLObject(httpRequest, true);
|
|
1507
|
+
const runQuery = {
|
|
1508
|
+
_type: "client.runQueryEx",
|
|
1509
|
+
modelName,
|
|
1510
|
+
query: queryPayload,
|
|
1511
|
+
maxCoefficient: options.maxCoefficient ?? 4e3,
|
|
1512
|
+
maxTokens: options.maxTokens ?? 1e3,
|
|
1513
|
+
timeout: timeout / 1e3 * 0.95,
|
|
1514
|
+
requestId,
|
|
1515
|
+
minConfigVersion: this.options.configVersion ?? 0,
|
|
1516
|
+
flags: options.enableDebug ? 1 : 0,
|
|
1517
|
+
enableDebug: options.enableDebug
|
|
1518
|
+
};
|
|
1519
|
+
const tlData = serializeTLObject(runQuery, true);
|
|
1520
|
+
const tcpPacket = {
|
|
1521
|
+
_type: "tcp.packet",
|
|
1522
|
+
data: tlData
|
|
1523
|
+
};
|
|
1524
|
+
this.conn.send(serializeTLObject(tcpPacket));
|
|
1525
|
+
return new Promise((resolve, reject) => {
|
|
1526
|
+
const requestIdHex = requestId.toString("hex");
|
|
1527
|
+
const timer = setTimeout(() => {
|
|
1528
|
+
this.pendingQueries.delete(requestIdHex);
|
|
1529
|
+
reject(new TimeoutError(`Query timed out after ${timeout}ms`));
|
|
1530
|
+
}, timeout);
|
|
1531
|
+
this.pendingQueries.set(requestIdHex, {
|
|
1532
|
+
resolve,
|
|
1533
|
+
reject,
|
|
1534
|
+
onPart: options.onPart,
|
|
1535
|
+
timer
|
|
1536
|
+
});
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Send a raw TL function (for getWorkerTypesV2, etc.)
|
|
1541
|
+
*/
|
|
1542
|
+
async sendRpcQuery(tlObject, timeoutMs = 3e4) {
|
|
1543
|
+
if (!this.conn || !this._connected) {
|
|
1544
|
+
throw new ConnectionError("Not connected");
|
|
1545
|
+
}
|
|
1546
|
+
const queryId = import_node_crypto3.default.randomBytes(8).readBigInt64LE();
|
|
1547
|
+
const data = serializeTLObject(tlObject, true);
|
|
1548
|
+
const tcpQuery = {
|
|
1549
|
+
_type: "tcp.query",
|
|
1550
|
+
id: queryId,
|
|
1551
|
+
data
|
|
1552
|
+
};
|
|
1553
|
+
this.conn.send(serializeTLObject(tcpQuery));
|
|
1554
|
+
return new Promise((resolve, reject) => {
|
|
1555
|
+
const timer = setTimeout(() => {
|
|
1556
|
+
this.removeListener(`queryAnswer:${queryId}`, onAnswer);
|
|
1557
|
+
reject(new TimeoutError(`RPC query timed out after ${timeoutMs}ms`));
|
|
1558
|
+
}, timeoutMs);
|
|
1559
|
+
const onAnswer = (result) => {
|
|
1560
|
+
clearTimeout(timer);
|
|
1561
|
+
if (result.error) {
|
|
1562
|
+
reject(new ProtocolError(result.error.message, result.error.code));
|
|
1563
|
+
} else if (result.data) {
|
|
1564
|
+
resolve(deserializeTLObject(result.data));
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
this.once(`queryAnswer:${queryId}`, onAnswer);
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
async disconnect() {
|
|
1571
|
+
this.cleanup();
|
|
1572
|
+
this.conn?.destroy();
|
|
1573
|
+
this.conn = null;
|
|
1574
|
+
this._connected = false;
|
|
1575
|
+
}
|
|
1576
|
+
handleFrame(data) {
|
|
1577
|
+
if (data.length === 0) {
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
let obj;
|
|
1581
|
+
try {
|
|
1582
|
+
obj = deserializeTLObject(data);
|
|
1583
|
+
} catch (e) {
|
|
1584
|
+
this.emit("error", new ProtocolError(`Failed to deserialize frame: ${e}`));
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
const type = obj["_type"];
|
|
1588
|
+
switch (type) {
|
|
1589
|
+
case "tcp.pong":
|
|
1590
|
+
break;
|
|
1591
|
+
case "tcp.ping": {
|
|
1592
|
+
if (this.conn) {
|
|
1593
|
+
const pong = { _type: "tcp.pong", id: obj["id"] };
|
|
1594
|
+
this.conn.send(serializeTLObject(pong));
|
|
1595
|
+
}
|
|
1596
|
+
break;
|
|
1597
|
+
}
|
|
1598
|
+
case "tcp.queryAnswer": {
|
|
1599
|
+
const queryId = obj["id"];
|
|
1600
|
+
this.emit(`queryAnswer:${queryId}`, { data: obj["data"] });
|
|
1601
|
+
break;
|
|
1602
|
+
}
|
|
1603
|
+
case "tcp.queryError": {
|
|
1604
|
+
const queryId = obj["id"];
|
|
1605
|
+
this.emit(`queryAnswer:${queryId}`, {
|
|
1606
|
+
error: { code: obj["code"], message: obj["message"] }
|
|
1607
|
+
});
|
|
1608
|
+
break;
|
|
1609
|
+
}
|
|
1610
|
+
case "tcp.packet": {
|
|
1611
|
+
const innerData = obj["data"];
|
|
1612
|
+
if (innerData.length === 0) break;
|
|
1613
|
+
let innerObj;
|
|
1614
|
+
try {
|
|
1615
|
+
innerObj = deserializeTLObject(innerData);
|
|
1616
|
+
} catch (e) {
|
|
1617
|
+
this.emit("error", new ProtocolError(`Failed to deserialize inner packet: ${e}`));
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
this.handleInnerPacket(innerObj);
|
|
1621
|
+
break;
|
|
1622
|
+
}
|
|
1623
|
+
default:
|
|
1624
|
+
this.emit("error", new ProtocolError(`Unexpected frame type: ${type}`));
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
handleInnerPacket(obj) {
|
|
1628
|
+
const type = obj["_type"];
|
|
1629
|
+
let normalized = obj;
|
|
1630
|
+
if (type === "client.queryAnswer") {
|
|
1631
|
+
normalized = {
|
|
1632
|
+
...obj,
|
|
1633
|
+
_type: "client.queryAnswerEx"
|
|
1634
|
+
};
|
|
1635
|
+
} else if (type === "client.queryAnswerPart") {
|
|
1636
|
+
normalized = {
|
|
1637
|
+
...obj,
|
|
1638
|
+
_type: "client.queryAnswerPartEx"
|
|
1639
|
+
};
|
|
1640
|
+
} else if (type === "client.queryAnswerError" || type === "client.queryAnswerPartError") {
|
|
1641
|
+
normalized = {
|
|
1642
|
+
...obj,
|
|
1643
|
+
_type: "client.queryAnswerErrorEx"
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
const normalizedType = normalized["_type"];
|
|
1647
|
+
if (normalizedType === "client.queryAnswerEx" || normalizedType === "client.queryAnswerErrorEx" || normalizedType === "client.queryAnswerPartEx") {
|
|
1648
|
+
const requestId = normalized["requestId"].toString("hex");
|
|
1649
|
+
const pending = this.pendingQueries.get(requestId);
|
|
1650
|
+
if (!pending) {
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
const answer = normalized;
|
|
1654
|
+
if (normalizedType === "client.queryAnswerErrorEx") {
|
|
1655
|
+
clearTimeout(pending.timer);
|
|
1656
|
+
this.pendingQueries.delete(requestId);
|
|
1657
|
+
pending.resolve(answer);
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
pending.onPart?.(answer);
|
|
1661
|
+
if (this.isTerminalQueryAnswer(answer)) {
|
|
1662
|
+
clearTimeout(pending.timer);
|
|
1663
|
+
this.pendingQueries.delete(requestId);
|
|
1664
|
+
pending.resolve(answer);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
isTerminalQueryAnswer(answer) {
|
|
1669
|
+
if (answer._type === "client.queryAnswerErrorEx") {
|
|
1670
|
+
return true;
|
|
1671
|
+
}
|
|
1672
|
+
const legacyIsCompleted = answer.isCompleted;
|
|
1673
|
+
if (typeof legacyIsCompleted === "boolean") {
|
|
1674
|
+
return legacyIsCompleted;
|
|
1675
|
+
}
|
|
1676
|
+
if ("finalInfo" in answer && answer.finalInfo) {
|
|
1677
|
+
return true;
|
|
1678
|
+
}
|
|
1679
|
+
if ("flags" in answer && typeof answer.flags === "number" && (answer.flags & 1) !== 0) {
|
|
1680
|
+
return true;
|
|
1681
|
+
}
|
|
1682
|
+
if ("answer" in answer && answer.answer) {
|
|
1683
|
+
try {
|
|
1684
|
+
const envelope = deserializeTLObject(answer.answer);
|
|
1685
|
+
if (envelope._type === "http.response") {
|
|
1686
|
+
const transferEncoding = envelope.headers?.find(
|
|
1687
|
+
(h) => h.name.toLowerCase() === "transfer-encoding"
|
|
1688
|
+
)?.value;
|
|
1689
|
+
if (transferEncoding && transferEncoding.toLowerCase().includes("chunked")) {
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
return true;
|
|
1693
|
+
}
|
|
1694
|
+
} catch {
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
if (answer._type === "client.queryAnswerPartEx") {
|
|
1698
|
+
return false;
|
|
1699
|
+
}
|
|
1700
|
+
return true;
|
|
1701
|
+
}
|
|
1702
|
+
startKeepalive() {
|
|
1703
|
+
this.keepaliveTimer = setInterval(() => {
|
|
1704
|
+
if (this.conn?.isConnected) {
|
|
1705
|
+
const pingId = import_node_crypto3.default.randomBytes(8).readBigInt64LE();
|
|
1706
|
+
const ping = { _type: "tcp.ping", id: pingId };
|
|
1707
|
+
try {
|
|
1708
|
+
this.conn.send(serializeTLObject(ping));
|
|
1709
|
+
} catch {
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}, 1e4);
|
|
1713
|
+
}
|
|
1714
|
+
cleanup() {
|
|
1715
|
+
if (this.keepaliveTimer) {
|
|
1716
|
+
clearInterval(this.keepaliveTimer);
|
|
1717
|
+
this.keepaliveTimer = null;
|
|
1718
|
+
}
|
|
1719
|
+
for (const [, pending] of this.pendingQueries) {
|
|
1720
|
+
clearTimeout(pending.timer);
|
|
1721
|
+
pending.reject(new ConnectionError("Connection closed"));
|
|
1722
|
+
}
|
|
1723
|
+
this.pendingQueries.clear();
|
|
1724
|
+
}
|
|
1725
|
+
};
|
|
1726
|
+
function buildHttpRequest(method, url, body, extraHeaders = []) {
|
|
1727
|
+
const hasHeader = (name) => extraHeaders.some((h) => h.name.toLowerCase() === name.toLowerCase());
|
|
1728
|
+
const headers = [...extraHeaders];
|
|
1729
|
+
if (!hasHeader("Content-Type")) {
|
|
1730
|
+
headers.unshift({ _type: "http.header", name: "Content-Type", value: "application/json" });
|
|
1731
|
+
}
|
|
1732
|
+
if (!hasHeader("Content-Length")) {
|
|
1733
|
+
headers.push({ _type: "http.header", name: "Content-Length", value: body.length.toString() });
|
|
1734
|
+
}
|
|
1735
|
+
if (!hasHeader("Host")) {
|
|
1736
|
+
headers.push({ _type: "http.header", name: "Host", value: "api.openai.com" });
|
|
1737
|
+
}
|
|
1738
|
+
return {
|
|
1739
|
+
_type: "http.request",
|
|
1740
|
+
method,
|
|
1741
|
+
url,
|
|
1742
|
+
httpVersion: "HTTP/1.1",
|
|
1743
|
+
headers,
|
|
1744
|
+
payload: body
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// src/core/streaming.ts
|
|
1749
|
+
var Stream = class {
|
|
1750
|
+
controller = null;
|
|
1751
|
+
stream;
|
|
1752
|
+
_done = false;
|
|
1753
|
+
constructor() {
|
|
1754
|
+
this.stream = new ReadableStream({
|
|
1755
|
+
start: (controller) => {
|
|
1756
|
+
this.controller = controller;
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* Push a chunk into the stream.
|
|
1762
|
+
*/
|
|
1763
|
+
push(chunk) {
|
|
1764
|
+
if (this._done) return;
|
|
1765
|
+
this.controller?.enqueue(chunk);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Signal that the stream is complete.
|
|
1769
|
+
*/
|
|
1770
|
+
end() {
|
|
1771
|
+
if (this._done) return;
|
|
1772
|
+
this._done = true;
|
|
1773
|
+
this.controller?.close();
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Signal an error on the stream.
|
|
1777
|
+
*/
|
|
1778
|
+
error(err) {
|
|
1779
|
+
if (this._done) return;
|
|
1780
|
+
this._done = true;
|
|
1781
|
+
this.controller?.error(err);
|
|
1782
|
+
}
|
|
1783
|
+
get done() {
|
|
1784
|
+
return this._done;
|
|
1785
|
+
}
|
|
1786
|
+
async *[Symbol.asyncIterator]() {
|
|
1787
|
+
const reader = this.stream.getReader();
|
|
1788
|
+
try {
|
|
1789
|
+
while (true) {
|
|
1790
|
+
const { done, value } = await reader.read();
|
|
1791
|
+
if (done) break;
|
|
1792
|
+
yield value;
|
|
1793
|
+
}
|
|
1794
|
+
} finally {
|
|
1795
|
+
reader.releaseLock();
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
// src/resources/chat/completions.ts
|
|
1801
|
+
var Completions = class {
|
|
1802
|
+
constructor(getSession) {
|
|
1803
|
+
this.getSession = getSession;
|
|
1804
|
+
}
|
|
1805
|
+
extractHttpData(answer) {
|
|
1806
|
+
try {
|
|
1807
|
+
const httpResponse = deserializeTLObject(answer);
|
|
1808
|
+
if (httpResponse._type === "http.response") {
|
|
1809
|
+
return {
|
|
1810
|
+
payload: httpResponse.payload,
|
|
1811
|
+
statusCode: httpResponse.statusCode,
|
|
1812
|
+
reason: httpResponse.reason
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
} catch {
|
|
1816
|
+
}
|
|
1817
|
+
return { payload: answer };
|
|
1818
|
+
}
|
|
1819
|
+
parseErrorPayload(payload, fallbackMessage) {
|
|
1820
|
+
if (payload.length === 0) {
|
|
1821
|
+
return { message: fallbackMessage, body: { error: fallbackMessage } };
|
|
1822
|
+
}
|
|
1823
|
+
const text = payload.toString("utf-8");
|
|
1824
|
+
try {
|
|
1825
|
+
const parsed = JSON.parse(text);
|
|
1826
|
+
const message = typeof parsed.message === "string" ? parsed.message : typeof parsed.error === "string" ? parsed.error : fallbackMessage;
|
|
1827
|
+
return { message, body: parsed };
|
|
1828
|
+
} catch {
|
|
1829
|
+
return { message: text || fallbackMessage, body: { error: text || fallbackMessage } };
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
async create(params) {
|
|
1833
|
+
const session = await this.getSession();
|
|
1834
|
+
const body = JSON.stringify({
|
|
1835
|
+
model: params.model,
|
|
1836
|
+
messages: params.messages,
|
|
1837
|
+
stream: params.stream ?? false,
|
|
1838
|
+
...params.temperature !== void 0 && { temperature: params.temperature },
|
|
1839
|
+
...params.top_p !== void 0 && { top_p: params.top_p },
|
|
1840
|
+
...params.max_tokens !== void 0 && { max_tokens: params.max_tokens },
|
|
1841
|
+
...params.max_completion_tokens !== void 0 && {
|
|
1842
|
+
max_completion_tokens: params.max_completion_tokens
|
|
1843
|
+
},
|
|
1844
|
+
...params.stop !== void 0 && { stop: params.stop },
|
|
1845
|
+
...params.presence_penalty !== void 0 && { presence_penalty: params.presence_penalty },
|
|
1846
|
+
...params.frequency_penalty !== void 0 && {
|
|
1847
|
+
frequency_penalty: params.frequency_penalty
|
|
1848
|
+
}
|
|
1849
|
+
});
|
|
1850
|
+
const httpRequest = buildHttpRequest(
|
|
1851
|
+
"POST",
|
|
1852
|
+
"/v1/chat/completions",
|
|
1853
|
+
Buffer.from(body, "utf-8")
|
|
1854
|
+
);
|
|
1855
|
+
if (params.stream) {
|
|
1856
|
+
return this.createStreaming(session, params, httpRequest);
|
|
1857
|
+
}
|
|
1858
|
+
return this.createNonStreaming(session, params, httpRequest);
|
|
1859
|
+
}
|
|
1860
|
+
async createNonStreaming(session, params, httpRequest) {
|
|
1861
|
+
const chunks = [];
|
|
1862
|
+
let sawAnswer = false;
|
|
1863
|
+
let statusCode;
|
|
1864
|
+
let statusReason;
|
|
1865
|
+
const finalAnswer = await session.sendQuery(params.model, httpRequest, {
|
|
1866
|
+
maxCoefficient: params.max_coefficient,
|
|
1867
|
+
maxTokens: params.max_tokens ?? params.max_completion_tokens,
|
|
1868
|
+
timeout: params.timeout,
|
|
1869
|
+
onPart: (part) => {
|
|
1870
|
+
if (!("answer" in part) || !part.answer) {
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
sawAnswer = true;
|
|
1874
|
+
const extracted = this.extractHttpData(part.answer);
|
|
1875
|
+
if (extracted.statusCode !== void 0) {
|
|
1876
|
+
statusCode = extracted.statusCode;
|
|
1877
|
+
statusReason = extracted.reason;
|
|
1878
|
+
}
|
|
1879
|
+
if (extracted.payload.length > 0) {
|
|
1880
|
+
chunks.push(extracted.payload);
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
if (finalAnswer._type === "client.queryAnswerErrorEx") {
|
|
1885
|
+
throw new APIError(finalAnswer.error, 500, {
|
|
1886
|
+
error_code: finalAnswer.errorCode,
|
|
1887
|
+
error: finalAnswer.error
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
if (!sawAnswer && "answer" in finalAnswer && finalAnswer.answer) {
|
|
1891
|
+
const extracted = this.extractHttpData(finalAnswer.answer);
|
|
1892
|
+
if (extracted.statusCode !== void 0) {
|
|
1893
|
+
statusCode = extracted.statusCode;
|
|
1894
|
+
statusReason = extracted.reason;
|
|
1895
|
+
}
|
|
1896
|
+
if (extracted.payload.length > 0) {
|
|
1897
|
+
chunks.push(extracted.payload);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
const fullPayload = Buffer.concat(chunks);
|
|
1901
|
+
if (statusCode !== void 0 && statusCode >= 400) {
|
|
1902
|
+
const fallback = statusReason ? `${statusCode} ${statusReason}` : `HTTP ${statusCode}`;
|
|
1903
|
+
const parsed = this.parseErrorPayload(fullPayload, fallback);
|
|
1904
|
+
throw new APIError(parsed.message, statusCode, parsed.body);
|
|
1905
|
+
}
|
|
1906
|
+
if (fullPayload.length === 0) {
|
|
1907
|
+
throw new ProtocolError("Empty response from proxy");
|
|
1908
|
+
}
|
|
1909
|
+
try {
|
|
1910
|
+
return JSON.parse(fullPayload.toString("utf-8"));
|
|
1911
|
+
} catch (error) {
|
|
1912
|
+
throw new ProtocolError(
|
|
1913
|
+
`Failed to parse completion payload as JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
async createStreaming(session, params, httpRequest) {
|
|
1918
|
+
const stream = new Stream();
|
|
1919
|
+
let sseBuffer = "";
|
|
1920
|
+
let headersParsed = false;
|
|
1921
|
+
let statusCode;
|
|
1922
|
+
let statusReason;
|
|
1923
|
+
const errorChunks = [];
|
|
1924
|
+
session.sendQuery(params.model, httpRequest, {
|
|
1925
|
+
maxCoefficient: params.max_coefficient,
|
|
1926
|
+
maxTokens: params.max_tokens ?? params.max_completion_tokens,
|
|
1927
|
+
timeout: params.timeout,
|
|
1928
|
+
onPart: (part) => {
|
|
1929
|
+
try {
|
|
1930
|
+
let rawData;
|
|
1931
|
+
if ("answer" in part && part.answer) {
|
|
1932
|
+
const answer = part.answer;
|
|
1933
|
+
if (!headersParsed) {
|
|
1934
|
+
try {
|
|
1935
|
+
const httpResponse = deserializeTLObject(answer);
|
|
1936
|
+
if (httpResponse._type === "http.response") {
|
|
1937
|
+
headersParsed = true;
|
|
1938
|
+
statusCode = httpResponse.statusCode;
|
|
1939
|
+
statusReason = httpResponse.reason;
|
|
1940
|
+
rawData = httpResponse.payload;
|
|
1941
|
+
} else {
|
|
1942
|
+
rawData = answer;
|
|
1943
|
+
}
|
|
1944
|
+
} catch {
|
|
1945
|
+
rawData = answer;
|
|
1946
|
+
headersParsed = true;
|
|
1947
|
+
}
|
|
1948
|
+
} else {
|
|
1949
|
+
rawData = answer;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (rawData && rawData.length > 0) {
|
|
1953
|
+
if (statusCode !== void 0 && statusCode >= 400) {
|
|
1954
|
+
errorChunks.push(rawData);
|
|
1955
|
+
return;
|
|
1956
|
+
}
|
|
1957
|
+
sseBuffer += rawData.toString("utf-8");
|
|
1958
|
+
this.processSSEBuffer(sseBuffer, stream);
|
|
1959
|
+
const lastNewline = sseBuffer.lastIndexOf("\n");
|
|
1960
|
+
if (lastNewline >= 0) {
|
|
1961
|
+
sseBuffer = sseBuffer.substring(lastNewline + 1);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
} catch (e) {
|
|
1965
|
+
stream.error(e instanceof Error ? e : new Error(String(e)));
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}).then(() => {
|
|
1969
|
+
if (statusCode !== void 0 && statusCode >= 400) {
|
|
1970
|
+
const parsed = this.parseErrorPayload(
|
|
1971
|
+
Buffer.concat(errorChunks),
|
|
1972
|
+
statusReason ? `${statusCode} ${statusReason}` : `HTTP ${statusCode}`
|
|
1973
|
+
);
|
|
1974
|
+
stream.error(new APIError(parsed.message, statusCode, parsed.body));
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
if (sseBuffer.trim().length > 0) {
|
|
1978
|
+
this.processSSEBuffer(sseBuffer + "\n", stream);
|
|
1979
|
+
}
|
|
1980
|
+
stream.end();
|
|
1981
|
+
}).catch((err) => {
|
|
1982
|
+
stream.error(err instanceof Error ? err : new Error(String(err)));
|
|
1983
|
+
});
|
|
1984
|
+
return stream;
|
|
1985
|
+
}
|
|
1986
|
+
processSSEBuffer(buffer, stream) {
|
|
1987
|
+
const lines = buffer.split("\n");
|
|
1988
|
+
for (const line of lines) {
|
|
1989
|
+
const trimmed = line.trim();
|
|
1990
|
+
if (trimmed === "") continue;
|
|
1991
|
+
if (trimmed === "data: [DONE]") continue;
|
|
1992
|
+
if (trimmed.startsWith("data: ")) {
|
|
1993
|
+
const jsonStr = trimmed.substring(6);
|
|
1994
|
+
try {
|
|
1995
|
+
const chunk = JSON.parse(jsonStr);
|
|
1996
|
+
stream.push(chunk);
|
|
1997
|
+
} catch {
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
// src/resources/models/models.ts
|
|
2005
|
+
var Models = class {
|
|
2006
|
+
constructor(getSession) {
|
|
2007
|
+
this.getSession = getSession;
|
|
2008
|
+
}
|
|
2009
|
+
/**
|
|
2010
|
+
* List all available models on the network.
|
|
2011
|
+
*/
|
|
2012
|
+
async list() {
|
|
2013
|
+
const session = await this.getSession();
|
|
2014
|
+
const result = await session.sendRpcQuery({
|
|
2015
|
+
_type: "client.getWorkerTypesV2"
|
|
2016
|
+
});
|
|
2017
|
+
const workerTypes = result;
|
|
2018
|
+
const models = workerTypes.types.map((wt) => {
|
|
2019
|
+
const totalWorkers = wt.workers.length;
|
|
2020
|
+
const coefficients = wt.workers.map((w) => w.coefficient);
|
|
2021
|
+
const minCoeff = coefficients.length > 0 ? Math.min(...coefficients) : 0;
|
|
2022
|
+
const maxCoeff = coefficients.length > 0 ? Math.max(...coefficients) : 0;
|
|
2023
|
+
return {
|
|
2024
|
+
id: wt.name,
|
|
2025
|
+
object: "model",
|
|
2026
|
+
created: Math.floor(Date.now() / 1e3),
|
|
2027
|
+
owned_by: "cocoon",
|
|
2028
|
+
active_workers: totalWorkers,
|
|
2029
|
+
coefficient_min: minCoeff,
|
|
2030
|
+
coefficient_max: maxCoeff
|
|
2031
|
+
};
|
|
2032
|
+
});
|
|
2033
|
+
return {
|
|
2034
|
+
object: "list",
|
|
2035
|
+
data: models
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
// src/ton/wallet.ts
|
|
2041
|
+
var import_crypto = require("@ton/crypto");
|
|
2042
|
+
var import_ton = require("@ton/ton");
|
|
2043
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
2044
|
+
var MnemonicWallet = class {
|
|
2045
|
+
mnemonic;
|
|
2046
|
+
keyPair = null;
|
|
2047
|
+
wallet = null;
|
|
2048
|
+
_address = null;
|
|
2049
|
+
tonClient = null;
|
|
2050
|
+
tonClient4 = null;
|
|
2051
|
+
constructor(mnemonic, network = "mainnet", options) {
|
|
2052
|
+
this.mnemonic = mnemonic.trim().split(/\s+/);
|
|
2053
|
+
if (this.mnemonic.length !== 24) {
|
|
2054
|
+
throw new Error(`Expected 24 mnemonic words, got ${this.mnemonic.length}`);
|
|
2055
|
+
}
|
|
2056
|
+
this.network = network;
|
|
2057
|
+
this.tonEndpoint = options?.tonEndpoint;
|
|
2058
|
+
this.tonV4Endpoint = options?.tonV4Endpoint;
|
|
2059
|
+
}
|
|
2060
|
+
network;
|
|
2061
|
+
tonEndpoint;
|
|
2062
|
+
tonV4Endpoint;
|
|
2063
|
+
async init() {
|
|
2064
|
+
if (this.keyPair) return;
|
|
2065
|
+
this.keyPair = await (0, import_crypto.mnemonicToPrivateKey)(this.mnemonic);
|
|
2066
|
+
this.wallet = import_ton.WalletContractV4.create({
|
|
2067
|
+
workchain: 0,
|
|
2068
|
+
publicKey: this.keyPair.publicKey
|
|
2069
|
+
});
|
|
2070
|
+
this._address = this.wallet.address;
|
|
2071
|
+
}
|
|
2072
|
+
get address() {
|
|
2073
|
+
if (!this._address) throw new Error("Wallet not initialized. Call init() first.");
|
|
2074
|
+
return this._address;
|
|
2075
|
+
}
|
|
2076
|
+
get addressString() {
|
|
2077
|
+
return this.address.toString({ bounceable: true, testOnly: this.network === "testnet" });
|
|
2078
|
+
}
|
|
2079
|
+
get publicKey() {
|
|
2080
|
+
if (!this.keyPair) throw new Error("Wallet not initialized. Call init() first.");
|
|
2081
|
+
return this.keyPair.publicKey;
|
|
2082
|
+
}
|
|
2083
|
+
get secretKey() {
|
|
2084
|
+
if (!this.keyPair) throw new Error("Wallet not initialized. Call init() first.");
|
|
2085
|
+
return this.keyPair.secretKey;
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Compute SHA-256 hash of a secret string (for short auth).
|
|
2089
|
+
*/
|
|
2090
|
+
secretHash(secret) {
|
|
2091
|
+
return import_node_crypto4.default.createHash("sha256").update(secret).digest();
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Get or create a TonClient for blockchain queries.
|
|
2095
|
+
*/
|
|
2096
|
+
getTonClient() {
|
|
2097
|
+
if (!this.tonClient) {
|
|
2098
|
+
const endpoint = this.tonEndpoint ?? (this.network === "mainnet" ? "https://toncenter.com/api/v2/jsonRPC" : "https://testnet.toncenter.com/api/v2/jsonRPC");
|
|
2099
|
+
this.tonClient = new import_ton.TonClient({ endpoint });
|
|
2100
|
+
}
|
|
2101
|
+
return this.tonClient;
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* Get or create a TonClient4 for sending transactions via v4 HTTP API.
|
|
2105
|
+
*/
|
|
2106
|
+
getTonClient4() {
|
|
2107
|
+
if (!this.tonClient4) {
|
|
2108
|
+
const endpoint = this.tonV4Endpoint ?? (this.network === "mainnet" ? "https://mainnet-v4.tonhubapi.com" : "https://testnet-v4.tonhubapi.com");
|
|
2109
|
+
this.tonClient4 = new import_ton.TonClient4({ endpoint });
|
|
2110
|
+
}
|
|
2111
|
+
return this.tonClient4;
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Create a sender for sending transactions.
|
|
2115
|
+
*/
|
|
2116
|
+
async createSender() {
|
|
2117
|
+
if (!this.wallet || !this.keyPair) {
|
|
2118
|
+
throw new Error("Wallet not initialized");
|
|
2119
|
+
}
|
|
2120
|
+
const client = this.getTonClient4();
|
|
2121
|
+
const contract = client.open(this.wallet);
|
|
2122
|
+
return contract.sender(this.keyPair.secretKey);
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
|
|
2126
|
+
// src/ton/discovery.ts
|
|
2127
|
+
var import_ton3 = require("@ton/ton");
|
|
2128
|
+
|
|
2129
|
+
// src/ton/contracts/root.ts
|
|
2130
|
+
var import_ton2 = require("@ton/ton");
|
|
2131
|
+
function buildClientParamsCell(params) {
|
|
2132
|
+
const b = (0, import_ton2.beginCell)().storeUint(params.structVersion, 8).storeUint(params.paramsVersion, 32).storeUint(params.uniqueId, 32).storeBit(params.isTest).storeCoins(params.pricePerToken).storeCoins(params.workerFeePerToken);
|
|
2133
|
+
if (params.structVersion >= 2) {
|
|
2134
|
+
if (params.structVersion >= 3) {
|
|
2135
|
+
b.storeUint(params.promptTokensPriceMultiplier, 32);
|
|
2136
|
+
}
|
|
2137
|
+
b.storeUint(params.cachedTokensPriceMultiplier, 32);
|
|
2138
|
+
if (params.structVersion >= 3) {
|
|
2139
|
+
b.storeUint(params.completionTokensPriceMultiplier, 32);
|
|
2140
|
+
}
|
|
2141
|
+
b.storeUint(params.reasoningTokensPriceMultiplier, 32);
|
|
2142
|
+
}
|
|
2143
|
+
b.storeUint(params.proxyDelayBeforeClose, 32);
|
|
2144
|
+
b.storeUint(params.clientDelayBeforeClose, 32);
|
|
2145
|
+
if (params.structVersion >= 1) {
|
|
2146
|
+
b.storeCoins(params.minProxyStake);
|
|
2147
|
+
b.storeCoins(params.minClientStake);
|
|
2148
|
+
}
|
|
2149
|
+
b.storeMaybeRef(null).storeMaybeRef(null).storeMaybeRef(null);
|
|
2150
|
+
return b.endCell();
|
|
2151
|
+
}
|
|
2152
|
+
function proxyInfoValue() {
|
|
2153
|
+
return {
|
|
2154
|
+
serialize: () => {
|
|
2155
|
+
throw new Error("ProxyInfo serialization not needed for read-only usage");
|
|
2156
|
+
},
|
|
2157
|
+
parse: (src) => {
|
|
2158
|
+
src.loadBit();
|
|
2159
|
+
const strlen = src.loadUint(7);
|
|
2160
|
+
const buf = src.loadBuffer(strlen);
|
|
2161
|
+
return { addr: buf.toString("utf-8") };
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
var CocoonRoot = class {
|
|
2166
|
+
constructor(client, address) {
|
|
2167
|
+
this.client = client;
|
|
2168
|
+
this.address = address;
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Get all parameters by reading the raw contract state and parsing the Cell.
|
|
2172
|
+
* Returns null if the contract is not initialized.
|
|
2173
|
+
*/
|
|
2174
|
+
async getAllParams() {
|
|
2175
|
+
const state = await this.client.getContractState(this.address);
|
|
2176
|
+
if (!state.data) {
|
|
2177
|
+
return null;
|
|
2178
|
+
}
|
|
2179
|
+
const cell = import_ton2.Cell.fromBoc(Buffer.from(state.data))[0];
|
|
2180
|
+
const cs = cell.beginParse();
|
|
2181
|
+
const ownerAddress = cs.loadAddress();
|
|
2182
|
+
const version = cs.loadUint(32);
|
|
2183
|
+
const data = cs.loadRef().beginParse();
|
|
2184
|
+
if (data.loadBit()) data.loadRef();
|
|
2185
|
+
const proxiesDict = data.loadDict(
|
|
2186
|
+
import_ton2.Dictionary.Keys.Uint(32),
|
|
2187
|
+
proxyInfoValue()
|
|
2188
|
+
);
|
|
2189
|
+
const lastProxySeqno = data.loadUint(32);
|
|
2190
|
+
if (data.loadBit()) data.loadRef();
|
|
2191
|
+
if (data.loadBit()) data.loadRef();
|
|
2192
|
+
const pcs = cs.loadRef().beginParse();
|
|
2193
|
+
const structVersion = pcs.loadUint(8);
|
|
2194
|
+
const paramsVersion = pcs.loadUint(32);
|
|
2195
|
+
const uniqueId = pcs.loadUint(32);
|
|
2196
|
+
const isTest = pcs.loadBit();
|
|
2197
|
+
const pricePerToken = pcs.loadCoins();
|
|
2198
|
+
const workerFeePerToken = pcs.loadCoins();
|
|
2199
|
+
let promptTokensPriceMultiplier = 1e4;
|
|
2200
|
+
if (structVersion >= 3) {
|
|
2201
|
+
promptTokensPriceMultiplier = pcs.loadUint(32);
|
|
2202
|
+
}
|
|
2203
|
+
let cachedTokensPriceMultiplier = 1e4;
|
|
2204
|
+
if (structVersion >= 2) {
|
|
2205
|
+
cachedTokensPriceMultiplier = pcs.loadUint(32);
|
|
2206
|
+
}
|
|
2207
|
+
let completionTokensPriceMultiplier = 1e4;
|
|
2208
|
+
if (structVersion >= 3) {
|
|
2209
|
+
completionTokensPriceMultiplier = pcs.loadUint(32);
|
|
2210
|
+
}
|
|
2211
|
+
let reasoningTokensPriceMultiplier = 1e4;
|
|
2212
|
+
if (structVersion >= 2) {
|
|
2213
|
+
reasoningTokensPriceMultiplier = pcs.loadUint(32);
|
|
2214
|
+
}
|
|
2215
|
+
const proxyDelayBeforeClose = pcs.loadUint(32);
|
|
2216
|
+
const clientDelayBeforeClose = pcs.loadUint(32);
|
|
2217
|
+
let minProxyStake = 1000000000n;
|
|
2218
|
+
let minClientStake = 1000000000n;
|
|
2219
|
+
if (structVersion >= 1) {
|
|
2220
|
+
minProxyStake = pcs.loadCoins();
|
|
2221
|
+
minClientStake = pcs.loadCoins();
|
|
2222
|
+
}
|
|
2223
|
+
const proxyScCode = pcs.loadMaybeRef();
|
|
2224
|
+
const workerScCode = pcs.loadMaybeRef();
|
|
2225
|
+
const clientScCode = pcs.loadMaybeRef();
|
|
2226
|
+
const registeredProxies = [];
|
|
2227
|
+
if (proxiesDict) {
|
|
2228
|
+
for (const [seqno, info] of proxiesDict) {
|
|
2229
|
+
registeredProxies.push({ seqno, address: info.addr });
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
return {
|
|
2233
|
+
ownerAddress,
|
|
2234
|
+
registeredProxies,
|
|
2235
|
+
lastProxySeqno,
|
|
2236
|
+
version,
|
|
2237
|
+
params: {
|
|
2238
|
+
structVersion,
|
|
2239
|
+
paramsVersion,
|
|
2240
|
+
uniqueId,
|
|
2241
|
+
isTest,
|
|
2242
|
+
pricePerToken,
|
|
2243
|
+
workerFeePerToken,
|
|
2244
|
+
promptTokensPriceMultiplier,
|
|
2245
|
+
cachedTokensPriceMultiplier,
|
|
2246
|
+
completionTokensPriceMultiplier,
|
|
2247
|
+
reasoningTokensPriceMultiplier,
|
|
2248
|
+
proxyDelayBeforeClose,
|
|
2249
|
+
clientDelayBeforeClose,
|
|
2250
|
+
minProxyStake,
|
|
2251
|
+
minClientStake
|
|
2252
|
+
},
|
|
2253
|
+
codes: {
|
|
2254
|
+
proxyScCode,
|
|
2255
|
+
workerScCode,
|
|
2256
|
+
clientScCode
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2262
|
+
// src/ton/discovery.ts
|
|
2263
|
+
var ROOT_CONTRACTS = {
|
|
2264
|
+
mainnet: "EQCns7bYSp0igFvS1wpb5wsZjCKCV19MD5AVzI4EyxsnU73k",
|
|
2265
|
+
testnet: "EQBT4hy4vMEZ9uxSCuhw_gBKh9_AwmHXLe7Wo0O4Vh-4kRjJ"
|
|
2266
|
+
};
|
|
2267
|
+
var ProxyDiscovery = class {
|
|
2268
|
+
tonClient;
|
|
2269
|
+
rootAddress;
|
|
2270
|
+
cachedParams = null;
|
|
2271
|
+
cacheTime = 0;
|
|
2272
|
+
cacheTtl = 6e4;
|
|
2273
|
+
// 1 minute
|
|
2274
|
+
constructor(options) {
|
|
2275
|
+
const endpoint = options.tonApiEndpoint ?? (options.network === "mainnet" ? "https://toncenter.com/api/v2/jsonRPC" : "https://testnet.toncenter.com/api/v2/jsonRPC");
|
|
2276
|
+
this.tonClient = new import_ton3.TonClient({ endpoint });
|
|
2277
|
+
const addr = options.rootContractAddress ?? ROOT_CONTRACTS[options.network];
|
|
2278
|
+
if (!addr) {
|
|
2279
|
+
throw new Error(`No root contract address for network: ${options.network}`);
|
|
2280
|
+
}
|
|
2281
|
+
this.rootAddress = import_ton3.Address.parse(addr);
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Get all registered proxies from the root contract.
|
|
2285
|
+
*/
|
|
2286
|
+
async getProxies() {
|
|
2287
|
+
const params = await this.getRootParams();
|
|
2288
|
+
return params.registeredProxies;
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Get a random proxy for connection.
|
|
2292
|
+
*/
|
|
2293
|
+
async getRandomProxy() {
|
|
2294
|
+
const proxies = await this.getProxies();
|
|
2295
|
+
if (proxies.length === 0) {
|
|
2296
|
+
throw new Error("No proxies available in the network");
|
|
2297
|
+
}
|
|
2298
|
+
const idx = Math.floor(Math.random() * proxies.length);
|
|
2299
|
+
return proxies[idx];
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Get root contract parameters (cached).
|
|
2303
|
+
*/
|
|
2304
|
+
async getRootParams() {
|
|
2305
|
+
const now = Date.now();
|
|
2306
|
+
if (this.cachedParams && now - this.cacheTime < this.cacheTtl) {
|
|
2307
|
+
return this.cachedParams;
|
|
2308
|
+
}
|
|
2309
|
+
const root = new CocoonRoot(this.tonClient, this.rootAddress);
|
|
2310
|
+
const result = await root.getAllParams();
|
|
2311
|
+
if (!result) {
|
|
2312
|
+
throw new Error("Root contract is not initialized");
|
|
2313
|
+
}
|
|
2314
|
+
this.cachedParams = result;
|
|
2315
|
+
this.cacheTime = now;
|
|
2316
|
+
return this.cachedParams;
|
|
2317
|
+
}
|
|
2318
|
+
};
|
|
2319
|
+
|
|
2320
|
+
// src/ton/contracts/client-contract.ts
|
|
2321
|
+
var import_ton4 = require("@ton/ton");
|
|
2322
|
+
var OPCODES = {
|
|
2323
|
+
ownerClientRegister: 3294601019,
|
|
2324
|
+
ownerClientChangeSecretHash: 2838851636,
|
|
2325
|
+
extClientTopUp: 4050839234
|
|
2326
|
+
};
|
|
2327
|
+
var CocoonClientContract = class _CocoonClientContract {
|
|
2328
|
+
constructor(address) {
|
|
2329
|
+
this.address = address;
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Create a registration message body for the proxy.
|
|
2333
|
+
* This is sent to the client smart contract to register with a proxy.
|
|
2334
|
+
*/
|
|
2335
|
+
static createRegisterBody(nonce, sendExcessesTo, queryId = 0n) {
|
|
2336
|
+
const nonceU64 = BigInt.asUintN(64, nonce);
|
|
2337
|
+
const queryIdU64 = BigInt.asUintN(64, queryId);
|
|
2338
|
+
return (0, import_ton4.beginCell)().storeUint(OPCODES.ownerClientRegister, 32).storeUint(queryIdU64, 64).storeUint(nonceU64, 64).storeAddress(sendExcessesTo).endCell();
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* Create a message body to change the secret hash.
|
|
2342
|
+
*/
|
|
2343
|
+
static createChangeSecretHashBody(secretHash, sendExcessesTo, queryId = 0n) {
|
|
2344
|
+
const queryIdU64 = BigInt.asUintN(64, queryId);
|
|
2345
|
+
return (0, import_ton4.beginCell)().storeUint(OPCODES.ownerClientChangeSecretHash, 32).storeUint(queryIdU64, 64).storeBuffer(secretHash, 32).storeAddress(sendExcessesTo).endCell();
|
|
2346
|
+
}
|
|
2347
|
+
/**
|
|
2348
|
+
* Create a top-up message body.
|
|
2349
|
+
*/
|
|
2350
|
+
static createTopUpBody(coins, sendExcessesTo, queryId = 0n) {
|
|
2351
|
+
const queryIdU64 = BigInt.asUintN(64, queryId);
|
|
2352
|
+
return (0, import_ton4.beginCell)().storeUint(OPCODES.extClientTopUp, 32).storeUint(queryIdU64, 64).storeCoins(coins).storeAddress(sendExcessesTo).endCell();
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Build client_sc data cell for deployment.
|
|
2356
|
+
* Mirrors ClientContract::init_data_cell in upstream C++ code.
|
|
2357
|
+
*/
|
|
2358
|
+
static createDeployDataCell(ownerAddress, proxyScAddress, proxyPublicKey, minClientStake, clientParamsCell) {
|
|
2359
|
+
if (proxyPublicKey.length !== 32) {
|
|
2360
|
+
throw new Error(`proxyPublicKey must be 32 bytes, got ${proxyPublicKey.length}`);
|
|
2361
|
+
}
|
|
2362
|
+
const configDataRef = (0, import_ton4.beginCell)().storeAddress(ownerAddress).storeAddress(proxyScAddress).storeBuffer(proxyPublicKey, 32).endCell();
|
|
2363
|
+
return (0, import_ton4.beginCell)().storeUint(0, 2).storeCoins(0n).storeCoins(minClientStake).storeInt(0n, 64).storeInt(0, 32).storeBuffer(Buffer.alloc(32), 32).storeRef(configDataRef).storeRef(clientParamsCell).endCell();
|
|
2364
|
+
}
|
|
2365
|
+
static createStateInit(clientCode, dataCell) {
|
|
2366
|
+
return {
|
|
2367
|
+
code: clientCode,
|
|
2368
|
+
data: dataCell
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
/**
|
|
2372
|
+
* Send a registration transaction to the client contract.
|
|
2373
|
+
*/
|
|
2374
|
+
async register(sender, ownerAddress, nonce, amount = (0, import_ton4.toNano)("1"), init) {
|
|
2375
|
+
const body = _CocoonClientContract.createRegisterBody(nonce, ownerAddress);
|
|
2376
|
+
const message = {
|
|
2377
|
+
to: this.address,
|
|
2378
|
+
value: amount,
|
|
2379
|
+
body
|
|
2380
|
+
};
|
|
2381
|
+
if (init) {
|
|
2382
|
+
message.init = init;
|
|
2383
|
+
}
|
|
2384
|
+
await sender.send(message);
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Top up the client contract balance.
|
|
2388
|
+
*/
|
|
2389
|
+
async topUp(sender, ownerAddress, amount) {
|
|
2390
|
+
const body = _CocoonClientContract.createTopUpBody(amount, ownerAddress);
|
|
2391
|
+
await sender.send({
|
|
2392
|
+
to: this.address,
|
|
2393
|
+
value: amount + (0, import_ton4.toNano)("0.7"),
|
|
2394
|
+
body
|
|
2395
|
+
});
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Change the secret hash for short auth.
|
|
2399
|
+
*/
|
|
2400
|
+
async changeSecretHash(sender, ownerAddress, secretHash, amount = (0, import_ton4.toNano)("0.7")) {
|
|
2401
|
+
const body = _CocoonClientContract.createChangeSecretHashBody(secretHash, ownerAddress);
|
|
2402
|
+
await sender.send({
|
|
2403
|
+
to: this.address,
|
|
2404
|
+
value: amount,
|
|
2405
|
+
body
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
};
|
|
2409
|
+
|
|
2410
|
+
// src/client.ts
|
|
2411
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
2412
|
+
var import_ton5 = require("@ton/ton");
|
|
2413
|
+
var import_core = require("@ton/core");
|
|
2414
|
+
var Cocoon = class {
|
|
2415
|
+
chat;
|
|
2416
|
+
models;
|
|
2417
|
+
mnemonicWallet;
|
|
2418
|
+
discovery;
|
|
2419
|
+
session = null;
|
|
2420
|
+
connecting = null;
|
|
2421
|
+
options;
|
|
2422
|
+
constructor(options) {
|
|
2423
|
+
if (options.tlsCert && !options.tlsKey || !options.tlsCert && options.tlsKey) {
|
|
2424
|
+
throw new ConnectionError(
|
|
2425
|
+
"Both tlsCert and tlsKey must be provided together for mTLS"
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
if (options.attestationProvider && (options.tlsCert || options.tlsKey)) {
|
|
2429
|
+
throw new ConnectionError(
|
|
2430
|
+
"Use either attestationProvider or tlsCert/tlsKey, not both"
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
this.options = {
|
|
2434
|
+
network: "mainnet",
|
|
2435
|
+
timeout: 12e4,
|
|
2436
|
+
useTls: true,
|
|
2437
|
+
autoRegisterOnLongAuth: true,
|
|
2438
|
+
longAuthRegisterAmountTon: "1",
|
|
2439
|
+
...options
|
|
2440
|
+
};
|
|
2441
|
+
this.mnemonicWallet = new MnemonicWallet(options.wallet, this.options.network, {
|
|
2442
|
+
tonEndpoint: this.options.tonEndpoint,
|
|
2443
|
+
tonV4Endpoint: this.options.tonV4Endpoint
|
|
2444
|
+
});
|
|
2445
|
+
if (!options.proxyUrl) {
|
|
2446
|
+
this.discovery = new ProxyDiscovery({ network: this.options.network });
|
|
2447
|
+
} else {
|
|
2448
|
+
this.discovery = null;
|
|
2449
|
+
}
|
|
2450
|
+
const getSession = () => this.ensureSession();
|
|
2451
|
+
this.chat = { completions: new Completions(getSession) };
|
|
2452
|
+
this.models = new Models(getSession);
|
|
2453
|
+
}
|
|
2454
|
+
/**
|
|
2455
|
+
* Explicitly connect to a proxy. Called lazily on first API call if not called manually.
|
|
2456
|
+
*/
|
|
2457
|
+
async connect() {
|
|
2458
|
+
await this.ensureSession();
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Disconnect from the proxy.
|
|
2462
|
+
*/
|
|
2463
|
+
async disconnect() {
|
|
2464
|
+
if (this.session) {
|
|
2465
|
+
await this.session.disconnect();
|
|
2466
|
+
this.session = null;
|
|
2467
|
+
}
|
|
2468
|
+
this.connecting = null;
|
|
2469
|
+
}
|
|
2470
|
+
async ensureSession() {
|
|
2471
|
+
if (this.session?.connected) {
|
|
2472
|
+
return this.session;
|
|
2473
|
+
}
|
|
2474
|
+
if (this.connecting) {
|
|
2475
|
+
return this.connecting;
|
|
2476
|
+
}
|
|
2477
|
+
this.connecting = this.createSession();
|
|
2478
|
+
try {
|
|
2479
|
+
this.session = await this.connecting;
|
|
2480
|
+
return this.session;
|
|
2481
|
+
} finally {
|
|
2482
|
+
this.connecting = null;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
async createSession() {
|
|
2486
|
+
await this.mnemonicWallet.init();
|
|
2487
|
+
let host;
|
|
2488
|
+
let port;
|
|
2489
|
+
if (this.options.proxyUrl) {
|
|
2490
|
+
const parts = this.options.proxyUrl.split(":");
|
|
2491
|
+
host = parts.slice(0, -1).join(":");
|
|
2492
|
+
port = parseInt(parts[parts.length - 1], 10);
|
|
2493
|
+
if (!host || isNaN(port)) {
|
|
2494
|
+
throw new ConnectionError(`Invalid proxyUrl: ${this.options.proxyUrl}`);
|
|
2495
|
+
}
|
|
2496
|
+
} else if (this.discovery) {
|
|
2497
|
+
const proxy = await this.discovery.getRandomProxy();
|
|
2498
|
+
const entries = proxy.address.trim().split(/\s+/);
|
|
2499
|
+
const clientEntry = entries.length > 1 ? entries[1] : entries[0];
|
|
2500
|
+
const lastColon = clientEntry.lastIndexOf(":");
|
|
2501
|
+
host = clientEntry.substring(0, lastColon);
|
|
2502
|
+
port = parseInt(clientEntry.substring(lastColon + 1), 10);
|
|
2503
|
+
if (!host || isNaN(port)) {
|
|
2504
|
+
throw new ConnectionError(`Invalid proxy address from discovery: ${proxy.address}`);
|
|
2505
|
+
}
|
|
2506
|
+
} else {
|
|
2507
|
+
throw new ConnectionError("No proxy URL or discovery available");
|
|
2508
|
+
}
|
|
2509
|
+
let tlsCert = this.options.tlsCert;
|
|
2510
|
+
let tlsKey = this.options.tlsKey;
|
|
2511
|
+
if (this.options.attestationProvider) {
|
|
2512
|
+
const context = {
|
|
2513
|
+
host,
|
|
2514
|
+
port,
|
|
2515
|
+
network: this.options.network
|
|
2516
|
+
};
|
|
2517
|
+
const credentials = await this.options.attestationProvider.getClientTlsCredentials(context);
|
|
2518
|
+
tlsCert = credentials.cert;
|
|
2519
|
+
tlsKey = credentials.key;
|
|
2520
|
+
}
|
|
2521
|
+
if (tlsCert && !tlsKey || !tlsCert && tlsKey) {
|
|
2522
|
+
throw new ConnectionError("Attestation provider returned incomplete TLS credentials");
|
|
2523
|
+
}
|
|
2524
|
+
const secretString = this.options.secretString ?? import_node_crypto5.default.randomBytes(32).toString("hex");
|
|
2525
|
+
const onLongAuthRequired = this.options.autoRegisterOnLongAuth ? async (context) => {
|
|
2526
|
+
try {
|
|
2527
|
+
const sender = await this.mnemonicWallet.createSender();
|
|
2528
|
+
const clientScAddress = import_ton5.Address.parse(context.clientScAddress);
|
|
2529
|
+
const clientContract = new CocoonClientContract(clientScAddress);
|
|
2530
|
+
const v4Client = this.mnemonicWallet.getTonClient4();
|
|
2531
|
+
const last = await v4Client.getLastBlock();
|
|
2532
|
+
const account = await v4Client.getAccount(last.last.seqno, clientScAddress);
|
|
2533
|
+
let init;
|
|
2534
|
+
if (account.account.state.type !== "active") {
|
|
2535
|
+
const discovery = this.discovery ?? new ProxyDiscovery({
|
|
2536
|
+
network: this.options.network,
|
|
2537
|
+
tonApiEndpoint: this.options.tonEndpoint
|
|
2538
|
+
});
|
|
2539
|
+
const rootParams = await discovery.getRootParams();
|
|
2540
|
+
const clientCode = rootParams.codes.clientScCode;
|
|
2541
|
+
if (!clientCode) {
|
|
2542
|
+
throw new Error(
|
|
2543
|
+
"Root contract does not contain client_sc_code; cannot deploy client contract"
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
const clientParamsCell = buildClientParamsCell(rootParams.params);
|
|
2547
|
+
const dataCell = CocoonClientContract.createDeployDataCell(
|
|
2548
|
+
this.mnemonicWallet.address,
|
|
2549
|
+
import_ton5.Address.parse(context.proxyParams.proxyScAddress),
|
|
2550
|
+
context.proxyParams.proxyPublicKey,
|
|
2551
|
+
rootParams.params.minClientStake,
|
|
2552
|
+
clientParamsCell
|
|
2553
|
+
);
|
|
2554
|
+
init = CocoonClientContract.createStateInit(clientCode, dataCell);
|
|
2555
|
+
const expectedAddress = (0, import_core.contractAddress)(0, init);
|
|
2556
|
+
if (!expectedAddress.equals(clientScAddress)) {
|
|
2557
|
+
throw new Error(
|
|
2558
|
+
`Computed client_sc mismatch: expected ${context.clientScAddress}, got ${expectedAddress.toString({ bounceable: true, testOnly: this.options.network === "testnet" })}`
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
await clientContract.register(
|
|
2563
|
+
sender,
|
|
2564
|
+
this.mnemonicWallet.address,
|
|
2565
|
+
context.nonce,
|
|
2566
|
+
(0, import_ton5.toNano)(this.options.longAuthRegisterAmountTon),
|
|
2567
|
+
init
|
|
2568
|
+
);
|
|
2569
|
+
} catch (err) {
|
|
2570
|
+
throw new ConnectionError(
|
|
2571
|
+
`Auto long-auth registration failed: ${err instanceof Error ? err.message : String(err)}. Configure tonEndpoint / wallet balance or provide a valid SECRET`,
|
|
2572
|
+
err instanceof Error ? err : void 0
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
} : void 0;
|
|
2576
|
+
const sessionOptions = {
|
|
2577
|
+
host,
|
|
2578
|
+
port,
|
|
2579
|
+
useTls: this.options.useTls,
|
|
2580
|
+
timeout: this.options.timeout,
|
|
2581
|
+
ownerAddress: this.mnemonicWallet.addressString,
|
|
2582
|
+
secretString,
|
|
2583
|
+
tlsCert,
|
|
2584
|
+
tlsKey,
|
|
2585
|
+
onLongAuthRequired
|
|
2586
|
+
};
|
|
2587
|
+
const session = new CocoonSession(sessionOptions);
|
|
2588
|
+
await session.connect();
|
|
2589
|
+
session.on("close", () => {
|
|
2590
|
+
if (this.session === session) {
|
|
2591
|
+
this.session = null;
|
|
2592
|
+
}
|
|
2593
|
+
});
|
|
2594
|
+
return session;
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
|
|
2598
|
+
// src/core/protocol/attestation.ts
|
|
2599
|
+
var import_promises = require("fs/promises");
|
|
2600
|
+
var StaticAttestationProvider = class {
|
|
2601
|
+
constructor(credentials) {
|
|
2602
|
+
this.credentials = credentials;
|
|
2603
|
+
}
|
|
2604
|
+
async getClientTlsCredentials() {
|
|
2605
|
+
return this.credentials;
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2608
|
+
var FileAttestationProvider = class {
|
|
2609
|
+
constructor(certPath, keyPath) {
|
|
2610
|
+
this.certPath = certPath;
|
|
2611
|
+
this.keyPath = keyPath;
|
|
2612
|
+
}
|
|
2613
|
+
async getClientTlsCredentials() {
|
|
2614
|
+
const [cert, key] = await Promise.all([
|
|
2615
|
+
(0, import_promises.readFile)(this.certPath),
|
|
2616
|
+
(0, import_promises.readFile)(this.keyPath)
|
|
2617
|
+
]);
|
|
2618
|
+
return { cert, key };
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2622
|
+
0 && (module.exports = {
|
|
2623
|
+
APIError,
|
|
2624
|
+
AuthenticationError,
|
|
2625
|
+
Cocoon,
|
|
2626
|
+
CocoonError,
|
|
2627
|
+
ConnectionError,
|
|
2628
|
+
FileAttestationProvider,
|
|
2629
|
+
ProtocolError,
|
|
2630
|
+
StaticAttestationProvider,
|
|
2631
|
+
Stream,
|
|
2632
|
+
TimeoutError
|
|
2633
|
+
});
|
|
2634
|
+
//# sourceMappingURL=index.cjs.map
|