wsbridge-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/LICENSE +21 -0
- package/README.md +405 -0
- package/dist/index.cjs +1207 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1764 -0
- package/dist/index.d.ts +1764 -0
- package/dist/index.js +1181 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/transport/base.ts
|
|
4
|
+
var TransportState = /* @__PURE__ */ ((TransportState3) => {
|
|
5
|
+
TransportState3["DISCONNECTED"] = "DISCONNECTED";
|
|
6
|
+
TransportState3["CONNECTING"] = "CONNECTING";
|
|
7
|
+
TransportState3["CONNECTED"] = "CONNECTED";
|
|
8
|
+
TransportState3["RECONNECTING"] = "RECONNECTING";
|
|
9
|
+
TransportState3["DESTROYED"] = "DESTROYED";
|
|
10
|
+
return TransportState3;
|
|
11
|
+
})(TransportState || {});
|
|
12
|
+
var AbstractTransport = class {
|
|
13
|
+
listeners = /* @__PURE__ */ new Map();
|
|
14
|
+
/** Whether the transport is currently connected. */
|
|
15
|
+
get isConnected() {
|
|
16
|
+
return this.state === "CONNECTED" /* CONNECTED */;
|
|
17
|
+
}
|
|
18
|
+
/** Register an event listener. */
|
|
19
|
+
on(event, listener) {
|
|
20
|
+
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
21
|
+
this.listeners.get(event).add(listener);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
/** Remove an event listener. */
|
|
25
|
+
off(event, listener) {
|
|
26
|
+
this.listeners.get(event)?.delete(listener);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
/** Register a one-shot event listener that auto-removes after the first call. */
|
|
30
|
+
once(event, listener) {
|
|
31
|
+
const wrapper = ((...args) => {
|
|
32
|
+
this.off(event, wrapper);
|
|
33
|
+
listener(...args);
|
|
34
|
+
});
|
|
35
|
+
return this.on(event, wrapper);
|
|
36
|
+
}
|
|
37
|
+
emit(event, ...args) {
|
|
38
|
+
const fns = this.listeners.get(event);
|
|
39
|
+
if (fns) for (const fn of fns) fn(...args);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/errors.ts
|
|
44
|
+
var Web3SocketsError = class _Web3SocketsError extends Error {
|
|
45
|
+
constructor(message, code) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.name = "Web3SocketsError";
|
|
49
|
+
Object.setPrototypeOf(this, _Web3SocketsError.prototype);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var ConnectionError = class _ConnectionError extends Web3SocketsError {
|
|
53
|
+
constructor(message, url) {
|
|
54
|
+
super(message, "CONNECTION_ERROR");
|
|
55
|
+
this.url = url;
|
|
56
|
+
this.name = "ConnectionError";
|
|
57
|
+
Object.setPrototypeOf(this, _ConnectionError.prototype);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var ConnectionClosedError = class _ConnectionClosedError extends Web3SocketsError {
|
|
61
|
+
constructor(closeCode, reason) {
|
|
62
|
+
super(reason || `Connection closed with code ${closeCode}`, "CONNECTION_CLOSED");
|
|
63
|
+
this.closeCode = closeCode;
|
|
64
|
+
this.name = "ConnectionClosedError";
|
|
65
|
+
Object.setPrototypeOf(this, _ConnectionClosedError.prototype);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var RpcError = class _RpcError extends Web3SocketsError {
|
|
69
|
+
constructor(message, rpcCode) {
|
|
70
|
+
super(message, "RPC_ERROR");
|
|
71
|
+
this.rpcCode = rpcCode;
|
|
72
|
+
this.name = "RpcError";
|
|
73
|
+
Object.setPrototypeOf(this, _RpcError.prototype);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var TimeoutError = class _TimeoutError extends Web3SocketsError {
|
|
77
|
+
constructor(method, timeoutMs) {
|
|
78
|
+
super(`Request "${method}" timed out after ${timeoutMs}ms`, "TIMEOUT");
|
|
79
|
+
this.name = "TimeoutError";
|
|
80
|
+
Object.setPrototypeOf(this, _TimeoutError.prototype);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var ValidationError = class _ValidationError extends Web3SocketsError {
|
|
84
|
+
constructor(message) {
|
|
85
|
+
super(message, "VALIDATION_ERROR");
|
|
86
|
+
this.name = "ValidationError";
|
|
87
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/transport/ws-transport.ts
|
|
92
|
+
var WsTransport = class extends AbstractTransport {
|
|
93
|
+
ws = null;
|
|
94
|
+
url;
|
|
95
|
+
autoReconnect;
|
|
96
|
+
reconnectDelay;
|
|
97
|
+
reconnectMaxDelay;
|
|
98
|
+
reconnectMaxRetries;
|
|
99
|
+
keepaliveInterval;
|
|
100
|
+
reconnectAttempt = 0;
|
|
101
|
+
reconnectTimer = null;
|
|
102
|
+
keepaliveTimer = null;
|
|
103
|
+
intentionalClose = false;
|
|
104
|
+
_state = "DISCONNECTED" /* DISCONNECTED */;
|
|
105
|
+
constructor(options = {}) {
|
|
106
|
+
super();
|
|
107
|
+
this.url = options.url ?? "ws://127.0.0.1:8081";
|
|
108
|
+
this.autoReconnect = options.autoReconnect ?? true;
|
|
109
|
+
this.reconnectDelay = options.reconnectDelay ?? 1e3;
|
|
110
|
+
this.reconnectMaxDelay = options.reconnectMaxDelay ?? 3e4;
|
|
111
|
+
this.reconnectMaxRetries = options.reconnectMaxRetries ?? Infinity;
|
|
112
|
+
this.keepaliveInterval = options.keepaliveInterval ?? 3e4;
|
|
113
|
+
}
|
|
114
|
+
/** Current transport state. */
|
|
115
|
+
get state() {
|
|
116
|
+
return this._state;
|
|
117
|
+
}
|
|
118
|
+
/** Open a WebSocket connection. Throws if already connecting or destroyed. */
|
|
119
|
+
async connect() {
|
|
120
|
+
if (this._state === "CONNECTED" /* CONNECTED */) return;
|
|
121
|
+
if (this._state === "CONNECTING" /* CONNECTING */ || this._state === "RECONNECTING" /* RECONNECTING */) {
|
|
122
|
+
throw new ConnectionError("Already connecting", this.url);
|
|
123
|
+
}
|
|
124
|
+
if (this._state === "DESTROYED" /* DESTROYED */) {
|
|
125
|
+
throw new ConnectionError("Transport destroyed", this.url);
|
|
126
|
+
}
|
|
127
|
+
this.intentionalClose = false;
|
|
128
|
+
this.setState("CONNECTING" /* CONNECTING */);
|
|
129
|
+
const WebSocketImpl = await this.getWebSocketImpl();
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
try {
|
|
132
|
+
this.ws = new WebSocketImpl(this.url);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
this.setState("DISCONNECTED" /* DISCONNECTED */);
|
|
135
|
+
reject(new ConnectionError(err.message, this.url));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.ws.addEventListener("close", (event) => {
|
|
139
|
+
this.stopKeepalive();
|
|
140
|
+
this.emit("close", event.code, event.reason);
|
|
141
|
+
if (!this.intentionalClose && this.autoReconnect && this._state !== "DESTROYED" /* DESTROYED */) {
|
|
142
|
+
this.scheduleReconnect();
|
|
143
|
+
} else if (this._state !== "DESTROYED" /* DESTROYED */) {
|
|
144
|
+
this.setState("DISCONNECTED" /* DISCONNECTED */);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const onOpen = () => {
|
|
148
|
+
this.ws?.removeEventListener("error", onError);
|
|
149
|
+
this.reconnectAttempt = 0;
|
|
150
|
+
this.setState("CONNECTED" /* CONNECTED */);
|
|
151
|
+
this.setupListeners();
|
|
152
|
+
this.startKeepalive();
|
|
153
|
+
this.emit("open");
|
|
154
|
+
resolve();
|
|
155
|
+
};
|
|
156
|
+
const onError = (event) => {
|
|
157
|
+
this.ws?.removeEventListener("open", onOpen);
|
|
158
|
+
const err = new ConnectionError(
|
|
159
|
+
event.message || "WebSocket connection failed",
|
|
160
|
+
this.url
|
|
161
|
+
);
|
|
162
|
+
reject(err);
|
|
163
|
+
};
|
|
164
|
+
this.ws.addEventListener("open", onOpen);
|
|
165
|
+
this.ws.addEventListener("error", onError);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/** Close the connection without triggering auto-reconnect. */
|
|
169
|
+
disconnect() {
|
|
170
|
+
this.intentionalClose = true;
|
|
171
|
+
this.clearReconnectTimer();
|
|
172
|
+
this.stopKeepalive();
|
|
173
|
+
if (this.ws) {
|
|
174
|
+
this.ws.close(1e3, "client disconnect");
|
|
175
|
+
this.ws = null;
|
|
176
|
+
}
|
|
177
|
+
if (this._state !== "DESTROYED" /* DESTROYED */) {
|
|
178
|
+
this.setState("DISCONNECTED" /* DISCONNECTED */);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Permanently destroy the transport. No further connect() calls are allowed. */
|
|
182
|
+
destroy() {
|
|
183
|
+
this.disconnect();
|
|
184
|
+
this.setState("DESTROYED" /* DESTROYED */);
|
|
185
|
+
this.listeners.clear();
|
|
186
|
+
}
|
|
187
|
+
/** Send data over the WebSocket. Throws if not connected. */
|
|
188
|
+
send(data) {
|
|
189
|
+
if (this._state !== "CONNECTED" /* CONNECTED */ || !this.ws) {
|
|
190
|
+
throw new ConnectionError("Not connected", this.url);
|
|
191
|
+
}
|
|
192
|
+
this.ws.send(data);
|
|
193
|
+
}
|
|
194
|
+
// ── Private helpers ──────────────────────────────────────────────
|
|
195
|
+
setState(next) {
|
|
196
|
+
const prev = this._state;
|
|
197
|
+
if (prev === next) return;
|
|
198
|
+
this._state = next;
|
|
199
|
+
this.emit("stateChange", next, prev);
|
|
200
|
+
}
|
|
201
|
+
setupListeners() {
|
|
202
|
+
if (!this.ws) return;
|
|
203
|
+
this.ws.addEventListener("message", (event) => {
|
|
204
|
+
const data = typeof event.data === "string" ? event.data : event.data.toString();
|
|
205
|
+
this.emit("message", data);
|
|
206
|
+
});
|
|
207
|
+
this.ws.addEventListener("error", () => {
|
|
208
|
+
this.emit("error", new ConnectionError("WebSocket error", this.url));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
scheduleReconnect() {
|
|
212
|
+
if (this.reconnectAttempt >= this.reconnectMaxRetries) {
|
|
213
|
+
this.setState("DISCONNECTED" /* DISCONNECTED */);
|
|
214
|
+
this.emit("reconnectFailed");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.setState("RECONNECTING" /* RECONNECTING */);
|
|
218
|
+
const delay = Math.min(
|
|
219
|
+
this.reconnectDelay * Math.pow(2, this.reconnectAttempt),
|
|
220
|
+
this.reconnectMaxDelay
|
|
221
|
+
);
|
|
222
|
+
this.reconnectAttempt++;
|
|
223
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
224
|
+
this._state = "DISCONNECTED" /* DISCONNECTED */;
|
|
225
|
+
try {
|
|
226
|
+
await this.connect();
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
}, delay);
|
|
230
|
+
}
|
|
231
|
+
clearReconnectTimer() {
|
|
232
|
+
if (this.reconnectTimer) {
|
|
233
|
+
clearTimeout(this.reconnectTimer);
|
|
234
|
+
this.reconnectTimer = null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
startKeepalive() {
|
|
238
|
+
if (this.keepaliveInterval <= 0) return;
|
|
239
|
+
if (typeof globalThis.WebSocket !== "undefined" && this.ws instanceof globalThis.WebSocket) return;
|
|
240
|
+
this.keepaliveTimer = setInterval(() => {
|
|
241
|
+
if (this.ws && this._state === "CONNECTED" /* CONNECTED */) {
|
|
242
|
+
try {
|
|
243
|
+
this.ws.ping();
|
|
244
|
+
} catch {
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}, this.keepaliveInterval);
|
|
248
|
+
}
|
|
249
|
+
stopKeepalive() {
|
|
250
|
+
if (this.keepaliveTimer) {
|
|
251
|
+
clearInterval(this.keepaliveTimer);
|
|
252
|
+
this.keepaliveTimer = null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async getWebSocketImpl() {
|
|
256
|
+
if (typeof globalThis.WebSocket !== "undefined") {
|
|
257
|
+
return globalThis.WebSocket;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
const { default: WS } = await import('ws');
|
|
261
|
+
return WS;
|
|
262
|
+
} catch {
|
|
263
|
+
throw new ConnectionError(
|
|
264
|
+
'WebSocket implementation not found. Install the "ws" package for Node.js.',
|
|
265
|
+
this.url
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// src/transport/ipc-transport.ts
|
|
272
|
+
var IpcTransport = class extends AbstractTransport {
|
|
273
|
+
unsubscribe = null;
|
|
274
|
+
_state = "DISCONNECTED" /* DISCONNECTED */;
|
|
275
|
+
/** Current transport state. */
|
|
276
|
+
get state() {
|
|
277
|
+
return this._state;
|
|
278
|
+
}
|
|
279
|
+
/** Connect to the IPC bridge via `window.ton.adnl`. */
|
|
280
|
+
async connect() {
|
|
281
|
+
if (this._state === "CONNECTED" /* CONNECTED */) return;
|
|
282
|
+
if (this._state === "CONNECTING" /* CONNECTING */) {
|
|
283
|
+
throw new ConnectionError("Already connecting", "ipc");
|
|
284
|
+
}
|
|
285
|
+
if (this._state === "DESTROYED" /* DESTROYED */) {
|
|
286
|
+
throw new ConnectionError("Transport destroyed", "ipc");
|
|
287
|
+
}
|
|
288
|
+
if (typeof window === "undefined" || !window.ton?.adnl) {
|
|
289
|
+
throw new ConnectionError("window.ton.adnl not available", "ipc");
|
|
290
|
+
}
|
|
291
|
+
this.setState("CONNECTING" /* CONNECTING */);
|
|
292
|
+
this.unsubscribe = window.ton.adnl.onMessage((data) => {
|
|
293
|
+
this.emit("message", data);
|
|
294
|
+
});
|
|
295
|
+
this.setState("CONNECTED" /* CONNECTED */);
|
|
296
|
+
this.emit("open");
|
|
297
|
+
}
|
|
298
|
+
/** Disconnect from the IPC bridge. */
|
|
299
|
+
disconnect() {
|
|
300
|
+
if (this.unsubscribe) {
|
|
301
|
+
this.unsubscribe();
|
|
302
|
+
this.unsubscribe = null;
|
|
303
|
+
}
|
|
304
|
+
if (this._state !== "DESTROYED" /* DESTROYED */) {
|
|
305
|
+
this.setState("DISCONNECTED" /* DISCONNECTED */);
|
|
306
|
+
}
|
|
307
|
+
this.emit("close", 1e3, "client disconnect");
|
|
308
|
+
}
|
|
309
|
+
/** Permanently destroy the transport. */
|
|
310
|
+
destroy() {
|
|
311
|
+
this.disconnect();
|
|
312
|
+
this.setState("DESTROYED" /* DESTROYED */);
|
|
313
|
+
this.listeners.clear();
|
|
314
|
+
}
|
|
315
|
+
/** Send data over the IPC bridge. */
|
|
316
|
+
send(data) {
|
|
317
|
+
if (this._state !== "CONNECTED" /* CONNECTED */) {
|
|
318
|
+
throw new ConnectionError("IPC transport not connected", "ipc");
|
|
319
|
+
}
|
|
320
|
+
if (typeof window === "undefined" || !window.ton?.adnl) {
|
|
321
|
+
throw new ConnectionError("window.ton.adnl not available", "ipc");
|
|
322
|
+
}
|
|
323
|
+
window.ton.adnl.send(data);
|
|
324
|
+
}
|
|
325
|
+
setState(next) {
|
|
326
|
+
const prev = this._state;
|
|
327
|
+
if (prev === next) return;
|
|
328
|
+
this._state = next;
|
|
329
|
+
this.emit("stateChange", next, prev);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// src/transport/index.ts
|
|
334
|
+
function createTransport(options) {
|
|
335
|
+
if (typeof window !== "undefined" && window.ton?.adnl) {
|
|
336
|
+
return new IpcTransport();
|
|
337
|
+
}
|
|
338
|
+
return new WsTransport(options);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/rpc/rpc-engine.ts
|
|
342
|
+
var idCounter = 0;
|
|
343
|
+
function generateId() {
|
|
344
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
345
|
+
return crypto.randomUUID();
|
|
346
|
+
}
|
|
347
|
+
idCounter = (idCounter + 1) % 2147483648;
|
|
348
|
+
return String(idCounter);
|
|
349
|
+
}
|
|
350
|
+
var RpcEngine = class {
|
|
351
|
+
constructor(transport, options = {}) {
|
|
352
|
+
this.transport = transport;
|
|
353
|
+
this.requestTimeout = options.requestTimeout ?? 3e4;
|
|
354
|
+
this.logger = options.logger ?? null;
|
|
355
|
+
this.transport.on("message", (data) => this.handleMessage(data));
|
|
356
|
+
this.transport.on("close", () => this.rejectAll("Connection closed"));
|
|
357
|
+
}
|
|
358
|
+
pending = /* @__PURE__ */ new Map();
|
|
359
|
+
pushHandler = null;
|
|
360
|
+
requestTimeout;
|
|
361
|
+
logger;
|
|
362
|
+
/** Register a handler for push events (subscriptions, ADNL). */
|
|
363
|
+
setPushHandler(handler) {
|
|
364
|
+
this.pushHandler = handler;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Send a JSON-RPC 2.0 request and return the result.
|
|
368
|
+
* @param method - The RPC method name.
|
|
369
|
+
* @param params - Optional parameters.
|
|
370
|
+
* @param options - Optional call options (abort signal).
|
|
371
|
+
*/
|
|
372
|
+
call(method, params, options) {
|
|
373
|
+
const id = generateId();
|
|
374
|
+
if (options?.signal?.aborted) {
|
|
375
|
+
return Promise.reject(new TimeoutError(method, 0));
|
|
376
|
+
}
|
|
377
|
+
return new Promise((resolve, reject) => {
|
|
378
|
+
const cleanup = () => {
|
|
379
|
+
const call2 = this.pending.get(id);
|
|
380
|
+
if (call2?.abortHandler && options?.signal) {
|
|
381
|
+
options.signal.removeEventListener("abort", call2.abortHandler);
|
|
382
|
+
}
|
|
383
|
+
this.pending.delete(id);
|
|
384
|
+
};
|
|
385
|
+
const timer = setTimeout(() => {
|
|
386
|
+
cleanup();
|
|
387
|
+
this.logger?.warn("RPC timeout", method, id);
|
|
388
|
+
reject(new TimeoutError(method, this.requestTimeout));
|
|
389
|
+
}, this.requestTimeout);
|
|
390
|
+
const call = {
|
|
391
|
+
resolve,
|
|
392
|
+
reject,
|
|
393
|
+
timer,
|
|
394
|
+
method
|
|
395
|
+
};
|
|
396
|
+
if (options?.signal) {
|
|
397
|
+
const abortHandler = () => {
|
|
398
|
+
clearTimeout(timer);
|
|
399
|
+
cleanup();
|
|
400
|
+
reject(new TimeoutError(method, 0));
|
|
401
|
+
};
|
|
402
|
+
call.abortHandler = abortHandler;
|
|
403
|
+
call.signal = options.signal;
|
|
404
|
+
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
405
|
+
}
|
|
406
|
+
this.pending.set(id, call);
|
|
407
|
+
const msg = JSON.stringify({ jsonrpc: "2.0", id, method, params: params ?? {} });
|
|
408
|
+
this.logger?.debug("RPC \u2192", method, id);
|
|
409
|
+
try {
|
|
410
|
+
this.transport.send(msg);
|
|
411
|
+
} catch (err) {
|
|
412
|
+
clearTimeout(timer);
|
|
413
|
+
cleanup();
|
|
414
|
+
reject(err);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
handleMessage(raw) {
|
|
419
|
+
let msg;
|
|
420
|
+
try {
|
|
421
|
+
msg = JSON.parse(raw);
|
|
422
|
+
} catch {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (msg.id != null && this.pending.has(String(msg.id))) {
|
|
426
|
+
const id = String(msg.id);
|
|
427
|
+
const call = this.pending.get(id);
|
|
428
|
+
clearTimeout(call.timer);
|
|
429
|
+
if (call.abortHandler && call.signal) {
|
|
430
|
+
call.signal.removeEventListener("abort", call.abortHandler);
|
|
431
|
+
}
|
|
432
|
+
this.pending.delete(id);
|
|
433
|
+
if (msg.error) {
|
|
434
|
+
this.logger?.error("RPC error", call.method, msg.error);
|
|
435
|
+
call.reject(new RpcError(msg.error.message, msg.error.code));
|
|
436
|
+
} else {
|
|
437
|
+
this.logger?.debug("RPC \u2190", call.method, id);
|
|
438
|
+
call.resolve(msg.result);
|
|
439
|
+
}
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (msg.event && this.pushHandler) {
|
|
443
|
+
this.pushHandler(msg.event, msg.data);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
rejectAll(reason) {
|
|
447
|
+
for (const [, call] of this.pending) {
|
|
448
|
+
clearTimeout(call.timer);
|
|
449
|
+
call.reject(new ConnectionClosedError(1006, `${reason} (pending: ${call.method})`));
|
|
450
|
+
}
|
|
451
|
+
this.pending.clear();
|
|
452
|
+
}
|
|
453
|
+
/** Destroy the engine, rejecting all pending calls. */
|
|
454
|
+
destroy() {
|
|
455
|
+
this.rejectAll("RPC engine destroyed");
|
|
456
|
+
this.pushHandler = null;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// src/subscription/subscription.ts
|
|
461
|
+
var DEFAULT_HIGH_WATER_MARK = 1e3;
|
|
462
|
+
var Subscription = class {
|
|
463
|
+
constructor(event, onUnsubscribe, options) {
|
|
464
|
+
this.event = event;
|
|
465
|
+
this.onUnsubscribe = onUnsubscribe;
|
|
466
|
+
this.highWaterMark = options?.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;
|
|
467
|
+
}
|
|
468
|
+
listeners = /* @__PURE__ */ new Set();
|
|
469
|
+
errorListeners = /* @__PURE__ */ new Set();
|
|
470
|
+
_active = true;
|
|
471
|
+
_iteratorResolve = null;
|
|
472
|
+
highWaterMark;
|
|
473
|
+
/** Whether the subscription is still active. */
|
|
474
|
+
get active() {
|
|
475
|
+
return this._active;
|
|
476
|
+
}
|
|
477
|
+
on(event, listener) {
|
|
478
|
+
if (event === "data") this.listeners.add(listener);
|
|
479
|
+
else if (event === "error") this.errorListeners.add(listener);
|
|
480
|
+
return this;
|
|
481
|
+
}
|
|
482
|
+
off(event, listener) {
|
|
483
|
+
if (event === "data") this.listeners.delete(listener);
|
|
484
|
+
else if (event === "error") this.errorListeners.delete(listener);
|
|
485
|
+
return this;
|
|
486
|
+
}
|
|
487
|
+
/** @internal Called by SubscriptionManager to deliver push events. */
|
|
488
|
+
_deliver(data) {
|
|
489
|
+
if (!this._active) return;
|
|
490
|
+
for (const fn of this.listeners) fn(data);
|
|
491
|
+
}
|
|
492
|
+
/** @internal Called by SubscriptionManager on error. */
|
|
493
|
+
_error(error) {
|
|
494
|
+
for (const fn of this.errorListeners) fn(error);
|
|
495
|
+
}
|
|
496
|
+
/** Unsubscribe, releasing all listeners and unblocking any active async iterator. */
|
|
497
|
+
async unsubscribe() {
|
|
498
|
+
if (!this._active) return;
|
|
499
|
+
this._active = false;
|
|
500
|
+
this.listeners.clear();
|
|
501
|
+
this.errorListeners.clear();
|
|
502
|
+
if (this._iteratorResolve) {
|
|
503
|
+
this._iteratorResolve();
|
|
504
|
+
this._iteratorResolve = null;
|
|
505
|
+
}
|
|
506
|
+
this.onUnsubscribe();
|
|
507
|
+
}
|
|
508
|
+
/** Consume events as an async iterable. Respects backpressure via highWaterMark. */
|
|
509
|
+
async *[Symbol.asyncIterator]() {
|
|
510
|
+
const buffer = [];
|
|
511
|
+
let resolve = null;
|
|
512
|
+
const listener = (data) => {
|
|
513
|
+
buffer.push(data);
|
|
514
|
+
while (buffer.length > this.highWaterMark) {
|
|
515
|
+
buffer.shift();
|
|
516
|
+
}
|
|
517
|
+
if (resolve) {
|
|
518
|
+
resolve();
|
|
519
|
+
resolve = null;
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
this.on("data", listener);
|
|
523
|
+
try {
|
|
524
|
+
while (this._active) {
|
|
525
|
+
if (buffer.length > 0) {
|
|
526
|
+
yield buffer.shift();
|
|
527
|
+
} else {
|
|
528
|
+
await new Promise((r) => {
|
|
529
|
+
resolve = r;
|
|
530
|
+
this._iteratorResolve = r;
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
} finally {
|
|
535
|
+
this._iteratorResolve = null;
|
|
536
|
+
this.off("data", listener);
|
|
537
|
+
await this.unsubscribe();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// src/subscription/manager.ts
|
|
543
|
+
var SubscriptionManager = class {
|
|
544
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
545
|
+
adnlListeners = /* @__PURE__ */ new Map();
|
|
546
|
+
subscriptionIds = /* @__PURE__ */ new Map();
|
|
547
|
+
/** Register a subscription for a push event type. */
|
|
548
|
+
register(eventType, onUnsubscribe, options) {
|
|
549
|
+
const sub = new Subscription(eventType, () => {
|
|
550
|
+
const subs = this.subscriptions.get(eventType);
|
|
551
|
+
if (subs) {
|
|
552
|
+
subs.delete(sub);
|
|
553
|
+
if (subs.size === 0) this.subscriptions.delete(eventType);
|
|
554
|
+
}
|
|
555
|
+
for (const [id, s] of this.subscriptionIds) {
|
|
556
|
+
if (s === sub) {
|
|
557
|
+
this.subscriptionIds.delete(id);
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
onUnsubscribe();
|
|
562
|
+
}, options);
|
|
563
|
+
if (!this.subscriptions.has(eventType)) {
|
|
564
|
+
this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
|
|
565
|
+
}
|
|
566
|
+
this.subscriptions.get(eventType).add(sub);
|
|
567
|
+
return sub;
|
|
568
|
+
}
|
|
569
|
+
/** Store the bridge-assigned subscription ID for a subscription. */
|
|
570
|
+
setSubscriptionId(subscriptionId, subscription) {
|
|
571
|
+
this.subscriptionIds.set(subscriptionId, subscription);
|
|
572
|
+
}
|
|
573
|
+
/** Get a subscription by its bridge-assigned ID. */
|
|
574
|
+
getBySubscriptionId(subscriptionId) {
|
|
575
|
+
return this.subscriptionIds.get(subscriptionId);
|
|
576
|
+
}
|
|
577
|
+
/** Route a push event to all matching subscriptions. */
|
|
578
|
+
handleEvent(event, data) {
|
|
579
|
+
const subs = this.subscriptions.get(event);
|
|
580
|
+
if (subs) {
|
|
581
|
+
for (const sub of subs) sub._deliver(data);
|
|
582
|
+
}
|
|
583
|
+
const listeners = this.adnlListeners.get(event);
|
|
584
|
+
if (listeners) {
|
|
585
|
+
for (const fn of listeners) fn(data);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
/** Register an ADNL event listener. */
|
|
589
|
+
onAdnl(event, listener) {
|
|
590
|
+
if (!this.adnlListeners.has(event)) {
|
|
591
|
+
this.adnlListeners.set(event, /* @__PURE__ */ new Set());
|
|
592
|
+
}
|
|
593
|
+
this.adnlListeners.get(event).add(listener);
|
|
594
|
+
}
|
|
595
|
+
/** Remove an ADNL event listener. */
|
|
596
|
+
offAdnl(event, listener) {
|
|
597
|
+
this.adnlListeners.get(event)?.delete(listener);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Returns all active subscriptions as event-type entries for resubscription after reconnect.
|
|
601
|
+
* The caller (typically the client) should iterate this list and re-send subscribe RPCs
|
|
602
|
+
* to the bridge, then update subscription IDs via setSubscriptionId().
|
|
603
|
+
*/
|
|
604
|
+
getResubscribeEntries() {
|
|
605
|
+
const entries = [];
|
|
606
|
+
for (const [eventType, subs] of this.subscriptions) {
|
|
607
|
+
for (const sub of subs) {
|
|
608
|
+
if (sub.active) {
|
|
609
|
+
entries.push({ eventType, subscription: sub });
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return entries;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Resubscribe all active subscriptions after a reconnect.
|
|
617
|
+
* Accepts a callback that performs the actual RPC subscribe call for each entry
|
|
618
|
+
* and returns the new subscription_id from the bridge.
|
|
619
|
+
* Old subscription IDs are cleared and replaced with new ones.
|
|
620
|
+
*/
|
|
621
|
+
async resubscribe(doSubscribe) {
|
|
622
|
+
this.subscriptionIds.clear();
|
|
623
|
+
const entries = this.getResubscribeEntries();
|
|
624
|
+
for (const { eventType, subscription } of entries) {
|
|
625
|
+
const newId = await doSubscribe(eventType);
|
|
626
|
+
this.subscriptionIds.set(newId, subscription);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/** Number of active subscriptions (for debugging). */
|
|
630
|
+
get activeCount() {
|
|
631
|
+
let count = 0;
|
|
632
|
+
for (const subs of this.subscriptions.values()) count += subs.size;
|
|
633
|
+
return count;
|
|
634
|
+
}
|
|
635
|
+
/** Clear all subscriptions and ADNL listeners (e.g. on disconnect). */
|
|
636
|
+
clear() {
|
|
637
|
+
for (const [, subs] of this.subscriptions) {
|
|
638
|
+
for (const sub of subs) {
|
|
639
|
+
sub._error(new Error("Connection closed"));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
this.subscriptions.clear();
|
|
643
|
+
this.adnlListeners.clear();
|
|
644
|
+
this.subscriptionIds.clear();
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/namespaces/base.ts
|
|
649
|
+
var BaseNamespace = class {
|
|
650
|
+
constructor(rpc) {
|
|
651
|
+
this.rpc = rpc;
|
|
652
|
+
}
|
|
653
|
+
/** Send a typed JSON-RPC call through the engine. */
|
|
654
|
+
call(method, params, options) {
|
|
655
|
+
return this.rpc.call(method, params, options);
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
// src/namespaces/dht.ts
|
|
660
|
+
var DhtNamespace = class extends BaseNamespace {
|
|
661
|
+
/** Look up ADNL addresses for a given key. */
|
|
662
|
+
findAddresses(params, options) {
|
|
663
|
+
return this.call("dht.findAddresses", params, options);
|
|
664
|
+
}
|
|
665
|
+
/** Find overlay nodes for a given overlay key. */
|
|
666
|
+
findOverlayNodes(params, options) {
|
|
667
|
+
return this.call("dht.findOverlayNodes", params, options);
|
|
668
|
+
}
|
|
669
|
+
/** Discover tunnel relay nodes from the DHT. */
|
|
670
|
+
findTunnelNodes(options) {
|
|
671
|
+
return this.call("dht.findTunnelNodes", void 0, options);
|
|
672
|
+
}
|
|
673
|
+
/** Look up an arbitrary value in the DHT. */
|
|
674
|
+
findValue(params, options) {
|
|
675
|
+
return this.call("dht.findValue", params, options);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// src/namespaces/lite.ts
|
|
680
|
+
var LiteNamespace = class extends BaseNamespace {
|
|
681
|
+
manager;
|
|
682
|
+
constructor(rpc, manager) {
|
|
683
|
+
super(rpc);
|
|
684
|
+
this.manager = manager;
|
|
685
|
+
}
|
|
686
|
+
/** Get the latest masterchain block info. */
|
|
687
|
+
getMasterchainInfo(options) {
|
|
688
|
+
return this.call("lite.getMasterchainInfo", void 0, options);
|
|
689
|
+
}
|
|
690
|
+
/** Get the state of an account. */
|
|
691
|
+
getAccountState(params, options) {
|
|
692
|
+
return this.call("lite.getAccountState", params, options);
|
|
693
|
+
}
|
|
694
|
+
/** Run a get-method on a smart contract. */
|
|
695
|
+
runMethod(params, options) {
|
|
696
|
+
return this.call("lite.runMethod", params, options);
|
|
697
|
+
}
|
|
698
|
+
/** Send an external message (fire and forget). */
|
|
699
|
+
sendMessage(params, options) {
|
|
700
|
+
return this.call("lite.sendMessage", params, options);
|
|
701
|
+
}
|
|
702
|
+
/** Send an external message and wait for processing confirmation. */
|
|
703
|
+
sendMessageWait(params, options) {
|
|
704
|
+
return this.call("lite.sendMessageWait", params, options);
|
|
705
|
+
}
|
|
706
|
+
/** Get account transactions with optional pagination. */
|
|
707
|
+
getTransactions(params, options) {
|
|
708
|
+
return this.call("lite.getTransactions", params, options);
|
|
709
|
+
}
|
|
710
|
+
/** Get a single transaction by address and LT. */
|
|
711
|
+
getTransaction(params, options) {
|
|
712
|
+
return this.call("lite.getTransaction", params, options);
|
|
713
|
+
}
|
|
714
|
+
/** Find a transaction by its inbound message hash. */
|
|
715
|
+
findTxByInMsgHash(params, options) {
|
|
716
|
+
return this.call("lite.findTxByInMsgHash", params, options);
|
|
717
|
+
}
|
|
718
|
+
/** Find a transaction by its outbound message hash. */
|
|
719
|
+
findTxByOutMsgHash(params, options) {
|
|
720
|
+
return this.call("lite.findTxByOutMsgHash", params, options);
|
|
721
|
+
}
|
|
722
|
+
/** Get the current liteserver time. */
|
|
723
|
+
getTime(options) {
|
|
724
|
+
return this.call("lite.getTime", void 0, options);
|
|
725
|
+
}
|
|
726
|
+
/** Look up a block by workchain, shard, and seqno. */
|
|
727
|
+
lookupBlock(params, options) {
|
|
728
|
+
return this.call("lite.lookupBlock", params, options);
|
|
729
|
+
}
|
|
730
|
+
/** Get short transaction references from a block. */
|
|
731
|
+
getBlockTransactions(params, options) {
|
|
732
|
+
return this.call("lite.getBlockTransactions", params, options);
|
|
733
|
+
}
|
|
734
|
+
/** Get current shard descriptors. */
|
|
735
|
+
getShards(options) {
|
|
736
|
+
return this.call("lite.getShards", void 0, options);
|
|
737
|
+
}
|
|
738
|
+
/** Get blockchain configuration parameters. */
|
|
739
|
+
getBlockchainConfig(params, options) {
|
|
740
|
+
return this.call("lite.getBlockchainConfig", params, options);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Send a message and subscribe to tx_confirmed / tx_timeout events.
|
|
744
|
+
* Returns a Subscription that delivers {@link SendAndWatchEvent} push events.
|
|
745
|
+
*/
|
|
746
|
+
async sendAndWatch(params, options) {
|
|
747
|
+
const confirmation = await this.call("lite.sendAndWatch", params, options);
|
|
748
|
+
if (!confirmation.watching) throw new Error("sendAndWatch rejected by bridge");
|
|
749
|
+
const subId = confirmation.subscription_id;
|
|
750
|
+
const sub = this.manager.register("tx_confirmed", () => {
|
|
751
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
755
|
+
const timeoutSub = this.manager.register("tx_timeout", () => {
|
|
756
|
+
});
|
|
757
|
+
this.manager.setSubscriptionId(`${subId}:timeout`, timeoutSub);
|
|
758
|
+
timeoutSub.on("data", (data) => sub._deliver(data));
|
|
759
|
+
return { confirmation, subscription: sub };
|
|
760
|
+
}
|
|
761
|
+
/** Get the raw block BOC. */
|
|
762
|
+
getBlockData(params, options) {
|
|
763
|
+
return this.call("lite.getBlockData", params, options);
|
|
764
|
+
}
|
|
765
|
+
/** Get the block header proof BOC. */
|
|
766
|
+
getBlockHeader(params, options) {
|
|
767
|
+
return this.call("lite.getBlockHeader", params, options);
|
|
768
|
+
}
|
|
769
|
+
/** Get library cells by their hashes. */
|
|
770
|
+
getLibraries(params, options) {
|
|
771
|
+
return this.call("lite.getLibraries", params, options);
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
// src/namespaces/subscribe.ts
|
|
776
|
+
var SubscribeNamespace = class extends BaseNamespace {
|
|
777
|
+
manager;
|
|
778
|
+
constructor(rpc, manager) {
|
|
779
|
+
super(rpc);
|
|
780
|
+
this.manager = manager;
|
|
781
|
+
}
|
|
782
|
+
/** Subscribe to transactions for a specific account. */
|
|
783
|
+
async transactions(params, options) {
|
|
784
|
+
const confirmation = await this.call("subscribe.transactions", params, options);
|
|
785
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
786
|
+
const subId = confirmation.subscription_id;
|
|
787
|
+
const sub = this.manager.register("transaction", () => {
|
|
788
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
792
|
+
return sub;
|
|
793
|
+
}
|
|
794
|
+
/** Subscribe to new masterchain blocks. */
|
|
795
|
+
async blocks(options) {
|
|
796
|
+
const confirmation = await this.call("subscribe.blocks", void 0, options);
|
|
797
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
798
|
+
const subId = confirmation.subscription_id;
|
|
799
|
+
const sub = this.manager.register("block", () => {
|
|
800
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
804
|
+
return sub;
|
|
805
|
+
}
|
|
806
|
+
/** Subscribe to account state changes. */
|
|
807
|
+
async accountState(params, options) {
|
|
808
|
+
const confirmation = await this.call("subscribe.accountState", params, options);
|
|
809
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
810
|
+
const subId = confirmation.subscription_id;
|
|
811
|
+
const sub = this.manager.register("account_state", () => {
|
|
812
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
816
|
+
return sub;
|
|
817
|
+
}
|
|
818
|
+
/** Subscribe to all new transactions across the blockchain. */
|
|
819
|
+
async newTransactions(options) {
|
|
820
|
+
const confirmation = await this.call("subscribe.newTransactions", void 0, options);
|
|
821
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
822
|
+
const subId = confirmation.subscription_id;
|
|
823
|
+
const sub = this.manager.register("new_transaction", () => {
|
|
824
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
828
|
+
return sub;
|
|
829
|
+
}
|
|
830
|
+
/** Subscribe to blockchain config parameter changes. */
|
|
831
|
+
async configChanges(params, options) {
|
|
832
|
+
const confirmation = await this.call("subscribe.configChanges", params, options);
|
|
833
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
834
|
+
const subId = confirmation.subscription_id;
|
|
835
|
+
const sub = this.manager.register("config_changed", () => {
|
|
836
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
840
|
+
return sub;
|
|
841
|
+
}
|
|
842
|
+
/** Subscribe to transactions across multiple accounts. */
|
|
843
|
+
async multiAccount(params, options) {
|
|
844
|
+
const confirmation = await this.call("subscribe.multiAccount", params, options);
|
|
845
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
846
|
+
const subId = confirmation.subscription_id;
|
|
847
|
+
const sub = this.manager.register("transaction", () => {
|
|
848
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
849
|
+
});
|
|
850
|
+
});
|
|
851
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
852
|
+
return sub;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Subscribe to transaction traces (internal message chains).
|
|
856
|
+
* Returns a subscription that delivers trace_started, trace_tx, trace_complete, and trace_timeout events.
|
|
857
|
+
*/
|
|
858
|
+
async trace(params, options) {
|
|
859
|
+
const confirmation = await this.call("subscribe.trace", params, options);
|
|
860
|
+
if (!confirmation.subscribed) throw new Error("Subscription rejected");
|
|
861
|
+
const subId = confirmation.subscription_id;
|
|
862
|
+
const sub = this.manager.register("trace_started", () => {
|
|
863
|
+
this.rpc.call("subscribe.unsubscribe", { subscription_id: subId }).catch(() => {
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
this.manager.setSubscriptionId(subId, sub);
|
|
867
|
+
const traceEvents = ["trace_tx", "trace_complete", "trace_timeout"];
|
|
868
|
+
for (const evt of traceEvents) {
|
|
869
|
+
const aux = this.manager.register(evt, () => {
|
|
870
|
+
});
|
|
871
|
+
aux.on("data", (data) => sub._deliver(data));
|
|
872
|
+
}
|
|
873
|
+
return sub;
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
// src/namespaces/jetton.ts
|
|
878
|
+
var JettonNamespace = class extends BaseNamespace {
|
|
879
|
+
/** Get jetton master data (supply, admin, content). */
|
|
880
|
+
getData(params, options) {
|
|
881
|
+
return this.call("jetton.getData", params, options);
|
|
882
|
+
}
|
|
883
|
+
/** Compute the jetton wallet address for an owner. */
|
|
884
|
+
getWalletAddress(params, options) {
|
|
885
|
+
return this.call("jetton.getWalletAddress", params, options);
|
|
886
|
+
}
|
|
887
|
+
/** Get balance of a jetton wallet. */
|
|
888
|
+
getBalance(params, options) {
|
|
889
|
+
return this.call("jetton.getBalance", params, options);
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
// src/namespaces/nft.ts
|
|
894
|
+
var NftNamespace = class extends BaseNamespace {
|
|
895
|
+
/** Get individual NFT item data. */
|
|
896
|
+
getData(params, options) {
|
|
897
|
+
return this.call("nft.getData", params, options);
|
|
898
|
+
}
|
|
899
|
+
/** Get NFT collection data. */
|
|
900
|
+
getCollectionData(params, options) {
|
|
901
|
+
return this.call("nft.getCollectionData", params, options);
|
|
902
|
+
}
|
|
903
|
+
/** Get the NFT item address by collection index. */
|
|
904
|
+
getAddressByIndex(params, options) {
|
|
905
|
+
return this.call("nft.getAddressByIndex", params, options);
|
|
906
|
+
}
|
|
907
|
+
/** Get royalty parameters for a collection. */
|
|
908
|
+
getRoyaltyParams(params, options) {
|
|
909
|
+
return this.call("nft.getRoyaltyParams", params, options);
|
|
910
|
+
}
|
|
911
|
+
/** Resolve the full content URI for an NFT by combining collection and individual content. */
|
|
912
|
+
getContent(params, options) {
|
|
913
|
+
return this.call("nft.getContent", params, options);
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
// src/namespaces/dns.ts
|
|
918
|
+
var DnsNamespace = class extends BaseNamespace {
|
|
919
|
+
/** Resolve a .ton domain to wallet, site ADNL, text records, etc. */
|
|
920
|
+
resolve(params, options) {
|
|
921
|
+
return this.call("dns.resolve", params, options);
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// src/namespaces/adnl.ts
|
|
926
|
+
var EVENT_LOOKUP = {
|
|
927
|
+
message: "adnl.message",
|
|
928
|
+
disconnected: "adnl.disconnected",
|
|
929
|
+
incomingConnection: "adnl.incomingConnection",
|
|
930
|
+
queryReceived: "adnl.queryReceived"
|
|
931
|
+
};
|
|
932
|
+
var AdnlNamespace = class extends BaseNamespace {
|
|
933
|
+
manager;
|
|
934
|
+
constructor(rpc, manager) {
|
|
935
|
+
super(rpc);
|
|
936
|
+
this.manager = manager;
|
|
937
|
+
}
|
|
938
|
+
/** Connect to a peer by IP address and public key. */
|
|
939
|
+
connect(params, options) {
|
|
940
|
+
return this.call("adnl.connect", params, options);
|
|
941
|
+
}
|
|
942
|
+
/** Connect to a peer by ADNL ID (resolved via DHT). */
|
|
943
|
+
connectByADNL(params, options) {
|
|
944
|
+
return this.call("adnl.connectByADNL", params, options);
|
|
945
|
+
}
|
|
946
|
+
/** Send an unreliable message to a connected peer. */
|
|
947
|
+
sendMessage(params, options) {
|
|
948
|
+
return this.call("adnl.sendMessage", params, options);
|
|
949
|
+
}
|
|
950
|
+
/** Ping a connected peer. */
|
|
951
|
+
ping(params, options) {
|
|
952
|
+
return this.call("adnl.ping", params, options);
|
|
953
|
+
}
|
|
954
|
+
/** Disconnect from a peer. */
|
|
955
|
+
disconnect(params, options) {
|
|
956
|
+
return this.call("adnl.disconnect", params, options);
|
|
957
|
+
}
|
|
958
|
+
/** List all connected ADNL peers. */
|
|
959
|
+
peers(options) {
|
|
960
|
+
return this.call("adnl.peers", void 0, options);
|
|
961
|
+
}
|
|
962
|
+
/** Send a TL query to a peer and wait for the response. */
|
|
963
|
+
query(params, options) {
|
|
964
|
+
return this.call("adnl.query", params, options);
|
|
965
|
+
}
|
|
966
|
+
/** Enable the query handler for a peer (receive queryReceived events). */
|
|
967
|
+
setQueryHandler(params, options) {
|
|
968
|
+
return this.call("adnl.setQueryHandler", params, options);
|
|
969
|
+
}
|
|
970
|
+
/** Answer a received query. */
|
|
971
|
+
answer(params, options) {
|
|
972
|
+
return this.call("adnl.answer", params, options);
|
|
973
|
+
}
|
|
974
|
+
/** Register a listener for ADNL push events. */
|
|
975
|
+
on(event, listener) {
|
|
976
|
+
this.manager.onAdnl(EVENT_LOOKUP[event], listener);
|
|
977
|
+
return this;
|
|
978
|
+
}
|
|
979
|
+
/** Remove a listener for ADNL push events. */
|
|
980
|
+
off(event, listener) {
|
|
981
|
+
this.manager.offAdnl(EVENT_LOOKUP[event], listener);
|
|
982
|
+
return this;
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
// src/namespaces/network.ts
|
|
987
|
+
var NetworkNamespace = class extends BaseNamespace {
|
|
988
|
+
/** Get bridge network information (DHT status, connected WS clients). */
|
|
989
|
+
info(options) {
|
|
990
|
+
return this.call("network.info", void 0, options);
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
// src/namespaces/overlay.ts
|
|
995
|
+
var EVENT_LOOKUP2 = {
|
|
996
|
+
broadcast: "overlay.broadcast",
|
|
997
|
+
message: "overlay.message",
|
|
998
|
+
queryReceived: "overlay.queryReceived"
|
|
999
|
+
};
|
|
1000
|
+
var OverlayNamespace = class extends BaseNamespace {
|
|
1001
|
+
manager;
|
|
1002
|
+
constructor(rpc, manager) {
|
|
1003
|
+
super(rpc);
|
|
1004
|
+
this.manager = manager;
|
|
1005
|
+
}
|
|
1006
|
+
/** Join an overlay network. */
|
|
1007
|
+
join(params, options) {
|
|
1008
|
+
return this.call("overlay.join", params, options);
|
|
1009
|
+
}
|
|
1010
|
+
/** Leave an overlay network. */
|
|
1011
|
+
leave(params, options) {
|
|
1012
|
+
return this.call("overlay.leave", params, options);
|
|
1013
|
+
}
|
|
1014
|
+
/** Get peers in an overlay network. */
|
|
1015
|
+
getPeers(params, options) {
|
|
1016
|
+
return this.call("overlay.getPeers", params, options);
|
|
1017
|
+
}
|
|
1018
|
+
/** Send a broadcast message to all overlay peers. */
|
|
1019
|
+
sendMessage(params, options) {
|
|
1020
|
+
return this.call("overlay.sendMessage", params, options);
|
|
1021
|
+
}
|
|
1022
|
+
/** Send a TL query through the overlay and wait for the response. */
|
|
1023
|
+
query(params, options) {
|
|
1024
|
+
return this.call("overlay.query", params, options);
|
|
1025
|
+
}
|
|
1026
|
+
/** Enable the query handler for an overlay (receive queryReceived events). */
|
|
1027
|
+
setQueryHandler(params, options) {
|
|
1028
|
+
return this.call("overlay.setQueryHandler", params, options);
|
|
1029
|
+
}
|
|
1030
|
+
/** Answer a received overlay query. */
|
|
1031
|
+
answer(params, options) {
|
|
1032
|
+
return this.call("overlay.answer", params, options);
|
|
1033
|
+
}
|
|
1034
|
+
/** Register a listener for overlay push events. */
|
|
1035
|
+
on(event, listener) {
|
|
1036
|
+
this.manager.onAdnl(EVENT_LOOKUP2[event], listener);
|
|
1037
|
+
return this;
|
|
1038
|
+
}
|
|
1039
|
+
/** Remove a listener for overlay push events. */
|
|
1040
|
+
off(event, listener) {
|
|
1041
|
+
this.manager.offAdnl(EVENT_LOOKUP2[event], listener);
|
|
1042
|
+
return this;
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
// src/namespaces/wallet.ts
|
|
1047
|
+
var WalletNamespace = class extends BaseNamespace {
|
|
1048
|
+
/** Get the current seqno of a wallet contract. */
|
|
1049
|
+
getSeqno(params, options) {
|
|
1050
|
+
return this.call("wallet.getSeqno", params, options);
|
|
1051
|
+
}
|
|
1052
|
+
/** Get the public key stored in a wallet contract. */
|
|
1053
|
+
getPublicKey(params, options) {
|
|
1054
|
+
return this.call("wallet.getPublicKey", params, options);
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
// src/namespaces/sbt.ts
|
|
1059
|
+
var SbtNamespace = class extends BaseNamespace {
|
|
1060
|
+
/** Get the authority address of a soulbound token. */
|
|
1061
|
+
getAuthorityAddress(params, options) {
|
|
1062
|
+
return this.call("sbt.getAuthorityAddress", params, options);
|
|
1063
|
+
}
|
|
1064
|
+
/** Get the revocation timestamp of a soulbound token (0 = not revoked). */
|
|
1065
|
+
getRevokedTime(params, options) {
|
|
1066
|
+
return this.call("sbt.getRevokedTime", params, options);
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
// src/namespaces/payment.ts
|
|
1071
|
+
var PaymentNamespace = class extends BaseNamespace {
|
|
1072
|
+
/** Get the state of a payment channel contract. */
|
|
1073
|
+
getChannelState(params, options) {
|
|
1074
|
+
return this.call("payment.getChannelState", params, options);
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
// src/client.ts
|
|
1079
|
+
var Web3SocketsClient = class {
|
|
1080
|
+
transport;
|
|
1081
|
+
rpc;
|
|
1082
|
+
subscriptionManager;
|
|
1083
|
+
clientListeners = /* @__PURE__ */ new Map();
|
|
1084
|
+
/** DHT namespace — distributed hash table lookups. */
|
|
1085
|
+
dht;
|
|
1086
|
+
/** Liteserver namespace — blockchain queries and transaction submission. */
|
|
1087
|
+
lite;
|
|
1088
|
+
/** Subscribe namespace — real-time event subscriptions. */
|
|
1089
|
+
subscribe;
|
|
1090
|
+
/** Jetton namespace — fungible token queries. */
|
|
1091
|
+
jetton;
|
|
1092
|
+
/** NFT namespace — non-fungible token queries. */
|
|
1093
|
+
nft;
|
|
1094
|
+
/** DNS namespace — TON DNS domain resolution. */
|
|
1095
|
+
dns;
|
|
1096
|
+
/** ADNL namespace — low-level peer-to-peer messaging. */
|
|
1097
|
+
adnl;
|
|
1098
|
+
/** Network namespace — bridge status. */
|
|
1099
|
+
network;
|
|
1100
|
+
/** Overlay namespace — P2P pubsub overlay networks. */
|
|
1101
|
+
overlay;
|
|
1102
|
+
/** Wallet namespace — standard wallet contract queries. */
|
|
1103
|
+
wallet;
|
|
1104
|
+
/** SBT namespace — soulbound token queries. */
|
|
1105
|
+
sbt;
|
|
1106
|
+
/** Payment namespace — payment channel queries. */
|
|
1107
|
+
payment;
|
|
1108
|
+
constructor(options = {}) {
|
|
1109
|
+
this.transport = options.transport ?? createTransport(options);
|
|
1110
|
+
this.rpc = new RpcEngine(this.transport, {
|
|
1111
|
+
requestTimeout: options.requestTimeout,
|
|
1112
|
+
logger: options.logger
|
|
1113
|
+
});
|
|
1114
|
+
this.subscriptionManager = new SubscriptionManager();
|
|
1115
|
+
this.rpc.setPushHandler((event, data) => {
|
|
1116
|
+
this.subscriptionManager.handleEvent(event, data);
|
|
1117
|
+
});
|
|
1118
|
+
this.transport.on("open", () => this.emitClient("connected"));
|
|
1119
|
+
this.transport.on("close", (code, reason) => {
|
|
1120
|
+
this.subscriptionManager.clear();
|
|
1121
|
+
this.emitClient("disconnected", code, reason);
|
|
1122
|
+
});
|
|
1123
|
+
this.transport.on("error", (err) => this.emitClient("error", err));
|
|
1124
|
+
this.transport.on("stateChange", (newState, oldState) => {
|
|
1125
|
+
this.emitClient("stateChange", newState, oldState);
|
|
1126
|
+
});
|
|
1127
|
+
this.dht = new DhtNamespace(this.rpc);
|
|
1128
|
+
this.lite = new LiteNamespace(this.rpc, this.subscriptionManager);
|
|
1129
|
+
this.subscribe = new SubscribeNamespace(this.rpc, this.subscriptionManager);
|
|
1130
|
+
this.jetton = new JettonNamespace(this.rpc);
|
|
1131
|
+
this.nft = new NftNamespace(this.rpc);
|
|
1132
|
+
this.dns = new DnsNamespace(this.rpc);
|
|
1133
|
+
this.adnl = new AdnlNamespace(this.rpc, this.subscriptionManager);
|
|
1134
|
+
this.network = new NetworkNamespace(this.rpc);
|
|
1135
|
+
this.overlay = new OverlayNamespace(this.rpc, this.subscriptionManager);
|
|
1136
|
+
this.wallet = new WalletNamespace(this.rpc);
|
|
1137
|
+
this.sbt = new SbtNamespace(this.rpc);
|
|
1138
|
+
this.payment = new PaymentNamespace(this.rpc);
|
|
1139
|
+
}
|
|
1140
|
+
/** Open the transport connection. */
|
|
1141
|
+
async connect() {
|
|
1142
|
+
await this.transport.connect();
|
|
1143
|
+
}
|
|
1144
|
+
/** Gracefully close the transport connection. */
|
|
1145
|
+
disconnect() {
|
|
1146
|
+
this.transport.disconnect();
|
|
1147
|
+
}
|
|
1148
|
+
/** Whether the transport is currently connected. */
|
|
1149
|
+
get isConnected() {
|
|
1150
|
+
return this.transport.isConnected;
|
|
1151
|
+
}
|
|
1152
|
+
/** Current transport state. */
|
|
1153
|
+
get state() {
|
|
1154
|
+
return this.transport.state;
|
|
1155
|
+
}
|
|
1156
|
+
/** Permanently tear down the client, releasing all resources. */
|
|
1157
|
+
destroy() {
|
|
1158
|
+
this.rpc.destroy();
|
|
1159
|
+
this.transport.destroy();
|
|
1160
|
+
this.clientListeners.clear();
|
|
1161
|
+
}
|
|
1162
|
+
/** Register a client event listener. */
|
|
1163
|
+
on(event, listener) {
|
|
1164
|
+
if (!this.clientListeners.has(event)) {
|
|
1165
|
+
this.clientListeners.set(event, /* @__PURE__ */ new Set());
|
|
1166
|
+
}
|
|
1167
|
+
this.clientListeners.get(event).add(listener);
|
|
1168
|
+
return this;
|
|
1169
|
+
}
|
|
1170
|
+
/** Remove a client event listener. */
|
|
1171
|
+
off(event, listener) {
|
|
1172
|
+
this.clientListeners.get(event)?.delete(listener);
|
|
1173
|
+
return this;
|
|
1174
|
+
}
|
|
1175
|
+
emitClient(event, ...args) {
|
|
1176
|
+
const fns = this.clientListeners.get(event);
|
|
1177
|
+
if (fns) for (const fn of fns) fn(...args);
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
exports.AbstractTransport = AbstractTransport;
|
|
1182
|
+
exports.AdnlNamespace = AdnlNamespace;
|
|
1183
|
+
exports.ConnectionClosedError = ConnectionClosedError;
|
|
1184
|
+
exports.ConnectionError = ConnectionError;
|
|
1185
|
+
exports.DhtNamespace = DhtNamespace;
|
|
1186
|
+
exports.DnsNamespace = DnsNamespace;
|
|
1187
|
+
exports.IpcTransport = IpcTransport;
|
|
1188
|
+
exports.JettonNamespace = JettonNamespace;
|
|
1189
|
+
exports.LiteNamespace = LiteNamespace;
|
|
1190
|
+
exports.NetworkNamespace = NetworkNamespace;
|
|
1191
|
+
exports.NftNamespace = NftNamespace;
|
|
1192
|
+
exports.OverlayNamespace = OverlayNamespace;
|
|
1193
|
+
exports.PaymentNamespace = PaymentNamespace;
|
|
1194
|
+
exports.RpcError = RpcError;
|
|
1195
|
+
exports.SbtNamespace = SbtNamespace;
|
|
1196
|
+
exports.SubscribeNamespace = SubscribeNamespace;
|
|
1197
|
+
exports.Subscription = Subscription;
|
|
1198
|
+
exports.TimeoutError = TimeoutError;
|
|
1199
|
+
exports.TransportState = TransportState;
|
|
1200
|
+
exports.ValidationError = ValidationError;
|
|
1201
|
+
exports.WalletNamespace = WalletNamespace;
|
|
1202
|
+
exports.Web3SocketsClient = Web3SocketsClient;
|
|
1203
|
+
exports.Web3SocketsError = Web3SocketsError;
|
|
1204
|
+
exports.WsTransport = WsTransport;
|
|
1205
|
+
exports.createTransport = createTransport;
|
|
1206
|
+
//# sourceMappingURL=index.cjs.map
|
|
1207
|
+
//# sourceMappingURL=index.cjs.map
|