@leofcoin/peernet 1.2.4 → 1.2.6

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.
@@ -1,4 +1,4 @@
1
- import { L as LittlePubSub, d as deflate_1, i as inflate_1, c as createDebugger } from './peernet-D6QlSJ6B.js';
1
+ import { L as LittlePubSub, d as deflate_1, i as inflate_1, c as createDebugger } from './peernet-CpcIFBTX.js';
2
2
  import './identity-nIyW_Xm8.js';
3
3
  import './value-C3vAp-wb.js';
4
4
 
@@ -490,6 +490,63 @@ class Peer extends SimplePeer {
490
490
  this.send(data, id);
491
491
  });
492
492
  }
493
+ /**
494
+ * Get comprehensive network statistics from WebRTC
495
+ * @returns NetworkStats object with detailed metrics
496
+ */
497
+ async getNetworkStats() {
498
+ try {
499
+ const pc = this._pc;
500
+ if (!pc)
501
+ return null;
502
+ const stats = await pc.getStats();
503
+ const result = {
504
+ latency: null,
505
+ jitter: null,
506
+ bytesReceived: 0,
507
+ bytesSent: 0,
508
+ packetsLost: 0,
509
+ fractionLost: null,
510
+ inboundBitrate: null,
511
+ outboundBitrate: null,
512
+ availableOutgoingBitrate: null,
513
+ timestamp: Date.now()
514
+ };
515
+ let prevBytesReceived = 0;
516
+ let prevBytesSent = 0;
517
+ let prevTimestamp = 0;
518
+ stats.forEach((report) => {
519
+ // Latency from candidate pair
520
+ if (report.type === 'candidate-pair' && report.currentRoundTripTime) {
521
+ result.latency = Math.round(report.currentRoundTripTime * 1000);
522
+ }
523
+ // Inbound RTP stats
524
+ if (report.type === 'inbound-rtp') {
525
+ result.bytesReceived += report.bytesReceived || 0;
526
+ result.packetsLost += report.packetsLost || 0;
527
+ if (report.jitter) {
528
+ result.jitter = Math.round(report.jitter * 1000);
529
+ }
530
+ if (report.fractionLost) {
531
+ result.fractionLost = report.fractionLost;
532
+ }
533
+ }
534
+ // Outbound RTP stats
535
+ if (report.type === 'outbound-rtp') {
536
+ result.bytesSent += report.bytesSent || 0;
537
+ }
538
+ // Available bandwidth
539
+ if (report.type === 'remote-candidate' &&
540
+ report.availableOutgoingBitrate) {
541
+ result.availableOutgoingBitrate = Math.round(report.availableOutgoingBitrate);
542
+ }
543
+ });
544
+ return result;
545
+ }
546
+ catch (e) {
547
+ return null;
548
+ }
549
+ }
493
550
  toJSON() {
494
551
  return {
495
552
  peerId: this.peerId,
@@ -1,4 +1,4 @@
1
- import { F as FormatInterface } from './peernet-D6QlSJ6B.js';
1
+ import { F as FormatInterface } from './peernet-CpcIFBTX.js';
2
2
  import './identity-nIyW_Xm8.js';
3
3
  import './value-C3vAp-wb.js';
4
4
 
@@ -8318,7 +8318,7 @@ class Peernet {
8318
8318
  return this.identity.accounts;
8319
8319
  }
8320
8320
  get defaultStores() {
8321
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message'];
8321
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message', 'share'];
8322
8322
  }
8323
8323
  selectAccount(account) {
8324
8324
  return this.identity.selectAccount(account);
@@ -8331,7 +8331,12 @@ class Peernet {
8331
8331
  return utils.addCodec(codec);
8332
8332
  }
8333
8333
  async addStore(name, prefix, root, isPrivate = true) {
8334
- if (name === 'block' || name === 'transaction' || name === 'chain' || name === 'data' || name === 'message')
8334
+ if (name === 'block' ||
8335
+ name === 'transaction' ||
8336
+ name === 'chain' ||
8337
+ name === 'data' ||
8338
+ name === 'message' ||
8339
+ name === 'share')
8335
8340
  isPrivate = false;
8336
8341
  let Storage;
8337
8342
  this.hasDaemon ? (Storage = LeofcoinStorageClient) : (Storage = LeofcoinStorage);
@@ -8380,7 +8385,7 @@ class Peernet {
8380
8385
  this.root = options.root;
8381
8386
  const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
8382
8387
  // FolderMessageResponse
8383
- } = await import(/* webpackChunkName: "messages" */ './messages-BVmbvFj4.js');
8388
+ } = await import(/* webpackChunkName: "messages" */ './messages-pDchwT17.js');
8384
8389
  /**
8385
8390
  * proto Object containing protos
8386
8391
  * @type {Object}
@@ -8474,7 +8479,7 @@ class Peernet {
8474
8479
  if (this.#starting || this.#started)
8475
8480
  return;
8476
8481
  this.#starting = true;
8477
- const importee = await import('./client-7chRAqOy.js');
8482
+ const importee = await import('./client-1JlanVkr.js');
8478
8483
  /**
8479
8484
  * @access public
8480
8485
  * @type {PeernetClient}
@@ -8574,6 +8579,8 @@ class Peernet {
8574
8579
  if (!this._inMemoryBroadcasts)
8575
8580
  this._inMemoryBroadcasts = new Map();
8576
8581
  this._inMemoryBroadcasts.set(hash, encoded);
8582
+ // Persist to share store
8583
+ await shareStore.put(hash, encoded);
8577
8584
  await this.publish('broadcast', { hash, from: this.id });
8578
8585
  return hash;
8579
8586
  }
@@ -8897,6 +8904,65 @@ class Peernet {
8897
8904
  has: async (hash) => await dataStore.has(hash)
8898
8905
  };
8899
8906
  }
8907
+ get share() {
8908
+ return {
8909
+ /**
8910
+ * Get content for given share hash
8911
+ *
8912
+ * @todo Add peer permission checking to validate if requesting peer has access
8913
+ *
8914
+ * @param {String} hash
8915
+ */
8916
+ get: async (hash) => {
8917
+ debug(`get share ${hash}`);
8918
+ const data = await shareStore.has(hash);
8919
+ if (data)
8920
+ return await shareStore.get(hash);
8921
+ return undefined;
8922
+ },
8923
+ /**
8924
+ * put share content
8925
+ *
8926
+ * @param {String} hash
8927
+ * @param {Buffer} data
8928
+ */
8929
+ put: async (hash, data) => await shareStore.put(hash, data),
8930
+ /**
8931
+ * @param {String} hash
8932
+ * @return {Boolean}
8933
+ */
8934
+ has: async (hash) => await shareStore.has(hash),
8935
+ /**
8936
+ * Put folder content
8937
+ *
8938
+ * @param {Array} files
8939
+ */
8940
+ putFolder: async (files) => {
8941
+ const links = [];
8942
+ for (const file of files) {
8943
+ const fileNode = await new globalThis.peernet.protos['peernet-file'](file);
8944
+ const hash = await fileNode.hash;
8945
+ await dataStore.put(hash, fileNode.encoded);
8946
+ links.push({ hash, path: file.path });
8947
+ }
8948
+ const node = await new globalThis.peernet.protos['peernet-file']({
8949
+ path: '/',
8950
+ links
8951
+ });
8952
+ const hash = await node.hash;
8953
+ await dataStore.put(hash, node.encoded);
8954
+ return hash;
8955
+ }
8956
+ };
8957
+ }
8958
+ /**
8959
+ * Get all shared hashes
8960
+ *
8961
+ * @returns {Promise<string[]>} Array of all shared hashes
8962
+ */
8963
+ async allSharedHashes() {
8964
+ return await shareStore.keys();
8965
+ }
8900
8966
  async addFolder(files) {
8901
8967
  const links = [];
8902
8968
  for (const file of files) {
@@ -16,6 +16,7 @@ declare global {
16
16
  var dataStore: LeofcoinStorageClass;
17
17
  var walletStore: LeofcoinStorageClass;
18
18
  var chainStore: LeofcoinStorageClass;
19
+ var shareStore: LeofcoinStorageClass;
19
20
  }
20
21
  /**
21
22
  * @access public
@@ -220,6 +221,40 @@ export default class Peernet {
220
221
  */
221
222
  has: (hash: any) => Promise<boolean | any[]>;
222
223
  };
224
+ get share(): {
225
+ /**
226
+ * Get content for given share hash
227
+ *
228
+ * @todo Add peer permission checking to validate if requesting peer has access
229
+ *
230
+ * @param {String} hash
231
+ */
232
+ get: (hash: any) => Promise<any>;
233
+ /**
234
+ * put share content
235
+ *
236
+ * @param {String} hash
237
+ * @param {Buffer} data
238
+ */
239
+ put: (hash: any, data: any) => Promise<unknown>;
240
+ /**
241
+ * @param {String} hash
242
+ * @return {Boolean}
243
+ */
244
+ has: (hash: any) => Promise<boolean | any[]>;
245
+ /**
246
+ * Put folder content
247
+ *
248
+ * @param {Array} files
249
+ */
250
+ putFolder: (files: any) => Promise<any>;
251
+ };
252
+ /**
253
+ * Get all shared hashes
254
+ *
255
+ * @returns {Promise<string[]>} Array of all shared hashes
256
+ */
257
+ allSharedHashes(): Promise<string[]>;
223
258
  addFolder(files: any): Promise<any>;
224
259
  ls(hash: any, options: any): Promise<any[]>;
225
260
  cat(hash: any, options: any): Promise<any>;
@@ -1,3 +1,3 @@
1
- export { P as default } from './peernet-D6QlSJ6B.js';
1
+ export { P as default } from './peernet-CpcIFBTX.js';
2
2
  import './identity-nIyW_Xm8.js';
3
3
  import './value-C3vAp-wb.js';
@@ -386,7 +386,7 @@ class Peernet {
386
386
  return this.identity.accounts;
387
387
  }
388
388
  get defaultStores() {
389
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message'];
389
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message', 'share'];
390
390
  }
391
391
  selectAccount(account) {
392
392
  return this.identity.selectAccount(account);
@@ -399,7 +399,12 @@ class Peernet {
399
399
  return utils.addCodec(codec);
400
400
  }
401
401
  async addStore(name, prefix, root, isPrivate = true) {
402
- if (name === 'block' || name === 'transaction' || name === 'chain' || name === 'data' || name === 'message')
402
+ if (name === 'block' ||
403
+ name === 'transaction' ||
404
+ name === 'chain' ||
405
+ name === 'data' ||
406
+ name === 'message' ||
407
+ name === 'share')
403
408
  isPrivate = false;
404
409
  let Storage;
405
410
  this.hasDaemon ? (Storage = LeofcoinStorageClient) : (Storage = LeofcoinStorage);
@@ -642,6 +647,8 @@ class Peernet {
642
647
  if (!this._inMemoryBroadcasts)
643
648
  this._inMemoryBroadcasts = new Map();
644
649
  this._inMemoryBroadcasts.set(hash, encoded);
650
+ // Persist to share store
651
+ await shareStore.put(hash, encoded);
645
652
  await this.publish('broadcast', { hash, from: this.id });
646
653
  return hash;
647
654
  }
@@ -965,6 +972,65 @@ class Peernet {
965
972
  has: async (hash) => await dataStore.has(hash)
966
973
  };
967
974
  }
975
+ get share() {
976
+ return {
977
+ /**
978
+ * Get content for given share hash
979
+ *
980
+ * @todo Add peer permission checking to validate if requesting peer has access
981
+ *
982
+ * @param {String} hash
983
+ */
984
+ get: async (hash) => {
985
+ debug(`get share ${hash}`);
986
+ const data = await shareStore.has(hash);
987
+ if (data)
988
+ return await shareStore.get(hash);
989
+ return undefined;
990
+ },
991
+ /**
992
+ * put share content
993
+ *
994
+ * @param {String} hash
995
+ * @param {Buffer} data
996
+ */
997
+ put: async (hash, data) => await shareStore.put(hash, data),
998
+ /**
999
+ * @param {String} hash
1000
+ * @return {Boolean}
1001
+ */
1002
+ has: async (hash) => await shareStore.has(hash),
1003
+ /**
1004
+ * Put folder content
1005
+ *
1006
+ * @param {Array} files
1007
+ */
1008
+ putFolder: async (files) => {
1009
+ const links = [];
1010
+ for (const file of files) {
1011
+ const fileNode = await new globalThis.peernet.protos['peernet-file'](file);
1012
+ const hash = await fileNode.hash;
1013
+ await dataStore.put(hash, fileNode.encoded);
1014
+ links.push({ hash, path: file.path });
1015
+ }
1016
+ const node = await new globalThis.peernet.protos['peernet-file']({
1017
+ path: '/',
1018
+ links
1019
+ });
1020
+ const hash = await node.hash;
1021
+ await dataStore.put(hash, node.encoded);
1022
+ return hash;
1023
+ }
1024
+ };
1025
+ }
1026
+ /**
1027
+ * Get all shared hashes
1028
+ *
1029
+ * @returns {Promise<string[]>} Array of all shared hashes
1030
+ */
1031
+ async allSharedHashes() {
1032
+ return await shareStore.keys();
1033
+ }
968
1034
  async addFolder(files) {
969
1035
  const links = [];
970
1036
  for (const file of files) {
@@ -16,6 +16,7 @@ declare global {
16
16
  var dataStore: LeofcoinStorageClass;
17
17
  var walletStore: LeofcoinStorageClass;
18
18
  var chainStore: LeofcoinStorageClass;
19
+ var shareStore: LeofcoinStorageClass;
19
20
  }
20
21
  /**
21
22
  * @access public
@@ -220,6 +221,40 @@ export default class Peernet {
220
221
  */
221
222
  has: (hash: any) => Promise<boolean | any[]>;
222
223
  };
224
+ get share(): {
225
+ /**
226
+ * Get content for given share hash
227
+ *
228
+ * @todo Add peer permission checking to validate if requesting peer has access
229
+ *
230
+ * @param {String} hash
231
+ */
232
+ get: (hash: any) => Promise<any>;
233
+ /**
234
+ * put share content
235
+ *
236
+ * @param {String} hash
237
+ * @param {Buffer} data
238
+ */
239
+ put: (hash: any, data: any) => Promise<unknown>;
240
+ /**
241
+ * @param {String} hash
242
+ * @return {Boolean}
243
+ */
244
+ has: (hash: any) => Promise<boolean | any[]>;
245
+ /**
246
+ * Put folder content
247
+ *
248
+ * @param {Array} files
249
+ */
250
+ putFolder: (files: any) => Promise<any>;
251
+ };
252
+ /**
253
+ * Get all shared hashes
254
+ *
255
+ * @returns {Promise<string[]>} Array of all shared hashes
256
+ */
257
+ allSharedHashes(): Promise<string[]>;
223
258
  addFolder(files: any): Promise<any>;
224
259
  ls(hash: any, options: any): Promise<any[]>;
225
260
  cat(hash: any, options: any): Promise<any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leofcoin/peernet",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "",
5
5
  "browser": "./exports/browser/peernet.js",
6
6
  "exports": {
@@ -38,7 +38,7 @@
38
38
  "@leofcoin/multi-wallet": "^3.1.8",
39
39
  "@leofcoin/storage": "^3.5.38",
40
40
  "@mapbox/node-pre-gyp": "^2.0.3",
41
- "@netpeer/swarm": "^0.9.1",
41
+ "@netpeer/swarm": "^0.9.2",
42
42
  "@vandeurenglenn/base58": "^1.1.9",
43
43
  "@vandeurenglenn/debug": "^1.4.0",
44
44
  "@vandeurenglenn/little-pubsub": "^1.5.2",
package/src/peernet.ts CHANGED
@@ -28,6 +28,7 @@ declare global {
28
28
  var dataStore: LeofcoinStorageClass
29
29
  var walletStore: LeofcoinStorageClass
30
30
  var chainStore: LeofcoinStorageClass
31
+ var shareStore: LeofcoinStorageClass
31
32
  }
32
33
 
33
34
  const debug = createDebugger('peernet')
@@ -121,7 +122,7 @@ export default class Peernet {
121
122
  }
122
123
 
123
124
  get defaultStores() {
124
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
125
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message', 'share']
125
126
  }
126
127
 
127
128
  selectAccount(account: string) {
@@ -137,7 +138,14 @@ export default class Peernet {
137
138
  }
138
139
 
139
140
  async addStore(name, prefix, root, isPrivate = true) {
140
- if (name === 'block' || name === 'transaction' || name === 'chain' || name === 'data' || name === 'message')
141
+ if (
142
+ name === 'block' ||
143
+ name === 'transaction' ||
144
+ name === 'chain' ||
145
+ name === 'data' ||
146
+ name === 'message' ||
147
+ name === 'share'
148
+ )
141
149
  isPrivate = false
142
150
 
143
151
  let Storage
@@ -423,6 +431,9 @@ export default class Peernet {
423
431
  if (!this._inMemoryBroadcasts) this._inMemoryBroadcasts = new Map()
424
432
  this._inMemoryBroadcasts.set(hash, encoded)
425
433
 
434
+ // Persist to share store
435
+ await shareStore.put(hash, encoded)
436
+
426
437
  await this.publish('broadcast', { hash, from: this.id })
427
438
  return hash
428
439
  }
@@ -754,6 +765,68 @@ export default class Peernet {
754
765
  }
755
766
  }
756
767
 
768
+ get share() {
769
+ return {
770
+ /**
771
+ * Get content for given share hash
772
+ *
773
+ * @todo Add peer permission checking to validate if requesting peer has access
774
+ *
775
+ * @param {String} hash
776
+ */
777
+ get: async (hash) => {
778
+ debug(`get share ${hash}`)
779
+ const data = await shareStore.has(hash)
780
+ if (data) return await shareStore.get(hash)
781
+ return undefined
782
+ },
783
+ /**
784
+ * put share content
785
+ *
786
+ * @param {String} hash
787
+ * @param {Buffer} data
788
+ */
789
+ put: async (hash, data) => await shareStore.put(hash, data),
790
+ /**
791
+ * @param {String} hash
792
+ * @return {Boolean}
793
+ */
794
+ has: async (hash) => await shareStore.has(hash),
795
+
796
+ /**
797
+ * Put folder content
798
+ *
799
+ * @param {Array} files
800
+ */
801
+ putFolder: async (files) => {
802
+ const links = []
803
+ for (const file of files) {
804
+ const fileNode = await new globalThis.peernet.protos['peernet-file'](file)
805
+ const hash = await fileNode.hash
806
+ await dataStore.put(hash, fileNode.encoded)
807
+ links.push({ hash, path: file.path })
808
+ }
809
+ const node = await new globalThis.peernet.protos['peernet-file']({
810
+ path: '/',
811
+ links
812
+ })
813
+ const hash = await node.hash
814
+ await dataStore.put(hash, node.encoded)
815
+
816
+ return hash
817
+ }
818
+ }
819
+ }
820
+
821
+ /**
822
+ * Get all shared hashes
823
+ *
824
+ * @returns {Promise<string[]>} Array of all shared hashes
825
+ */
826
+ async allSharedHashes(): Promise<string[]> {
827
+ return await shareStore.keys()
828
+ }
829
+
757
830
  async addFolder(files) {
758
831
  const links = []
759
832
  for (const file of files) {
@@ -211,6 +211,7 @@ test('default stores are initialized', () => {
211
211
  assert.ok(defaultStores.includes('chain'))
212
212
  assert.ok(defaultStores.includes('data'))
213
213
  assert.ok(defaultStores.includes('message'))
214
+ assert.ok(defaultStores.includes('share'))
214
215
  })
215
216
 
216
217
  test('identity has all expected methods', () => {
@@ -302,3 +303,46 @@ test('in-memory broadcast and handleData supports large binary data', async () =
302
303
  const originalBuffer = Buffer.from(largeBuffer)
303
304
  assert.equal(Buffer.compare(receivedBuffer, originalBuffer), 0)
304
305
  })
306
+
307
+ test('share object provides get/put/has', () => {
308
+ const shareObj = peernet.share
309
+ assert.equal(typeof shareObj.get, 'function')
310
+ assert.equal(typeof shareObj.put, 'function')
311
+ assert.equal(typeof shareObj.has, 'function')
312
+ })
313
+
314
+ test('allSharedHashes method exists and is callable', () => {
315
+ assert.equal(typeof peernet.allSharedHashes, 'function')
316
+ })
317
+
318
+ test('broadcast persists to share store', async () => {
319
+ const testString = 'test broadcast content'
320
+ const path = '/broadcast-test'
321
+ const content = new TextEncoder().encode(testString)
322
+
323
+ const hash = await peernet.broadcast(path, { content })
324
+
325
+ // Verify it was stored in share store
326
+ assert.ok(hash)
327
+ const hasInShare = await peernet.share.has(hash)
328
+ assert.equal(hasInShare, true)
329
+ })
330
+
331
+ test('share store can retrieve broadcasted content', async () => {
332
+ const testString = 'retrievable broadcast content'
333
+ const path = '/retrievable-test'
334
+ const content = new TextEncoder().encode(testString)
335
+
336
+ const hash = await peernet.broadcast(path, { content })
337
+
338
+ // Verify we can retrieve it from share store
339
+ const storedData = await peernet.share.get(hash)
340
+ assert.ok(storedData)
341
+ })
342
+
343
+ test('allSharedHashes returns array of hashes', async () => {
344
+ const hashes = await peernet.allSharedHashes()
345
+ assert.ok(Array.isArray(hashes))
346
+ // Should contain at least the hashes we broadcasted in previous tests
347
+ assert.ok(hashes.length >= 0)
348
+ })