@leofcoin/peernet 1.1.72 → 1.1.74

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,605 @@
1
+ import { L as LittlePubSub } from './peernet-w0f2V8kl.js';
2
+ import './value-wzPYMxsX.js';
3
+
4
+ class Api {
5
+ _pubsub;
6
+ constructor(_pubsub) {
7
+ this._pubsub = _pubsub;
8
+ }
9
+ subscribe(topic, cb) {
10
+ this._pubsub.subscribe(topic, cb);
11
+ }
12
+ unsubscribe(topic, cb) {
13
+ this._pubsub.unsubscribe(topic, cb);
14
+ }
15
+ publish(topic, value) {
16
+ this._pubsub.publish(topic, value);
17
+ }
18
+ subscribers() {
19
+ this._pubsub.subscribers;
20
+ }
21
+ connectionState(state) {
22
+ switch (state) {
23
+ case 0:
24
+ return 'connecting';
25
+ case 1:
26
+ return 'open';
27
+ case 2:
28
+ return 'closing';
29
+ case 3:
30
+ return 'closed';
31
+ }
32
+ }
33
+ /**
34
+ * @param {string} type
35
+ * @param {string} name
36
+ * @param {object} params
37
+ */
38
+ request(client, request) {
39
+ return new Promise((resolve, reject) => {
40
+ const state = this.connectionState(client.readyState);
41
+ if (state !== 'open')
42
+ return reject(`coudn't send request to ${client.id}, no open connection found.`);
43
+ request.id = Math.random().toString(36).slice(-12);
44
+ const handler = result => {
45
+ if (result && result.error)
46
+ return reject(result.error);
47
+ resolve({ result, id: request.id, handler });
48
+ this.unsubscribe(request.id, handler);
49
+ };
50
+ this.subscribe(request.id, handler);
51
+ this.send(client, request);
52
+ });
53
+ }
54
+ async send(client, request) {
55
+ return client.send(JSON.stringify(request));
56
+ }
57
+ pubsub(client) {
58
+ return {
59
+ publish: (topic = 'pubsub', value) => {
60
+ return this.send(client, { url: 'pubsub', params: { topic, value } });
61
+ },
62
+ subscribe: (topic = 'pubsub', cb) => {
63
+ this.subscribe(topic, cb);
64
+ return this.send(client, { url: 'pubsub', params: { topic, subscribe: true } });
65
+ },
66
+ unsubscribe: (topic = 'pubsub', cb) => {
67
+ this.unsubscribe(topic, cb);
68
+ return this.send(client, { url: 'pubsub', params: { topic, unsubscribe: true } });
69
+ },
70
+ subscribers: this._pubsub.subscribers
71
+ };
72
+ }
73
+ server(client) {
74
+ return {
75
+ uptime: async () => {
76
+ try {
77
+ const { result, id, handler } = await this.request(client, { url: 'uptime' });
78
+ this.unsubscribe(id, handler);
79
+ return result;
80
+ }
81
+ catch (e) {
82
+ throw e;
83
+ }
84
+ },
85
+ ping: async () => {
86
+ try {
87
+ const now = new Date().getTime();
88
+ const { result, id, handler } = await this.request(client, { url: 'ping' });
89
+ this.unsubscribe(id, handler);
90
+ return (Number(result) - now);
91
+ }
92
+ catch (e) {
93
+ throw e;
94
+ }
95
+ }
96
+ };
97
+ }
98
+ peernet(client) {
99
+ return {
100
+ join: async (params) => {
101
+ try {
102
+ params.join = true;
103
+ const requested = { url: 'peernet', params };
104
+ const { result, id, handler } = await this.request(client, requested);
105
+ this.unsubscribe(id, handler);
106
+ return result;
107
+ }
108
+ catch (e) {
109
+ throw e;
110
+ }
111
+ },
112
+ leave: async (params) => {
113
+ try {
114
+ params.join = false;
115
+ const requested = { url: 'peernet', params };
116
+ const { result, id, handler } = await this.request(client, requested);
117
+ this.unsubscribe(id, handler);
118
+ return result;
119
+ }
120
+ catch (e) {
121
+ throw e;
122
+ }
123
+ }
124
+ };
125
+ }
126
+ }
127
+
128
+ class ClientConnection {
129
+ client;
130
+ api;
131
+ #startTime;
132
+ constructor(client, api) {
133
+ this.#startTime = new Date().getTime();
134
+ this.client = client;
135
+ this.api = api;
136
+ }
137
+ request = async (req) => {
138
+ const { result, id, handler } = await this.api.request(this.client, req);
139
+ globalThis.pubsub.unsubscribe(id, handler);
140
+ return result;
141
+ };
142
+ send = (req) => this.api.send(this.client, req);
143
+ get subscribe() {
144
+ return this.api.subscribe;
145
+ }
146
+ get unsubscribe() {
147
+ return this.api.unsubscribe;
148
+ }
149
+ get subscribers() {
150
+ return this.api.subscribers;
151
+ }
152
+ get publish() {
153
+ return this.api.publish;
154
+ }
155
+ get pubsub() {
156
+ return this.api.pubsub(this.client);
157
+ }
158
+ uptime = () => {
159
+ const now = new Date().getTime();
160
+ return (now - this.#startTime);
161
+ };
162
+ get peernet() {
163
+ return this.api.peernet(this.client);
164
+ }
165
+ get server() {
166
+ return this.api.server(this.client);
167
+ }
168
+ connectionState = () => this.api.connectionState(this.client.readyState);
169
+ close = exit => {
170
+ // client.onclose = message => {
171
+ // if (exit) process.exit()
172
+ // }
173
+ this.client.close();
174
+ };
175
+ }
176
+
177
+ if (!globalThis.PubSub)
178
+ globalThis.PubSub = LittlePubSub;
179
+ if (!globalThis.pubsub)
180
+ globalThis.pubsub = new LittlePubSub(false);
181
+ class SocketRequestClient {
182
+ api;
183
+ clientConnection;
184
+ #tries = 0;
185
+ #retry = false;
186
+ #timeout = 10000;
187
+ #times = 10;
188
+ #options;
189
+ #protocol;
190
+ #url;
191
+ constructor(url, protocol, options) {
192
+ let { retry, timeout, times } = options || {};
193
+ if (retry !== undefined)
194
+ this.#retry = retry;
195
+ if (timeout !== undefined)
196
+ this.#timeout = timeout;
197
+ if (times !== undefined)
198
+ this.#times = times;
199
+ this.#url = url;
200
+ this.#protocol = protocol;
201
+ this.#options = options;
202
+ this.api = new Api(globalThis.pubsub);
203
+ }
204
+ init() {
205
+ return new Promise(async (resolve, reject) => {
206
+ const init = async () => {
207
+ // @ts-ignore
208
+ if (!globalThis.WebSocket)
209
+ globalThis.WebSocket = (await import('./browser-rHvRu5xW.js').then(function (n) { return n.b; })).default.w3cwebsocket;
210
+ const client = new WebSocket(this.#url, this.#protocol);
211
+ client.onmessage = this.onmessage;
212
+ client.onerror = this.onerror;
213
+ client.onopen = () => {
214
+ this.#tries = 0;
215
+ resolve(new ClientConnection(client, this.api));
216
+ };
217
+ client.onclose = message => {
218
+ this.#tries++;
219
+ if (!this.#retry)
220
+ return reject(this.#options);
221
+ if (this.#tries > this.#times) {
222
+ console.log(`${this.#options.protocol} Client Closed`);
223
+ console.error(`could not connect to - ${this.#url}/`);
224
+ return resolve(new ClientConnection(client, this.api));
225
+ }
226
+ if (message.code === 1006) {
227
+ console.log(`Retrying in ${this.#timeout} ms`);
228
+ setTimeout(() => {
229
+ return init();
230
+ }, this.#timeout);
231
+ }
232
+ };
233
+ };
234
+ return init();
235
+ });
236
+ }
237
+ onerror = error => {
238
+ if (globalThis.pubsub.subscribers['error']) {
239
+ globalThis.pubsub.publish('error', error);
240
+ }
241
+ else {
242
+ console.error(error);
243
+ }
244
+ };
245
+ onmessage(message) {
246
+ const { value, url, status, id } = JSON.parse(message.data.toString());
247
+ const publisher = id ? id : url;
248
+ if (status === 200) {
249
+ globalThis.pubsub.publish(publisher, value);
250
+ }
251
+ else {
252
+ globalThis.pubsub.publish(publisher, { error: value });
253
+ }
254
+ }
255
+ }
256
+
257
+ const MAX_MESSAGE_SIZE = 16000;
258
+ const defaultOptions = {
259
+ networkVersion: 'peach',
260
+ version: 'v1',
261
+ stars: ['wss://star.leofcoin.org'],
262
+ connectEvent: 'peer:connected'
263
+ };
264
+
265
+ const iceServers = [
266
+ {
267
+ urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
268
+ },
269
+ {
270
+ urls: 'stun:openrelay.metered.ca:80'
271
+ },
272
+ {
273
+ urls: 'turn:openrelay.metered.ca:443',
274
+ username: 'openrelayproject',
275
+ credential: 'openrelayproject'
276
+ },
277
+ {
278
+ urls: 'turn:openrelay.metered.ca:443?transport=tcp',
279
+ username: 'openrelayproject',
280
+ credential: 'openrelayproject'
281
+ }
282
+ ];
283
+ const SimplePeer = (await import('./index-jZbVSPhQ.js').then(function (n) { return n.i; })).default;
284
+ class Peer extends SimplePeer {
285
+ peerId;
286
+ channelName;
287
+ version;
288
+ bw = { up: 0, down: 0 };
289
+ get connected() {
290
+ return super.connected;
291
+ }
292
+ constructor(options) {
293
+ const { from, to, initiator, trickle, config, version } = options;
294
+ const channelName = initiator ? `${from}:${to}` : `${to}:${from}`;
295
+ super({
296
+ channelName,
297
+ initiator,
298
+ trickle: trickle || true,
299
+ config: { iceServers, ...config },
300
+ wrtc: globalThis.wrtc
301
+ });
302
+ this.version = String(version);
303
+ this.peerId = to;
304
+ this.channelName = channelName;
305
+ }
306
+ async #chunkit(data, id) {
307
+ this.bw.up = data.length;
308
+ const size = data.length;
309
+ // no needles chunking, keep it simple, if data is smaller then max size just send it
310
+ if (data.length <= MAX_MESSAGE_SIZE) {
311
+ return super.send(JSON.stringify({ chunk: data, id, size: data.length }));
312
+ }
313
+ async function* chunks(data) {
314
+ while (data.length !== 0) {
315
+ const amountToSlice = data.length >= MAX_MESSAGE_SIZE ? MAX_MESSAGE_SIZE : data.length;
316
+ const subArray = data.subarray(0, amountToSlice);
317
+ data = data.subarray(amountToSlice, data.length);
318
+ yield subArray;
319
+ // super.send(JSON.stringify({ chunk: subArray, id, size }))
320
+ }
321
+ }
322
+ // while (data.length !== 0) {
323
+ // const amountToSlice =
324
+ // data.length >= MAX_MESSAGE_SIZE ? MAX_MESSAGE_SIZE : data.length
325
+ // const subArray = data.subarray(0, amountToSlice)
326
+ // data = data.subarray(amountToSlice, data.length)
327
+ // super.send(JSON.stringify({ chunk: subArray, id, size }))
328
+ // }
329
+ for await (const chunk of chunks(data)) {
330
+ super.send(JSON.stringify({ chunk, id, size }));
331
+ }
332
+ }
333
+ /**
334
+ * send to peer
335
+ * @param data ArrayLike
336
+ * @param id custom id to listen to
337
+ */
338
+ send(data, id = crypto.randomUUID()) {
339
+ // send chuncks till ndata support for SCTP is added
340
+ // wraps data
341
+ this.#chunkit(data, id);
342
+ }
343
+ /**
344
+ * send to peer & wait for response
345
+ * @param data ArrayLike
346
+ * @param id custom id to listen to
347
+ */
348
+ request(data, id = crypto.randomUUID()) {
349
+ return new Promise((resolve, reject) => {
350
+ const timeout = setTimeout(() => reject(`request for ${id} timed out`), 30000);
351
+ const onrequest = ({ data }) => {
352
+ clearTimeout(timeout);
353
+ resolve(data);
354
+ globalThis.pubsub.unsubscribe(id, onrequest);
355
+ };
356
+ globalThis.pubsub.subscribe(id, onrequest);
357
+ this.send(data, id);
358
+ });
359
+ }
360
+ }
361
+
362
+ const debug = globalThis.createDebugger('@peernet/swarm/client');
363
+ class Client {
364
+ #peerId;
365
+ #connections = {};
366
+ #stars = {};
367
+ #connectEvent = 'peer:connected';
368
+ id;
369
+ networkVersion;
370
+ starsConfig;
371
+ socketClient;
372
+ messageSize = 262144;
373
+ version;
374
+ #messagesToHandle = {};
375
+ get peerId() {
376
+ return this.#peerId;
377
+ }
378
+ get connections() {
379
+ return { ...this.#connections };
380
+ }
381
+ get peers() {
382
+ return Object.entries(this.#connections);
383
+ }
384
+ getPeer(peerId) {
385
+ return this.#connections[peerId];
386
+ }
387
+ /**
388
+ *
389
+ * @param options {object}
390
+ * @param options.peerId {string}
391
+ * @param options.networkVersion {string}
392
+ * @param options.version {string}
393
+ * @param options.stars {string[]}
394
+ * @param options.connectEvent {string} defaults to peer:connected, can be renamed to handle different protocols, like peer:discovered (setup peer props before fireing the connect event)
395
+ */
396
+ constructor(options) {
397
+ const { peerId, networkVersion, version, connectEvent, stars } = {
398
+ ...defaultOptions,
399
+ ...options
400
+ };
401
+ this.#peerId = peerId;
402
+ this.networkVersion = networkVersion;
403
+ this.version = version;
404
+ this.#connectEvent = connectEvent;
405
+ this.starsConfig = stars;
406
+ this._init();
407
+ }
408
+ async _init() {
409
+ // reconnectJob()
410
+ if (!globalThis.RTCPeerConnection)
411
+ globalThis.wrtc = (await import('./browser-AyxSBUXj.js').then(function (n) { return n.b; })).default;
412
+ for (const star of this.starsConfig) {
413
+ try {
414
+ const client = new SocketRequestClient(star, this.networkVersion);
415
+ this.#stars[star] = await client.init();
416
+ this.setupStarListeners(this.#stars[star]);
417
+ this.#stars[star].send({
418
+ url: 'join',
419
+ params: { version: this.version, peerId: this.peerId }
420
+ });
421
+ }
422
+ catch (e) {
423
+ if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1 &&
424
+ !this.socketClient)
425
+ throw new Error(`No star available to connect`);
426
+ }
427
+ }
428
+ if (globalThis.process?.versions?.node) {
429
+ process.on('SIGINT', async () => {
430
+ process.stdin.resume();
431
+ await this.close();
432
+ process.exit();
433
+ });
434
+ }
435
+ else {
436
+ globalThis.addEventListener('beforeunload', async () => this.close());
437
+ }
438
+ }
439
+ setupStarListeners(star) {
440
+ star.pubsub.subscribe('peer:joined', (id) => this.#peerJoined(id, star));
441
+ star.pubsub.subscribe('peer:left', (id) => this.#peerLeft(id, star));
442
+ star.pubsub.subscribe('star:joined', this.#starJoined);
443
+ star.pubsub.subscribe('star:left', this.#starLeft);
444
+ star.pubsub.subscribe('signal', (message) => this.#inComingSignal(message, star));
445
+ }
446
+ #starJoined = (id) => {
447
+ if (this.#stars[id]) {
448
+ this.#stars[id].close(0);
449
+ delete this.#stars[id];
450
+ }
451
+ console.log(`star ${id} joined`);
452
+ };
453
+ #starLeft = async (id) => {
454
+ if (this.#stars[id]) {
455
+ this.#stars[id].close(0);
456
+ delete this.#stars[id];
457
+ }
458
+ if (Object.keys(this.#stars).length === 0) {
459
+ for (const star of this.starsConfig) {
460
+ try {
461
+ const socketClient = await new SocketRequestClient(star, this.networkVersion).init();
462
+ if (!socketClient?.client?.OPEN)
463
+ return;
464
+ this.#stars[star] = socketClient;
465
+ this.#stars[star].send({
466
+ url: 'join',
467
+ params: { peerId: this.peerId, version: this.version }
468
+ });
469
+ this.setupStarListeners(socketClient);
470
+ }
471
+ catch (e) {
472
+ if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1)
473
+ throw new Error(`No star available to connect`);
474
+ }
475
+ }
476
+ }
477
+ debug(`star ${id} left`);
478
+ };
479
+ #peerLeft = (peer, star) => {
480
+ const id = peer.peerId || peer;
481
+ if (this.#connections[id]) {
482
+ this.#connections[id].destroy();
483
+ delete this.#connections[id];
484
+ }
485
+ debug(`peer ${id} left`);
486
+ };
487
+ #createRTCPeerConnection = (peerId, star, version, initiator = false) => {
488
+ const peer = new Peer({
489
+ initiator: initiator,
490
+ from: this.peerId,
491
+ to: peerId,
492
+ version
493
+ });
494
+ peer.on('signal', (signal) => this.#peerSignal(peer, signal, star, this.version));
495
+ peer.on('connect', () => this.#peerConnect(peer));
496
+ peer.on('close', () => this.#peerClose(peer));
497
+ peer.on('data', (data) => this.#peerData(peer, data));
498
+ peer.on('error', (error) => this.#peerError(peer, error));
499
+ this.#connections[peerId] = peer;
500
+ };
501
+ #peerJoined = async ({ peerId, version }, star) => {
502
+ // check if peer rejoined before the previous connection closed
503
+ if (this.#connections[peerId]) {
504
+ this.#connections[peerId].destroy();
505
+ delete this.#connections[peerId];
506
+ }
507
+ // RTCPeerConnection
508
+ this.#createRTCPeerConnection(peerId, star, version, true);
509
+ debug(`peer ${peerId} joined`);
510
+ };
511
+ #inComingSignal = async ({ from, signal, channelName, version }, star) => {
512
+ if (version !== this.version) {
513
+ console.warn(`${from} joined using the wrong version.\nexpected: ${this.version} but got:${version}`);
514
+ return;
515
+ }
516
+ let peer = this.#connections[from];
517
+ if (!peer) {
518
+ this.#createRTCPeerConnection(from, star, version);
519
+ peer = this.#connections[from];
520
+ }
521
+ if (String(peer.channelName) !== String(channelName))
522
+ console.warn(`channelNames don't match: got ${peer.channelName}, expected: ${channelName}`);
523
+ peer.signal(signal);
524
+ };
525
+ #peerSignal = (peer, signal, star, version) => {
526
+ let client = this.#stars[star];
527
+ if (!client)
528
+ client = this.#stars[Object.keys(this.#stars)[0]];
529
+ client.send({
530
+ url: 'signal',
531
+ params: {
532
+ from: this.peerId,
533
+ to: peer.peerId,
534
+ channelName: peer.channelName,
535
+ version,
536
+ signal
537
+ }
538
+ });
539
+ };
540
+ #peerClose = (peer) => {
541
+ if (this.#connections[peer.peerId]) {
542
+ peer.destroy();
543
+ delete this.#connections[peer.peerId];
544
+ }
545
+ debug(`closed ${peer.peerId}'s connection`);
546
+ };
547
+ #peerConnect = (peer) => {
548
+ debug(`${peer.peerId} connected`);
549
+ globalThis.pubsub.publishVerbose(this.#connectEvent, peer.peerId);
550
+ };
551
+ #noticeMessage = (message, id, from, peer) => {
552
+ if (globalThis.pubsub.subscribers[id]) {
553
+ globalThis.pubsub.publish(id, {
554
+ data: new Uint8Array(Object.values(message)),
555
+ id,
556
+ from,
557
+ peer
558
+ });
559
+ }
560
+ else {
561
+ globalThis.pubsub.publish('peer:data', {
562
+ data: new Uint8Array(Object.values(message)),
563
+ id,
564
+ from,
565
+ peer
566
+ });
567
+ }
568
+ };
569
+ #peerData = (peer, data) => {
570
+ const { id, size, chunk } = JSON.parse(new TextDecoder().decode(data));
571
+ peer.bw.down += size;
572
+ if (size <= MAX_MESSAGE_SIZE) {
573
+ this.#noticeMessage(chunk, id, peer.peerId, peer);
574
+ }
575
+ else {
576
+ if (!this.#messagesToHandle[id])
577
+ this.#messagesToHandle[id] = [];
578
+ this.#messagesToHandle[id] = [
579
+ ...this.#messagesToHandle[id],
580
+ ...Object.values(chunk)
581
+ ];
582
+ if (this.#messagesToHandle[id].length === Number(size)) {
583
+ this.#noticeMessage(this.#messagesToHandle[id], id, peer.peerId, peer);
584
+ delete this.#messagesToHandle[id];
585
+ }
586
+ }
587
+ };
588
+ #peerError = (peer, error) => {
589
+ console.warn(`Connection error: ${error.message}`);
590
+ peer.destroy();
591
+ };
592
+ async close() {
593
+ for (const star in this.#stars) {
594
+ if (this.#stars[star].connectionState() === 'open')
595
+ await this.#stars[star].send({ url: 'leave', params: this.peerId });
596
+ }
597
+ const promises = [
598
+ Object.values(this.#connections).map((connection) => connection.destroy()),
599
+ Object.values(this.#stars).map((connection) => connection.close(0))
600
+ ];
601
+ return Promise.allSettled(promises);
602
+ }
603
+ }
604
+
605
+ export { Client as default };
@@ -0,0 +1,19 @@
1
+ import type { base58String } from '@vandeurenglenn/base58';
2
+ export default class Identity {
3
+ #private;
4
+ network: any;
5
+ id: string;
6
+ selectedAccount: string;
7
+ constructor(network: string);
8
+ get accounts(): Promise<[[name: string, externalAddress: string, internalAddress: string]]>;
9
+ getAccounts(): Promise<[[name: string, externalAddress: string, internalAddress: string]]>;
10
+ load(password?: string): Promise<void>;
11
+ selectAccount(account: string): Promise<void> | Promise<IDBValidKey> | Promise<any[]>;
12
+ sign(hash: Uint8Array): any;
13
+ lock(password: string): void;
14
+ unlock(password: string): void;
15
+ export(password: string): Promise<any>;
16
+ import(password: any, encrypted: base58String): Promise<void>;
17
+ exportQR(password: string): Promise<string>;
18
+ importQR(image: File | Blob, password: string): Promise<void>;
19
+ }
@@ -1,5 +1,5 @@
1
- import { M as MultiWallet, e as encrypt, b as base58$1 } from './peernet-fa94440c.js';
2
- import './value-4e80eeeb.js';
1
+ import { M as MultiWallet, e as encrypt, b as base58$1 } from './peernet-w0f2V8kl.js';
2
+ import './value-wzPYMxsX.js';
3
3
 
4
4
  /**
5
5
  * @params {String} network