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.
@@ -0,0 +1,462 @@
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ /**
4
+ * TCP + TLS connection with Cocoon framing.
5
+ *
6
+ * Connection flow:
7
+ * 1. Raw TCP connect
8
+ * 2. Receive PoW challenge (24 bytes), solve it, send response (12 bytes)
9
+ * 3. Upgrade to TLS on same socket
10
+ * 4. TL framing begins: [4 bytes LE size][4 bytes LE seqno][payload]
11
+ * Where `size` is the length of `payload` only.
12
+ */
13
+
14
+ interface ConnectionOptions {
15
+ host: string;
16
+ port: number;
17
+ useTls?: boolean;
18
+ timeout?: number;
19
+ /** PEM-encoded TLS client certificate (for RA-TLS / mTLS) */
20
+ tlsCert?: string | Buffer;
21
+ /** PEM-encoded TLS client private key (for RA-TLS / mTLS) */
22
+ tlsKey?: string | Buffer;
23
+ }
24
+
25
+ /**
26
+ * TypeScript interfaces for TL objects used in the Cocoon protocol.
27
+ * Derived from cocoon_api.tl schema.
28
+ */
29
+ type TLInt = number;
30
+ type TLLong = bigint;
31
+ type TLDouble = number;
32
+ type TLInt256 = Buffer;
33
+ type TLBytes = Buffer;
34
+ type TLString = string;
35
+ type TLBool = boolean;
36
+ interface ProxyParams {
37
+ _type: 'proxy.params';
38
+ flags: TLInt;
39
+ proxyPublicKey: TLInt256;
40
+ proxyOwnerAddress: TLString;
41
+ proxyScAddress: TLString;
42
+ isTest?: TLBool;
43
+ protoVersion?: TLInt;
44
+ }
45
+ interface TokensUsed {
46
+ _type: 'tokensUsed';
47
+ promptTokensUsed: TLLong;
48
+ cachedTokensUsed: TLLong;
49
+ completionTokensUsed: TLLong;
50
+ reasoningTokensUsed: TLLong;
51
+ totalTokensUsed: TLLong;
52
+ }
53
+ interface ClientQueryFinalInfo {
54
+ _type: 'client.queryFinalInfo';
55
+ flags: TLInt;
56
+ tokensUsed: TokensUsed;
57
+ workerDebug?: TLString;
58
+ proxyDebug?: TLString;
59
+ proxyStartTime?: TLDouble;
60
+ proxyEndTime?: TLDouble;
61
+ workerStartTime?: TLDouble;
62
+ workerEndTime?: TLDouble;
63
+ }
64
+ interface ClientQueryAnswerEx {
65
+ _type: 'client.queryAnswerEx';
66
+ requestId: TLInt256;
67
+ answer: TLBytes;
68
+ flags: TLInt;
69
+ finalInfo?: ClientQueryFinalInfo;
70
+ }
71
+ interface ClientQueryAnswerErrorEx {
72
+ _type: 'client.queryAnswerErrorEx';
73
+ requestId: TLInt256;
74
+ errorCode: TLInt;
75
+ error: TLString;
76
+ flags: TLInt;
77
+ finalInfo?: ClientQueryFinalInfo;
78
+ }
79
+ interface ClientQueryAnswerPartEx {
80
+ _type: 'client.queryAnswerPartEx';
81
+ requestId: TLInt256;
82
+ answer: TLBytes;
83
+ flags: TLInt;
84
+ finalInfo?: ClientQueryFinalInfo;
85
+ }
86
+ type ClientQueryAnswerExType = ClientQueryAnswerEx | ClientQueryAnswerErrorEx | ClientQueryAnswerPartEx;
87
+ interface HttpHeader {
88
+ _type: 'http.header';
89
+ name: TLString;
90
+ value: TLString;
91
+ }
92
+ interface HttpRequest {
93
+ _type: 'http.request';
94
+ method: TLString;
95
+ url: TLString;
96
+ httpVersion: TLString;
97
+ headers: HttpHeader[];
98
+ payload: TLBytes;
99
+ }
100
+
101
+ /**
102
+ * Cocoon protocol handshake.
103
+ *
104
+ * Flow:
105
+ * 1. Client sends tcp.connect(id) → Server replies tcp.connected(id)
106
+ * 2. Client sends client.connectToProxy(params, minConfigVersion)
107
+ * → Server replies client.connectedToProxy(params, clientScAddress, auth, signedPayment)
108
+ * 3. Auth: short (secret hash match) or long (blockchain registration)
109
+ * - Short: client.authorizeWithProxyShort(secretData)
110
+ * - Long: client.authorizeWithProxyLong() (after on-chain tx)
111
+ * → Server replies client.AuthorizationWithProxy (success or failed)
112
+ */
113
+
114
+ interface LongAuthContext {
115
+ nonce: bigint;
116
+ clientScAddress: string;
117
+ proxyParams: ProxyParams;
118
+ }
119
+ type LongAuthHandler = (context: LongAuthContext) => Promise<void>;
120
+
121
+ /**
122
+ * Cocoon Session — manages an authenticated connection to a proxy.
123
+ *
124
+ * Handles:
125
+ * - Keepalive (tcp.ping/tcp.pong)
126
+ * - Query dispatch and response routing by requestId
127
+ * - Streaming response assembly
128
+ */
129
+
130
+ interface SessionOptions extends ConnectionOptions {
131
+ ownerAddress: string;
132
+ secretString: string;
133
+ configVersion?: number;
134
+ onLongAuthRequired?: LongAuthHandler;
135
+ }
136
+ declare class CocoonSession extends EventEmitter {
137
+ private conn;
138
+ private handshakeResult;
139
+ private pendingQueries;
140
+ private keepaliveTimer;
141
+ private _connected;
142
+ private readonly options;
143
+ constructor(options: SessionOptions);
144
+ get connected(): boolean;
145
+ get protoVersion(): number;
146
+ connect(): Promise<void>;
147
+ /**
148
+ * Send a query and wait for the complete answer.
149
+ */
150
+ sendQuery(modelName: string, httpRequest: HttpRequest, options?: {
151
+ maxCoefficient?: number;
152
+ maxTokens?: number;
153
+ timeout?: number;
154
+ enableDebug?: boolean;
155
+ onPart?: (part: ClientQueryAnswerExType) => void;
156
+ }): Promise<ClientQueryAnswerExType>;
157
+ /**
158
+ * Send a raw TL function (for getWorkerTypesV2, etc.)
159
+ */
160
+ sendRpcQuery(tlObject: Record<string, unknown>, timeoutMs?: number): Promise<Record<string, unknown>>;
161
+ disconnect(): Promise<void>;
162
+ private handleFrame;
163
+ private handleInnerPacket;
164
+ private isTerminalQueryAnswer;
165
+ private startKeepalive;
166
+ private cleanup;
167
+ }
168
+
169
+ /**
170
+ * Stream<T> — an async iterable wrapper for streaming responses.
171
+ * Follows the OpenAI SDK pattern.
172
+ */
173
+ declare class Stream<T> implements AsyncIterable<T> {
174
+ private controller;
175
+ private stream;
176
+ private _done;
177
+ constructor();
178
+ /**
179
+ * Push a chunk into the stream.
180
+ */
181
+ push(chunk: T): void;
182
+ /**
183
+ * Signal that the stream is complete.
184
+ */
185
+ end(): void;
186
+ /**
187
+ * Signal an error on the stream.
188
+ */
189
+ error(err: Error): void;
190
+ get done(): boolean;
191
+ [Symbol.asyncIterator](): AsyncIterator<T>;
192
+ }
193
+
194
+ /**
195
+ * Common types shared across the API.
196
+ */
197
+ interface Usage {
198
+ prompt_tokens: number;
199
+ completion_tokens: number;
200
+ total_tokens: number;
201
+ cached_tokens?: number;
202
+ reasoning_tokens?: number;
203
+ }
204
+ type FinishReason = 'stop' | 'length' | 'content_filter' | 'tool_calls' | null;
205
+
206
+ /**
207
+ * OpenAI-compatible chat completion types.
208
+ */
209
+
210
+ type ChatRole = 'system' | 'user' | 'assistant';
211
+ interface ChatMessage {
212
+ role: ChatRole;
213
+ content: string;
214
+ }
215
+ interface ChatCompletionCreateParams {
216
+ model: string;
217
+ messages: ChatMessage[];
218
+ temperature?: number;
219
+ top_p?: number;
220
+ max_tokens?: number;
221
+ max_completion_tokens?: number;
222
+ stream?: boolean;
223
+ stop?: string | string[];
224
+ presence_penalty?: number;
225
+ frequency_penalty?: number;
226
+ /** Cocoon-specific: max coefficient for worker selection */
227
+ max_coefficient?: number;
228
+ /** Cocoon-specific: request timeout in ms */
229
+ timeout?: number;
230
+ }
231
+ interface ChatCompletionChoice {
232
+ index: number;
233
+ message: ChatMessage;
234
+ finish_reason: FinishReason;
235
+ }
236
+ interface ChatCompletion {
237
+ id: string;
238
+ object: 'chat.completion';
239
+ created: number;
240
+ model: string;
241
+ choices: ChatCompletionChoice[];
242
+ usage?: Usage;
243
+ }
244
+ interface ChatCompletionChunkDelta {
245
+ role?: ChatRole;
246
+ content?: string;
247
+ }
248
+ interface ChatCompletionChunkChoice {
249
+ index: number;
250
+ delta: ChatCompletionChunkDelta;
251
+ finish_reason: FinishReason;
252
+ }
253
+ interface ChatCompletionChunk {
254
+ id: string;
255
+ object: 'chat.completion.chunk';
256
+ created: number;
257
+ model: string;
258
+ choices: ChatCompletionChunkChoice[];
259
+ usage?: Usage;
260
+ }
261
+
262
+ /**
263
+ * Chat Completions resource — the main API for AI inference.
264
+ *
265
+ * Implements both non-streaming and streaming modes:
266
+ * - Non-streaming: collects all queryAnswerPartEx + final queryAnswerEx,
267
+ * parses the HTTP response body as JSON, returns ChatCompletion.
268
+ * - Streaming: wraps parts in Stream<ChatCompletionChunk>, parses SSE from chunks.
269
+ */
270
+
271
+ type SessionProvider$1 = () => Promise<CocoonSession>;
272
+ declare class Completions {
273
+ private readonly getSession;
274
+ constructor(getSession: SessionProvider$1);
275
+ private extractHttpData;
276
+ private parseErrorPayload;
277
+ /**
278
+ * Create a chat completion.
279
+ *
280
+ * @param params - OpenAI-compatible chat completion parameters
281
+ * @returns ChatCompletion (non-streaming) or Stream<ChatCompletionChunk> (streaming)
282
+ */
283
+ create(params: ChatCompletionCreateParams & {
284
+ stream: true;
285
+ }): Promise<Stream<ChatCompletionChunk>>;
286
+ create(params: ChatCompletionCreateParams & {
287
+ stream?: false;
288
+ }): Promise<ChatCompletion>;
289
+ create(params: ChatCompletionCreateParams): Promise<ChatCompletion | Stream<ChatCompletionChunk>>;
290
+ private createNonStreaming;
291
+ private createStreaming;
292
+ private processSSEBuffer;
293
+ }
294
+
295
+ /**
296
+ * OpenAI-compatible model types.
297
+ */
298
+ interface Model {
299
+ id: string;
300
+ object: 'model';
301
+ created: number;
302
+ owned_by: string;
303
+ /** Cocoon-specific: number of active workers for this model */
304
+ active_workers?: number;
305
+ /** Cocoon-specific: coefficient range */
306
+ coefficient_min?: number;
307
+ coefficient_max?: number;
308
+ }
309
+ interface ModelList {
310
+ object: 'list';
311
+ data: Model[];
312
+ }
313
+
314
+ /**
315
+ * Models resource — list available AI models on the network.
316
+ *
317
+ * Uses client.getWorkerTypesV2 TL function to query the proxy.
318
+ */
319
+
320
+ type SessionProvider = () => Promise<CocoonSession>;
321
+ declare class Models {
322
+ private readonly getSession;
323
+ constructor(getSession: SessionProvider);
324
+ /**
325
+ * List all available models on the network.
326
+ */
327
+ list(): Promise<ModelList>;
328
+ }
329
+
330
+ interface ClientTlsCredentials {
331
+ cert: string | Buffer;
332
+ key: string | Buffer;
333
+ }
334
+ interface AttestationContext {
335
+ host: string;
336
+ port: number;
337
+ network: 'mainnet' | 'testnet';
338
+ }
339
+ /**
340
+ * Provides RA-TLS client credentials (certificate + private key) for mTLS.
341
+ * Implementations may load static values, files, or fetch from sidecars.
342
+ */
343
+ interface AttestationProvider {
344
+ getClientTlsCredentials(context: AttestationContext): Promise<ClientTlsCredentials>;
345
+ }
346
+ /**
347
+ * Uses already available in-memory credentials.
348
+ */
349
+ declare class StaticAttestationProvider implements AttestationProvider {
350
+ private readonly credentials;
351
+ constructor(credentials: ClientTlsCredentials);
352
+ getClientTlsCredentials(): Promise<ClientTlsCredentials>;
353
+ }
354
+ /**
355
+ * Loads credentials from PEM files on each call.
356
+ * Useful when credentials are rotated externally.
357
+ */
358
+ declare class FileAttestationProvider implements AttestationProvider {
359
+ private readonly certPath;
360
+ private readonly keyPath;
361
+ constructor(certPath: string, keyPath: string);
362
+ getClientTlsCredentials(): Promise<ClientTlsCredentials>;
363
+ }
364
+
365
+ /**
366
+ * Cocoon SDK Client — the main entry point.
367
+ *
368
+ * Usage:
369
+ * const client = new Cocoon({
370
+ * wallet: '24 word mnemonic...',
371
+ * network: 'mainnet',
372
+ * });
373
+ *
374
+ * const response = await client.chat.completions.create({
375
+ * model: 'deepseek-r1',
376
+ * messages: [{ role: 'user', content: 'Hello!' }],
377
+ * });
378
+ */
379
+
380
+ interface CocoonOptions {
381
+ /** 24-word mnemonic phrase */
382
+ wallet: string;
383
+ /** Network: mainnet or testnet. Default: mainnet */
384
+ network?: 'mainnet' | 'testnet';
385
+ /** Direct proxy URL (bypasses discovery). Format: host:port */
386
+ proxyUrl?: string;
387
+ /** Request timeout in ms. Default: 120000 */
388
+ timeout?: number;
389
+ /** Optional TON JSON-RPC endpoint for on-chain operations (registration, wallet tx). */
390
+ tonEndpoint?: string;
391
+ /** Optional TON v4 endpoint used for wallet transaction sending. */
392
+ tonV4Endpoint?: string;
393
+ /** Secret string for short auth. Auto-generated if not provided. */
394
+ secretString?: string;
395
+ /** Use TLS for proxy connection. Default: true */
396
+ useTls?: boolean;
397
+ /** PEM-encoded TLS client certificate for RA-TLS / mTLS authentication */
398
+ tlsCert?: string | Buffer;
399
+ /** PEM-encoded TLS client private key for RA-TLS / mTLS authentication */
400
+ tlsKey?: string | Buffer;
401
+ /** Dynamic provider for RA-TLS credentials (e.g. sidecar, file rotation). */
402
+ attestationProvider?: AttestationProvider;
403
+ /**
404
+ * If true, automatically perform on-chain long-auth registration when proxy requests it.
405
+ * This sends a TON transaction from the mnemonic wallet.
406
+ * Default: true
407
+ */
408
+ autoRegisterOnLongAuth?: boolean;
409
+ /** Amount in TON to attach to auto long-auth registration tx. Default: "1" */
410
+ longAuthRegisterAmountTon?: string;
411
+ }
412
+ declare class Cocoon {
413
+ readonly chat: {
414
+ completions: Completions;
415
+ };
416
+ readonly models: Models;
417
+ private readonly mnemonicWallet;
418
+ private readonly discovery;
419
+ private session;
420
+ private connecting;
421
+ private readonly options;
422
+ constructor(options: CocoonOptions);
423
+ /**
424
+ * Explicitly connect to a proxy. Called lazily on first API call if not called manually.
425
+ */
426
+ connect(): Promise<void>;
427
+ /**
428
+ * Disconnect from the proxy.
429
+ */
430
+ disconnect(): Promise<void>;
431
+ private ensureSession;
432
+ private createSession;
433
+ }
434
+
435
+ /**
436
+ * Error classes for the Cocoon SDK.
437
+ */
438
+ declare class CocoonError extends Error {
439
+ constructor(message: string);
440
+ }
441
+ declare class ConnectionError extends CocoonError {
442
+ readonly cause?: Error | undefined;
443
+ constructor(message: string, cause?: Error | undefined);
444
+ }
445
+ declare class ProtocolError extends CocoonError {
446
+ readonly code?: number | undefined;
447
+ constructor(message: string, code?: number | undefined);
448
+ }
449
+ declare class APIError extends CocoonError {
450
+ readonly statusCode: number;
451
+ readonly errorBody?: unknown | undefined;
452
+ constructor(message: string, statusCode: number, errorBody?: unknown | undefined);
453
+ }
454
+ declare class AuthenticationError extends CocoonError {
455
+ readonly code?: number | undefined;
456
+ constructor(message: string, code?: number | undefined);
457
+ }
458
+ declare class TimeoutError extends CocoonError {
459
+ constructor(message?: string);
460
+ }
461
+
462
+ export { APIError, type AttestationContext, type AttestationProvider, AuthenticationError, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionChunk, type ChatCompletionChunkChoice, type ChatCompletionChunkDelta, type ChatCompletionCreateParams, type ChatMessage, type ChatRole, type ClientTlsCredentials, Cocoon, CocoonError, type CocoonOptions, ConnectionError, FileAttestationProvider, type FinishReason, type Model, type ModelList, ProtocolError, StaticAttestationProvider, Stream, TimeoutError, type Usage };