react-native-ble-mesh 2.1.0 → 2.1.2
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/package.json +1 -1
- package/src/MeshNetwork.js +48 -46
- package/src/constants/audio.js +4 -4
- package/src/constants/ble.js +1 -1
- package/src/constants/crypto.js +1 -1
- package/src/constants/errors.js +2 -2
- package/src/constants/events.js +1 -1
- package/src/constants/protocol.js +2 -2
- package/src/crypto/AutoCrypto.js +2 -0
- package/src/crypto/CryptoProvider.js +17 -17
- package/src/crypto/providers/ExpoCryptoProvider.js +12 -7
- package/src/crypto/providers/QuickCryptoProvider.js +12 -7
- package/src/crypto/providers/TweetNaClProvider.js +9 -7
- package/src/errors/AudioError.js +2 -1
- package/src/errors/ConnectionError.js +2 -2
- package/src/errors/CryptoError.js +1 -1
- package/src/errors/HandshakeError.js +2 -2
- package/src/errors/MeshError.js +4 -4
- package/src/errors/MessageError.js +2 -2
- package/src/errors/ValidationError.js +3 -3
- package/src/expo/withBLEMesh.js +10 -10
- package/src/hooks/AppStateManager.js +2 -1
- package/src/hooks/useMesh.js +7 -7
- package/src/hooks/useMessages.js +13 -12
- package/src/hooks/usePeers.js +10 -9
- package/src/index.js +2 -2
- package/src/mesh/dedup/BloomFilter.js +1 -0
- package/src/mesh/dedup/DedupManager.js +4 -7
- package/src/mesh/dedup/MessageCache.js +3 -0
- package/src/mesh/fragment/Assembler.js +5 -4
- package/src/mesh/fragment/Fragmenter.js +2 -2
- package/src/mesh/monitor/ConnectionQuality.js +17 -8
- package/src/mesh/monitor/NetworkMonitor.js +22 -15
- package/src/mesh/peer/Peer.js +4 -9
- package/src/mesh/peer/PeerDiscovery.js +18 -19
- package/src/mesh/peer/PeerManager.js +14 -14
- package/src/mesh/router/MessageRouter.js +15 -15
- package/src/mesh/router/PathFinder.js +10 -13
- package/src/mesh/router/RouteTable.js +8 -7
- package/src/mesh/store/StoreAndForwardManager.js +20 -23
- package/src/protocol/message.js +5 -13
- package/src/protocol/serializer.js +4 -4
- package/src/protocol/validator.js +7 -6
- package/src/service/BatteryOptimizer.js +18 -17
- package/src/service/EmergencyManager.js +18 -25
- package/src/service/HandshakeManager.js +100 -2
- package/src/service/MeshService.js +106 -22
- package/src/service/SessionManager.js +38 -3
- package/src/service/audio/AudioManager.js +80 -38
- package/src/service/audio/buffer/FrameBuffer.js +7 -8
- package/src/service/audio/buffer/JitterBuffer.js +1 -1
- package/src/service/audio/codec/LC3Codec.js +18 -19
- package/src/service/audio/codec/LC3Decoder.js +10 -10
- package/src/service/audio/codec/LC3Encoder.js +11 -9
- package/src/service/audio/session/AudioSession.js +14 -17
- package/src/service/audio/session/VoiceMessage.js +15 -22
- package/src/service/audio/transport/AudioFragmenter.js +17 -9
- package/src/service/audio/transport/AudioFramer.js +8 -12
- package/src/service/file/FileAssembler.js +4 -2
- package/src/service/file/FileChunker.js +1 -1
- package/src/service/file/FileManager.js +26 -20
- package/src/service/file/FileMessage.js +7 -12
- package/src/service/text/TextManager.js +55 -28
- package/src/service/text/broadcast/BroadcastManager.js +14 -17
- package/src/service/text/channel/Channel.js +10 -14
- package/src/service/text/channel/ChannelManager.js +10 -10
- package/src/service/text/message/TextMessage.js +12 -19
- package/src/service/text/message/TextSerializer.js +2 -2
- package/src/storage/AsyncStorageAdapter.js +17 -14
- package/src/storage/MemoryStorage.js +11 -8
- package/src/storage/MessageStore.js +22 -30
- package/src/storage/Storage.js +9 -9
- package/src/transport/BLETransport.js +16 -14
- package/src/transport/MockTransport.js +7 -2
- package/src/transport/MultiTransport.js +13 -6
- package/src/transport/Transport.js +9 -9
- package/src/transport/WiFiDirectTransport.js +22 -17
- package/src/transport/adapters/BLEAdapter.js +19 -19
- package/src/transport/adapters/NodeBLEAdapter.js +24 -23
- package/src/transport/adapters/RNBLEAdapter.js +14 -11
- package/src/utils/EventEmitter.js +9 -7
- package/src/utils/LRUCache.js +10 -4
- package/src/utils/RateLimiter.js +1 -1
- package/src/utils/compression.js +5 -5
- package/src/utils/encoding.js +8 -2
- package/src/utils/retry.js +11 -13
- package/src/utils/time.js +9 -4
- 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.
|
|
3
|
+
"version": "2.1.2",
|
|
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",
|
package/src/MeshNetwork.js
CHANGED
|
@@ -30,7 +30,7 @@ const _decoder = new TextDecoder();
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Default MeshNetwork configuration
|
|
33
|
-
* @constant {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
718
|
-
* @param {
|
|
719
|
-
* @returns {
|
|
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
|
|
862
|
+
this._storeForward?.clear();
|
|
861
863
|
});
|
|
862
864
|
}
|
|
863
865
|
|
package/src/constants/audio.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* LC3 codec configuration
|
|
10
|
-
* @constant {
|
|
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 {
|
|
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 {
|
|
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
|
-
* @
|
|
101
|
+
* @type {Record<string, string>}
|
|
102
102
|
*/
|
|
103
103
|
const AUDIO_SESSION_STATE = Object.freeze({
|
|
104
104
|
IDLE: 'idle',
|
package/src/constants/ble.js
CHANGED
package/src/constants/crypto.js
CHANGED
package/src/constants/errors.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Error codes organized by category
|
|
10
|
-
* @
|
|
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
|
-
* @
|
|
111
|
+
* @type {Record<string, string>}
|
|
112
112
|
*/
|
|
113
113
|
const ERROR_MESSAGES = Object.freeze({
|
|
114
114
|
E001: 'Initialization failed',
|
package/src/constants/events.js
CHANGED
|
@@ -115,7 +115,7 @@ const MESH_CONFIG = Object.freeze({
|
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* Connection states
|
|
118
|
-
* @
|
|
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
|
-
* @
|
|
132
|
+
* @type {Record<string, string>}
|
|
133
133
|
*/
|
|
134
134
|
const SERVICE_STATE = Object.freeze({
|
|
135
135
|
UNINITIALIZED: 'uninitialized',
|
package/src/crypto/AutoCrypto.js
CHANGED
|
@@ -37,53 +37,53 @@ class CryptoProvider {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Computes X25519 shared secret
|
|
40
|
-
* @param {Uint8Array}
|
|
41
|
-
* @param {Uint8Array}
|
|
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}
|
|
51
|
-
* @param {Uint8Array}
|
|
52
|
-
* @param {Uint8Array}
|
|
53
|
-
* @param {Uint8Array} [
|
|
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}
|
|
63
|
-
* @param {Uint8Array}
|
|
64
|
-
* @param {Uint8Array}
|
|
65
|
-
* @param {Uint8Array} [
|
|
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}
|
|
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}
|
|
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
|
-
|
|
27
|
-
|
|
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) {
|