react-native-ble-mesh 2.1.0 → 2.1.3

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.
Files changed (88) hide show
  1. package/package.json +9 -2
  2. package/src/MeshNetwork.js +48 -46
  3. package/src/constants/audio.js +4 -4
  4. package/src/constants/ble.js +1 -1
  5. package/src/constants/crypto.js +1 -1
  6. package/src/constants/errors.js +2 -2
  7. package/src/constants/events.js +1 -1
  8. package/src/constants/protocol.js +2 -2
  9. package/src/crypto/AutoCrypto.js +2 -0
  10. package/src/crypto/CryptoProvider.js +17 -17
  11. package/src/crypto/providers/ExpoCryptoProvider.js +12 -7
  12. package/src/crypto/providers/QuickCryptoProvider.js +50 -15
  13. package/src/crypto/providers/TweetNaClProvider.js +9 -7
  14. package/src/errors/AudioError.js +2 -1
  15. package/src/errors/ConnectionError.js +2 -2
  16. package/src/errors/CryptoError.js +1 -1
  17. package/src/errors/HandshakeError.js +2 -2
  18. package/src/errors/MeshError.js +4 -4
  19. package/src/errors/MessageError.js +2 -2
  20. package/src/errors/ValidationError.js +3 -3
  21. package/src/expo/withBLEMesh.js +10 -10
  22. package/src/hooks/AppStateManager.js +10 -4
  23. package/src/hooks/useMesh.js +7 -7
  24. package/src/hooks/useMessages.js +13 -12
  25. package/src/hooks/usePeers.js +10 -9
  26. package/src/index.js +2 -2
  27. package/src/mesh/dedup/BloomFilter.js +1 -0
  28. package/src/mesh/dedup/DedupManager.js +4 -7
  29. package/src/mesh/dedup/MessageCache.js +3 -0
  30. package/src/mesh/fragment/Assembler.js +5 -4
  31. package/src/mesh/fragment/Fragmenter.js +2 -2
  32. package/src/mesh/monitor/ConnectionQuality.js +17 -8
  33. package/src/mesh/monitor/NetworkMonitor.js +22 -15
  34. package/src/mesh/peer/Peer.js +4 -9
  35. package/src/mesh/peer/PeerDiscovery.js +18 -19
  36. package/src/mesh/peer/PeerManager.js +14 -14
  37. package/src/mesh/router/MessageRouter.js +15 -15
  38. package/src/mesh/router/PathFinder.js +10 -13
  39. package/src/mesh/router/RouteTable.js +8 -7
  40. package/src/mesh/store/StoreAndForwardManager.js +20 -23
  41. package/src/protocol/message.js +5 -13
  42. package/src/protocol/serializer.js +4 -4
  43. package/src/protocol/validator.js +7 -6
  44. package/src/service/BatteryOptimizer.js +18 -17
  45. package/src/service/EmergencyManager.js +19 -26
  46. package/src/service/HandshakeManager.js +100 -2
  47. package/src/service/MeshService.js +106 -22
  48. package/src/service/SessionManager.js +38 -3
  49. package/src/service/audio/AudioManager.js +80 -38
  50. package/src/service/audio/buffer/FrameBuffer.js +7 -8
  51. package/src/service/audio/buffer/JitterBuffer.js +1 -1
  52. package/src/service/audio/codec/LC3Codec.js +22 -20
  53. package/src/service/audio/codec/LC3Decoder.js +10 -10
  54. package/src/service/audio/codec/LC3Encoder.js +11 -9
  55. package/src/service/audio/session/AudioSession.js +14 -17
  56. package/src/service/audio/session/VoiceMessage.js +15 -22
  57. package/src/service/audio/transport/AudioFragmenter.js +17 -9
  58. package/src/service/audio/transport/AudioFramer.js +8 -12
  59. package/src/service/file/FileAssembler.js +4 -2
  60. package/src/service/file/FileChunker.js +1 -1
  61. package/src/service/file/FileManager.js +26 -20
  62. package/src/service/file/FileMessage.js +7 -12
  63. package/src/service/text/TextManager.js +55 -28
  64. package/src/service/text/broadcast/BroadcastManager.js +14 -17
  65. package/src/service/text/channel/Channel.js +10 -14
  66. package/src/service/text/channel/ChannelManager.js +10 -10
  67. package/src/service/text/message/TextMessage.js +12 -19
  68. package/src/service/text/message/TextSerializer.js +2 -2
  69. package/src/storage/AsyncStorageAdapter.js +17 -14
  70. package/src/storage/MemoryStorage.js +11 -8
  71. package/src/storage/MessageStore.js +22 -30
  72. package/src/storage/Storage.js +9 -9
  73. package/src/transport/BLETransport.js +16 -14
  74. package/src/transport/MockTransport.js +7 -2
  75. package/src/transport/MultiTransport.js +13 -6
  76. package/src/transport/Transport.js +9 -9
  77. package/src/transport/WiFiDirectTransport.js +25 -24
  78. package/src/transport/adapters/BLEAdapter.js +19 -19
  79. package/src/transport/adapters/NodeBLEAdapter.js +24 -23
  80. package/src/transport/adapters/RNBLEAdapter.js +19 -24
  81. package/src/utils/EventEmitter.js +17 -12
  82. package/src/utils/LRUCache.js +10 -4
  83. package/src/utils/RateLimiter.js +1 -1
  84. package/src/utils/compression.js +6 -8
  85. package/src/utils/encoding.js +8 -2
  86. package/src/utils/retry.js +11 -13
  87. package/src/utils/time.js +9 -4
  88. package/src/utils/validation.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ble-mesh",
3
- "version": "2.1.0",
3
+ "version": "2.1.3",
4
4
  "description": "React Native Bluetooth Low Energy (BLE) mesh networking library with end-to-end encryption, offline messaging, peer-to-peer communication, and Noise Protocol security for iOS and Android",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -78,7 +78,8 @@
78
78
  "peerDependencies": {
79
79
  "react-native": ">=0.60.0",
80
80
  "react-native-get-random-values": ">=1.8.0",
81
- "react-native-ble-plx": ">=2.0.0"
81
+ "react-native-ble-plx": ">=2.0.0",
82
+ "tweetnacl": ">=1.0.0"
82
83
  },
83
84
  "peerDependenciesMeta": {
84
85
  "react-native": {
@@ -86,6 +87,12 @@
86
87
  },
87
88
  "react-native-ble-plx": {
88
89
  "optional": true
90
+ },
91
+ "react-native-get-random-values": {
92
+ "optional": true
93
+ },
94
+ "tweetnacl": {
95
+ "optional": true
89
96
  }
90
97
  },
91
98
  "files": [
@@ -30,7 +30,7 @@ const _decoder = new TextDecoder();
30
30
 
31
31
  /**
32
32
  * Default MeshNetwork configuration
33
- * @constant {Object}
33
+ * @constant {any}
34
34
  */
35
35
  const DEFAULT_CONFIG = Object.freeze({
36
36
  /** Display name for this node */
@@ -88,21 +88,21 @@ class MeshNetwork extends EventEmitter {
88
88
  * @param {Object} [config.encryption] - Encryption settings
89
89
  * @param {Object} [config.routing] - Routing settings
90
90
  * @param {Object} [config.compression] - Compression settings
91
- * @param {Object} [config.storeAndForward] - Store and forward settings
91
+ * @param {any} [config.storeAndForward] - Store and forward settings
92
92
  */
93
93
  constructor(config = {}) {
94
94
  super();
95
95
 
96
96
  /**
97
97
  * Configuration
98
- * @type {Object}
98
+ * @type {any}
99
99
  * @private
100
100
  */
101
101
  this._config = this._mergeConfig(DEFAULT_CONFIG, config);
102
102
 
103
103
  /**
104
104
  * Underlying MeshService
105
- * @type {MeshService}
105
+ * @type {InstanceType<typeof MeshService>}
106
106
  * @private
107
107
  */
108
108
  this._service = new MeshService({
@@ -111,7 +111,7 @@ class MeshNetwork extends EventEmitter {
111
111
 
112
112
  /**
113
113
  * Transport layer
114
- * @type {Transport|null}
114
+ * @type {any}
115
115
  * @private
116
116
  */
117
117
  this._transport = null;
@@ -180,7 +180,7 @@ class MeshNetwork extends EventEmitter {
180
180
 
181
181
  /**
182
182
  * Channel manager reference
183
- * @type {Object|null}
183
+ * @type {any}
184
184
  * @private
185
185
  */
186
186
  this._channels = null;
@@ -202,7 +202,7 @@ class MeshNetwork extends EventEmitter {
202
202
 
203
203
  /**
204
204
  * Starts the mesh network.
205
- * @param {Object} [transport] - Optional custom transport
205
+ * @param {any} [transport] - Optional custom transport
206
206
  * @returns {Promise<void>}
207
207
  */
208
208
  async start(transport) {
@@ -216,7 +216,7 @@ class MeshNetwork extends EventEmitter {
216
216
  const { RNBLEAdapter } = require('./transport/adapters');
217
217
  const adapter = new RNBLEAdapter();
218
218
  this._transport = new BLETransport(adapter);
219
- } catch (e) {
219
+ } catch (/** @type {any} */ e) {
220
220
  throw new MeshError(
221
221
  'No transport provided and BLE adapter not available. ' +
222
222
  'Either pass a transport to start(), install react-native-ble-plx for BLE, ' +
@@ -252,15 +252,15 @@ class MeshNetwork extends EventEmitter {
252
252
  }
253
253
 
254
254
  // Setup file transfer events
255
- this._fileManager.on('sendProgress', (info) => this.emit('fileSendProgress', info));
256
- this._fileManager.on('receiveProgress', (info) => this.emit('fileReceiveProgress', info));
257
- this._fileManager.on('fileReceived', (info) => this.emit('fileReceived', info));
258
- this._fileManager.on('transferFailed', (info) => this.emit('fileTransferFailed', info));
259
- this._fileManager.on('transferCancelled', (info) => this.emit('fileTransferCancelled', info));
255
+ this._fileManager.on('sendProgress', (/** @type {any} */ info) => this.emit('fileSendProgress', info));
256
+ this._fileManager.on('receiveProgress', (/** @type {any} */ info) => this.emit('fileReceiveProgress', info));
257
+ this._fileManager.on('fileReceived', (/** @type {any} */ info) => this.emit('fileReceived', info));
258
+ this._fileManager.on('transferFailed', (/** @type {any} */ info) => this.emit('fileTransferFailed', info));
259
+ this._fileManager.on('transferCancelled', (/** @type {any} */ info) => this.emit('fileTransferCancelled', info));
260
260
 
261
261
  // Start connection quality monitoring
262
262
  this._connectionQuality.start();
263
- this._connectionQuality.on('qualityChanged', (quality) => {
263
+ this._connectionQuality.on('qualityChanged', (/** @type {any} */ quality) => {
264
264
  this.emit('connectionQualityChanged', quality);
265
265
  });
266
266
 
@@ -352,9 +352,9 @@ class MeshNetwork extends EventEmitter {
352
352
  // If peer is offline and store-forward is enabled, cache the message
353
353
  if (this._storeForward && this._isPeerOffline(peerId)) {
354
354
  const payload = this._encodeMessage(text);
355
- await this._storeForward.cacheForOfflinePeer(peerId, payload, {
355
+ await this._storeForward.cacheForOfflinePeer(peerId, payload, /** @type {any} */ ({
356
356
  needsEncryption: true
357
- });
357
+ }));
358
358
  this.emit('messageCached', { peerId, text });
359
359
  return 'cached';
360
360
  }
@@ -410,7 +410,7 @@ class MeshNetwork extends EventEmitter {
410
410
 
411
411
  /**
412
412
  * Gets list of joined channels.
413
- * @returns {Object[]} Channels
413
+ * @returns {any[]} Channels
414
414
  */
415
415
  getChannels() {
416
416
  return this._service.getChannels();
@@ -422,7 +422,7 @@ class MeshNetwork extends EventEmitter {
422
422
 
423
423
  /**
424
424
  * Gets all known peers.
425
- * @returns {Object[]} Array of peers
425
+ * @returns {any[]} Array of peers
426
426
  */
427
427
  getPeers() {
428
428
  return this._service.getPeers();
@@ -430,7 +430,7 @@ class MeshNetwork extends EventEmitter {
430
430
 
431
431
  /**
432
432
  * Gets connected peers.
433
- * @returns {Object[]} Connected peers
433
+ * @returns {any[]} Connected peers
434
434
  */
435
435
  getConnectedPeers() {
436
436
  return this._service.getConnectedPeers();
@@ -438,7 +438,7 @@ class MeshNetwork extends EventEmitter {
438
438
 
439
439
  /**
440
440
  * Gets peers with secure sessions.
441
- * @returns {Object[]} Secured peers
441
+ * @returns {any[]} Secured peers
442
442
  */
443
443
  getSecuredPeers() {
444
444
  return this._service.getSecuredPeers();
@@ -468,7 +468,7 @@ class MeshNetwork extends EventEmitter {
468
468
 
469
469
  /**
470
470
  * Gets network health metrics.
471
- * @returns {Object} Health report
471
+ * @returns {any} Health report
472
472
  */
473
473
  getNetworkHealth() {
474
474
  return this._monitor.generateHealthReport();
@@ -477,7 +477,7 @@ class MeshNetwork extends EventEmitter {
477
477
  /**
478
478
  * Gets detailed health for a specific peer.
479
479
  * @param {string} peerId - Peer ID
480
- * @returns {Object|null} Node health
480
+ * @returns {any} Node health
481
481
  */
482
482
  getPeerHealth(peerId) {
483
483
  return this._monitor.getNodeHealth(peerId);
@@ -562,7 +562,7 @@ class MeshNetwork extends EventEmitter {
562
562
  * @param {Uint8Array} fileInfo.data - File data
563
563
  * @param {string} fileInfo.name - File name
564
564
  * @param {string} [fileInfo.mimeType] - MIME type
565
- * @returns {Object} Transfer info with id and event emitter
565
+ * @returns {Promise<any>} Transfer info with id and event emitter
566
566
  */
567
567
  async sendFile(peerId, fileInfo) {
568
568
  this._validateRunning();
@@ -572,6 +572,7 @@ class MeshNetwork extends EventEmitter {
572
572
  throw new ValidationError('File must have data and name', 'E800');
573
573
  }
574
574
 
575
+ /** @type {any} */
575
576
  const transfer = this._fileManager.prepareSend(peerId, fileInfo);
576
577
 
577
578
  // Send offer (JSON is OK for metadata, but use binary type marker)
@@ -611,14 +612,14 @@ class MeshNetwork extends EventEmitter {
611
612
  // Add per-chunk timeout (10 seconds)
612
613
  const sendPromise = this._service._sendRaw(peerId, payload);
613
614
  let timeoutId;
614
- const timeoutPromise = new Promise((_, reject) => {
615
+ const timeoutPromise = new Promise((/** @type {any} */ _, /** @type {any} */ reject) => {
615
616
  timeoutId = setTimeout(() => reject(new Error('Chunk send timeout')), 10000);
616
617
  });
617
618
 
618
619
  try {
619
620
  await Promise.race([sendPromise, timeoutPromise]);
620
621
  clearTimeout(timeoutId);
621
- } catch (err) {
622
+ } catch (/** @type {any} */ err) {
622
623
  clearTimeout(timeoutId);
623
624
  this._fileManager.cancelTransfer(transfer.id);
624
625
  this.emit('fileTransferFailed', {
@@ -635,7 +636,7 @@ class MeshNetwork extends EventEmitter {
635
636
 
636
637
  /**
637
638
  * Gets active file transfers
638
- * @returns {Object} { outgoing: [], incoming: [] }
639
+ * @returns {any} { outgoing: [], incoming: [] }
639
640
  */
640
641
  getActiveTransfers() {
641
642
  return this._fileManager.getActiveTransfers();
@@ -656,7 +657,7 @@ class MeshNetwork extends EventEmitter {
656
657
  /**
657
658
  * Gets connection quality for a specific peer.
658
659
  * @param {string} peerId - Peer ID
659
- * @returns {Object|null} Quality report
660
+ * @returns {any} Quality report
660
661
  */
661
662
  getConnectionQuality(peerId) {
662
663
  return this._connectionQuality.getQuality(peerId);
@@ -664,7 +665,7 @@ class MeshNetwork extends EventEmitter {
664
665
 
665
666
  /**
666
667
  * Gets connection quality for all peers.
667
- * @returns {Object[]} Array of quality reports
668
+ * @returns {any[]} Array of quality reports
668
669
  */
669
670
  getAllConnectionQuality() {
670
671
  return this._connectionQuality.getAllQuality();
@@ -676,7 +677,7 @@ class MeshNetwork extends EventEmitter {
676
677
 
677
678
  /**
678
679
  * Gets the network status.
679
- * @returns {Object} Status
680
+ * @returns {any} Status
680
681
  */
681
682
  getStatus() {
682
683
  const identity = this._state === 'running' ? this._service.getIdentity() : null;
@@ -693,7 +694,7 @@ class MeshNetwork extends EventEmitter {
693
694
 
694
695
  /**
695
696
  * Gets the identity information.
696
- * @returns {Object} Identity
697
+ * @returns {any} Identity
697
698
  */
698
699
  getIdentity() {
699
700
  return this._service.getIdentity();
@@ -714,9 +715,9 @@ class MeshNetwork extends EventEmitter {
714
715
 
715
716
  /**
716
717
  * Merges configuration with defaults.
717
- * @param {Object} defaults - Default config
718
- * @param {Object} custom - Custom config
719
- * @returns {Object} Merged config
718
+ * @param {any} defaults - Default config
719
+ * @param {any} custom - Custom config
720
+ * @returns {any} Merged config
720
721
  * @private
721
722
  */
722
723
  _mergeConfig(defaults, custom) {
@@ -738,12 +739,12 @@ class MeshNetwork extends EventEmitter {
738
739
  */
739
740
  _setupEventForwarding() {
740
741
  // Forward service events with PRD-style naming
741
- this._service.on(EVENTS.PEER_DISCOVERED, (peer) => {
742
+ this._service.on(EVENTS.PEER_DISCOVERED, (/** @type {any} */ peer) => {
742
743
  this._monitor.trackPeerDiscovered(peer.id);
743
744
  this.emit('peerDiscovered', peer);
744
745
  });
745
746
 
746
- this._service.on(EVENTS.PEER_CONNECTED, (peer) => {
747
+ this._service.on(EVENTS.PEER_CONNECTED, (/** @type {any} */ peer) => {
747
748
  if (peer.rssi) {
748
749
  this._connectionQuality.recordRssi(peer.id, peer.rssi);
749
750
  }
@@ -754,13 +755,13 @@ class MeshNetwork extends EventEmitter {
754
755
  }
755
756
  });
756
757
 
757
- this._service.on(EVENTS.PEER_DISCONNECTED, (peer) => {
758
+ this._service.on(EVENTS.PEER_DISCONNECTED, (/** @type {any} */ peer) => {
758
759
  this._monitor.trackPeerDisconnected(peer.id);
759
760
  this._connectionQuality.removePeer(peer.id);
760
761
  this.emit('peerDisconnected', peer);
761
762
  });
762
763
 
763
- this._service.on('message', (message) => {
764
+ this._service.on('message', (/** @type {any} */ message) => {
764
765
  this._monitor.trackMessageReceived(message.senderId);
765
766
  this.emit('messageReceived', {
766
767
  from: message.senderId,
@@ -770,7 +771,7 @@ class MeshNetwork extends EventEmitter {
770
771
  });
771
772
  });
772
773
 
773
- this._service.on('private-message', (message) => {
774
+ this._service.on('private-message', (/** @type {any} */ message) => {
774
775
  this.emit('directMessage', {
775
776
  from: message.senderId,
776
777
  text: message.content,
@@ -778,7 +779,7 @@ class MeshNetwork extends EventEmitter {
778
779
  });
779
780
  });
780
781
 
781
- this._service.on('channel-message', (message) => {
782
+ this._service.on('channel-message', (/** @type {any} */ message) => {
782
783
  this.emit('channelMessage', {
783
784
  channel: message.channelId,
784
785
  from: message.senderId,
@@ -787,22 +788,22 @@ class MeshNetwork extends EventEmitter {
787
788
  });
788
789
  });
789
790
 
790
- this._service.on('message-delivered', (info) => {
791
+ this._service.on('message-delivered', (/** @type {any} */ info) => {
791
792
  this._monitor.trackMessageDelivered(info.messageId);
792
793
  this.emit('messageDelivered', info);
793
794
  });
794
795
 
795
- this._service.on('error', (error) => {
796
+ this._service.on('error', (/** @type {any} */ error) => {
796
797
  this.emit('error', error);
797
798
  });
798
799
 
799
800
  // Forward monitor events
800
- this._monitor.on('health-changed', (info) => {
801
+ this._monitor.on('health-changed', (/** @type {any} */ info) => {
801
802
  this.emit('networkHealthChanged', info);
802
803
  });
803
804
 
804
805
  // Forward emergency events
805
- this._emergencyManager.on('panic-wipe-completed', (result) => {
806
+ this._emergencyManager.on('panic-wipe-completed', (/** @type {any} */ result) => {
806
807
  this.emit('dataWiped', result);
807
808
  });
808
809
  }
@@ -823,17 +824,18 @@ class MeshNetwork extends EventEmitter {
823
824
  async _deliverCachedMessages(peerId) {
824
825
  if (!this._storeForward) { return; }
825
826
 
826
- const sendFn = async (payload) => {
827
+ const sendFn = async (/** @type {any} */ payload) => {
827
828
  // Re-encrypt and send via the proper encrypted channel
828
829
  try {
829
830
  const text = _decoder.decode(payload);
830
831
  await this._service.sendPrivateMessage(peerId, text);
831
- } catch (e) {
832
+ } catch (/** @type {any} */ e) {
832
833
  // Fallback to raw send if encryption fails
833
834
  await this._service._sendRaw(peerId, payload);
834
835
  }
835
836
  };
836
837
 
838
+ /** @type {any} */
837
839
  const result = await this._storeForward.deliverCachedMessages(peerId, sendFn);
838
840
 
839
841
  if (result.delivered > 0) {
@@ -857,7 +859,7 @@ class MeshNetwork extends EventEmitter {
857
859
  // Clear store and forward cache
858
860
  if (this._storeForward) {
859
861
  this._emergencyManager.registerClearer(async () => {
860
- this._storeForward.clear();
862
+ this._storeForward?.clear();
861
863
  });
862
864
  }
863
865
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  /**
9
9
  * LC3 codec configuration
10
- * @constant {Object}
10
+ * @constant {any}
11
11
  */
12
12
  const LC3_CONFIG = Object.freeze({
13
13
  /** Supported sample rates (Hz) */
@@ -62,7 +62,7 @@ const AUDIO_QUALITY = Object.freeze({
62
62
 
63
63
  /**
64
64
  * Voice message configuration
65
- * @constant {Object}
65
+ * @constant {any}
66
66
  */
67
67
  const VOICE_MESSAGE_CONFIG = Object.freeze({
68
68
  /** Maximum voice message duration in seconds */
@@ -79,7 +79,7 @@ const VOICE_MESSAGE_CONFIG = Object.freeze({
79
79
 
80
80
  /**
81
81
  * Audio streaming configuration
82
- * @constant {Object}
82
+ * @constant {any}
83
83
  */
84
84
  const AUDIO_STREAM_CONFIG = Object.freeze({
85
85
  /** Default jitter buffer size in frames */
@@ -98,7 +98,7 @@ const AUDIO_STREAM_CONFIG = Object.freeze({
98
98
 
99
99
  /**
100
100
  * Audio session states
101
- * @constant {Object.<string, string>}
101
+ * @type {Record<string, string>}
102
102
  */
103
103
  const AUDIO_SESSION_STATE = Object.freeze({
104
104
  IDLE: 'idle',
@@ -77,7 +77,7 @@ const POWER_MODE = Object.freeze({
77
77
 
78
78
  /**
79
79
  * Bluetooth adapter states
80
- * @constant {Object.<string, string>}
80
+ * @type {Record<string, string>}
81
81
  */
82
82
  const BLUETOOTH_STATE = Object.freeze({
83
83
  UNKNOWN: 'unknown',
@@ -35,7 +35,7 @@ const NOISE_PROTOCOL_NAME = 'Noise_XX_25519_ChaChaPoly_SHA256';
35
35
 
36
36
  /**
37
37
  * Noise handshake states
38
- * @constant {Object.<string, string>}
38
+ * @type {Record<string, string>}
39
39
  */
40
40
  const NOISE_HANDSHAKE_STATE = Object.freeze({
41
41
  INITIAL: 'initial',
@@ -7,7 +7,7 @@
7
7
 
8
8
  /**
9
9
  * Error codes organized by category
10
- * @constant {Object.<string, string>}
10
+ * @type {Record<string, string>}
11
11
  */
12
12
  const ERROR_CODE = Object.freeze({
13
13
  // Initialization errors (E0xx)
@@ -108,7 +108,7 @@ const ERROR_CODE = Object.freeze({
108
108
 
109
109
  /**
110
110
  * Error messages for each error code
111
- * @constant {Object.<string, string>}
111
+ * @type {Record<string, string>}
112
112
  */
113
113
  const ERROR_MESSAGES = Object.freeze({
114
114
  E001: 'Initialization failed',
@@ -7,7 +7,7 @@
7
7
 
8
8
  /**
9
9
  * Event names for the mesh network
10
- * @constant {Object.<string, string>}
10
+ * @type {Record<string, string>}
11
11
  */
12
12
  const EVENTS = Object.freeze({
13
13
  // Lifecycle events
@@ -115,7 +115,7 @@ const MESH_CONFIG = Object.freeze({
115
115
 
116
116
  /**
117
117
  * Connection states
118
- * @constant {Object.<string, string>}
118
+ * @type {Record<string, string>}
119
119
  */
120
120
  const CONNECTION_STATE = Object.freeze({
121
121
  DISCONNECTED: 'disconnected',
@@ -129,7 +129,7 @@ const CONNECTION_STATE = Object.freeze({
129
129
 
130
130
  /**
131
131
  * Service states
132
- * @constant {Object.<string, string>}
132
+ * @type {Record<string, string>}
133
133
  */
134
134
  const SERVICE_STATE = Object.freeze({
135
135
  UNINITIALIZED: 'uninitialized',
@@ -64,7 +64,9 @@ function createProvider(config) {
64
64
  return detectProvider();
65
65
  }
66
66
 
67
+ // @ts-ignore
67
68
  if (typeof config === 'object' && typeof config.generateKeyPair === 'function') {
69
+ // @ts-ignore
68
70
  return config; // Already a provider instance
69
71
  }
70
72
 
@@ -37,53 +37,53 @@ class CryptoProvider {
37
37
 
38
38
  /**
39
39
  * Computes X25519 shared secret
40
- * @param {Uint8Array} secretKey - Our secret key (32 bytes)
41
- * @param {Uint8Array} publicKey - Their public key (32 bytes)
40
+ * @param {Uint8Array} _secretKey - Our secret key (32 bytes)
41
+ * @param {Uint8Array} _publicKey - Their public key (32 bytes)
42
42
  * @returns {Uint8Array} Shared secret (32 bytes)
43
43
  */
44
- sharedSecret(_secretKey, _publicKey) {
44
+ sharedSecret(/** @type {any} */ _secretKey, _publicKey) {
45
45
  throw new Error('CryptoProvider.sharedSecret() must be implemented');
46
46
  }
47
47
 
48
48
  /**
49
49
  * AEAD encrypt (XSalsa20-Poly1305 or ChaCha20-Poly1305)
50
- * @param {Uint8Array} key - Encryption key (32 bytes)
51
- * @param {Uint8Array} nonce - Nonce (24 bytes for XSalsa20, 12 for ChaCha20)
52
- * @param {Uint8Array} plaintext - Data to encrypt
53
- * @param {Uint8Array} [ad] - Additional authenticated data (optional)
50
+ * @param {Uint8Array} _key - Encryption key (32 bytes)
51
+ * @param {Uint8Array} _nonce - Nonce (24 bytes for XSalsa20, 12 for ChaCha20)
52
+ * @param {Uint8Array} _plaintext - Data to encrypt
53
+ * @param {Uint8Array} [_ad] - Additional authenticated data (optional)
54
54
  * @returns {Uint8Array} Ciphertext with authentication tag
55
55
  */
56
- encrypt(_key, _nonce, _plaintext, _ad) {
56
+ encrypt(/** @type {any} */ _key, _nonce, _plaintext, _ad) {
57
57
  throw new Error('CryptoProvider.encrypt() must be implemented');
58
58
  }
59
59
 
60
60
  /**
61
61
  * AEAD decrypt
62
- * @param {Uint8Array} key - Encryption key (32 bytes)
63
- * @param {Uint8Array} nonce - Nonce
64
- * @param {Uint8Array} ciphertext - Ciphertext with auth tag
65
- * @param {Uint8Array} [ad] - Additional authenticated data (optional)
62
+ * @param {Uint8Array} _key - Encryption key (32 bytes)
63
+ * @param {Uint8Array} _nonce - Nonce
64
+ * @param {Uint8Array} _ciphertext - Ciphertext with auth tag
65
+ * @param {Uint8Array} [_ad] - Additional authenticated data (optional)
66
66
  * @returns {Uint8Array|null} Plaintext or null if authentication fails
67
67
  */
68
- decrypt(_key, _nonce, _ciphertext, _ad) {
68
+ decrypt(/** @type {any} */ _key, _nonce, _ciphertext, _ad) {
69
69
  throw new Error('CryptoProvider.decrypt() must be implemented');
70
70
  }
71
71
 
72
72
  /**
73
73
  * Computes SHA-256 hash
74
- * @param {Uint8Array} data - Data to hash
74
+ * @param {Uint8Array} _data - Data to hash
75
75
  * @returns {Uint8Array} Hash (32 bytes)
76
76
  */
77
- hash(_data) {
77
+ hash(/** @type {any} */ _data) {
78
78
  throw new Error('CryptoProvider.hash() must be implemented');
79
79
  }
80
80
 
81
81
  /**
82
82
  * Generates cryptographically secure random bytes
83
- * @param {number} length - Number of bytes
83
+ * @param {number} _length - Number of bytes
84
84
  * @returns {Uint8Array} Random bytes
85
85
  */
86
- randomBytes(_length) {
86
+ randomBytes(/** @type {any} */ _length) {
87
87
  throw new Error('CryptoProvider.randomBytes() must be implemented');
88
88
  }
89
89
 
@@ -23,8 +23,10 @@ const CryptoProvider = require('../CryptoProvider');
23
23
  class ExpoCryptoProvider extends CryptoProvider {
24
24
  constructor(options = {}) {
25
25
  super();
26
- this._expoCrypto = options.expoCrypto || null;
27
- this._nacl = options.nacl || null;
26
+ /** @type {any} */
27
+ const opts = options;
28
+ this._expoCrypto = opts.expoCrypto || null;
29
+ this._nacl = opts.nacl || null;
28
30
  }
29
31
 
30
32
  get name() {
@@ -34,6 +36,7 @@ class ExpoCryptoProvider extends CryptoProvider {
34
36
  _getExpoCrypto() {
35
37
  if (!this._expoCrypto) {
36
38
  try {
39
+ // @ts-ignore
37
40
  this._expoCrypto = require('expo-crypto');
38
41
  } catch (e) {
39
42
  throw new Error('expo-crypto is required. Install: npx expo install expo-crypto');
@@ -45,6 +48,7 @@ class ExpoCryptoProvider extends CryptoProvider {
45
48
  _getNacl() {
46
49
  if (!this._nacl) {
47
50
  try {
51
+ // @ts-ignore
48
52
  this._nacl = require('tweetnacl');
49
53
  } catch (e) {
50
54
  throw new Error('tweetnacl is required with ExpoCryptoProvider. Install: npm install tweetnacl');
@@ -61,13 +65,13 @@ class ExpoCryptoProvider extends CryptoProvider {
61
65
  }
62
66
 
63
67
  /** @inheritdoc */
64
- sharedSecret(secretKey, publicKey) {
68
+ sharedSecret(/** @type {any} */ secretKey, /** @type {any} */ publicKey) {
65
69
  const nacl = this._getNacl();
66
70
  return nacl.box.before(publicKey, secretKey);
67
71
  }
68
72
 
69
73
  /** @inheritdoc */
70
- encrypt(key, nonce, plaintext, _ad) {
74
+ encrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ plaintext, /** @type {any} */ _ad) {
71
75
  const nacl = this._getNacl();
72
76
 
73
77
  // Ensure 24-byte nonce (pad short nonces with zeros)
@@ -81,7 +85,7 @@ class ExpoCryptoProvider extends CryptoProvider {
81
85
  }
82
86
 
83
87
  /** @inheritdoc */
84
- decrypt(key, nonce, ciphertext, _ad) {
88
+ decrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ ciphertext, /** @type {any} */ _ad) {
85
89
  const nacl = this._getNacl();
86
90
 
87
91
  // Ensure 24-byte nonce (pad short nonces with zeros)
@@ -95,14 +99,14 @@ class ExpoCryptoProvider extends CryptoProvider {
95
99
  }
96
100
 
97
101
  /** @inheritdoc */
98
- hash(data) {
102
+ hash(/** @type {any} */ data) {
99
103
  // expo-crypto's digestStringAsync is async — for sync compat, use tweetnacl
100
104
  const nacl = this._getNacl();
101
105
  return nacl.hash(data).subarray(0, 32);
102
106
  }
103
107
 
104
108
  /** @inheritdoc */
105
- randomBytes(length) {
109
+ randomBytes(/** @type {any} */ length) {
106
110
  const expoCrypto = this._getExpoCrypto();
107
111
  if (expoCrypto.getRandomBytes) {
108
112
  const bytes = expoCrypto.getRandomBytes(length);
@@ -115,6 +119,7 @@ class ExpoCryptoProvider extends CryptoProvider {
115
119
 
116
120
  static isAvailable() {
117
121
  try {
122
+ // @ts-ignore
118
123
  require('expo-crypto');
119
124
  return true;
120
125
  } catch (e) {