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
@@ -10,10 +10,11 @@
10
10
 
11
11
  const Transport = require('./Transport');
12
12
  const { ConnectionError } = require('../errors');
13
+ const base64 = require('../utils/base64');
13
14
 
14
15
  /**
15
16
  * Wi-Fi Direct transport states
16
- * @constant {Object}
17
+ * @constant {any}
17
18
  */
18
19
  const WIFI_DIRECT_STATE = Object.freeze({
19
20
  AVAILABLE: 'available',
@@ -46,6 +47,7 @@ class WiFiDirectTransport extends Transport {
46
47
  this._isDiscovering = false;
47
48
  this._isGroupOwner = false;
48
49
  this._groupInfo = null;
50
+ /** @type {any} */
49
51
  this._subscriptions = [];
50
52
  }
51
53
 
@@ -75,16 +77,16 @@ class WiFiDirectTransport extends Transport {
75
77
 
76
78
  try {
77
79
  const p2p = this._getWifiP2p();
78
- await p2p.initialize();
80
+ await p2p?.initialize();
79
81
 
80
82
  // Check if Wi-Fi Direct is supported
81
- const isAvailable = await p2p.isSuccessfulInitialize();
83
+ const isAvailable = await p2p?.isSuccessfulInitialize();
82
84
  if (!isAvailable) {
83
85
  throw new ConnectionError('Wi-Fi Direct is not available on this device', 'E100');
84
86
  }
85
87
 
86
88
  this._setState(Transport.STATE.RUNNING);
87
- } catch (error) {
89
+ } catch (/** @type {any} */ error) {
88
90
  this._setState(Transport.STATE.ERROR);
89
91
  throw error;
90
92
  }
@@ -107,13 +109,13 @@ class WiFiDirectTransport extends Transport {
107
109
 
108
110
  // Disconnect from group
109
111
  try {
110
- await p2p.removeGroup();
112
+ await p2p?.removeGroup();
111
113
  } catch (e) {
112
114
  // Ignore — may not be in a group
113
115
  }
114
116
 
115
117
  // Cleanup subscriptions
116
- this._subscriptions.forEach(sub => {
118
+ this._subscriptions.forEach((/** @type {any} */ sub) => {
117
119
  if (sub && typeof sub.remove === 'function') { sub.remove(); }
118
120
  });
119
121
  this._subscriptions = [];
@@ -132,7 +134,7 @@ class WiFiDirectTransport extends Transport {
132
134
  if (!this.isRunning || this._isDiscovering) { return; }
133
135
 
134
136
  const p2p = this._getWifiP2p();
135
- await p2p.discoverPeers();
137
+ await p2p?.discoverPeers();
136
138
  this._isDiscovering = true;
137
139
  this.emit('discoveryStarted');
138
140
  }
@@ -146,7 +148,7 @@ class WiFiDirectTransport extends Transport {
146
148
 
147
149
  const p2p = this._getWifiP2p();
148
150
  try {
149
- await p2p.stopDiscoveringPeers();
151
+ await p2p?.stopDiscoveringPeers();
150
152
  } catch (e) {
151
153
  // Ignore
152
154
  }
@@ -173,9 +175,9 @@ class WiFiDirectTransport extends Transport {
173
175
  const p2p = this._getWifiP2p();
174
176
 
175
177
  try {
176
- await p2p.connect(peerId);
178
+ await p2p?.connect(peerId);
177
179
 
178
- const connectionInfo = await p2p.getConnectionInfo();
180
+ const connectionInfo = await p2p?.getConnectionInfo();
179
181
  this._isGroupOwner = connectionInfo.isGroupOwner || false;
180
182
  this._groupInfo = connectionInfo;
181
183
 
@@ -187,7 +189,7 @@ class WiFiDirectTransport extends Transport {
187
189
  });
188
190
 
189
191
  this.emit('peerConnected', { peerId, transport: 'wifi-direct' });
190
- } catch (error) {
192
+ } catch (/** @type {any} */ error) {
191
193
  throw ConnectionError.connectionFailed(peerId, { cause: error.message });
192
194
  }
193
195
  }
@@ -202,7 +204,7 @@ class WiFiDirectTransport extends Transport {
202
204
 
203
205
  const p2p = this._getWifiP2p();
204
206
  try {
205
- await p2p.removeGroup();
207
+ await p2p?.removeGroup();
206
208
  } catch (e) {
207
209
  // Ignore
208
210
  }
@@ -227,14 +229,14 @@ class WiFiDirectTransport extends Transport {
227
229
  const peerInfo = this._peers.get(peerId);
228
230
 
229
231
  // Convert Uint8Array to base64 for transfer
230
- const base64 = this._uint8ArrayToBase64(data);
232
+ const encoded = this._uint8ArrayToBase64(data);
231
233
 
232
234
  if (this._isGroupOwner) {
233
235
  // Group owner sends via server socket
234
- await p2p.sendMessage(base64);
236
+ await p2p?.sendMessage(encoded);
235
237
  } else {
236
238
  // Client sends to group owner address
237
- await p2p.sendMessageTo(peerInfo.groupOwnerAddress, this._port, base64);
239
+ await p2p?.sendMessageTo(peerInfo.groupOwnerAddress, this._port, encoded);
238
240
  }
239
241
  }
240
242
 
@@ -261,16 +263,20 @@ class WiFiDirectTransport extends Transport {
261
263
  if (!this.isRunning) { return []; }
262
264
  const p2p = this._getWifiP2p();
263
265
  try {
264
- return await p2p.getAvailablePeers();
266
+ return await p2p?.getAvailablePeers();
265
267
  } catch (e) {
266
268
  return [];
267
269
  }
268
270
  }
269
271
 
270
- /** @private */
272
+ /**
273
+ * @private
274
+ * @returns {any}
275
+ */
271
276
  _getWifiP2p() {
272
277
  if (!this._wifiP2p) {
273
278
  try {
279
+ // @ts-ignore
274
280
  this._wifiP2p = require('react-native-wifi-p2p');
275
281
  } catch (e) {
276
282
  throw new Error(
@@ -283,13 +289,8 @@ class WiFiDirectTransport extends Transport {
283
289
  }
284
290
 
285
291
  /** @private */
286
- _uint8ArrayToBase64(bytes) {
287
- const chunks = [];
288
- for (let i = 0; i < bytes.length; i += 8192) {
289
- chunks.push(String.fromCharCode.apply(null, bytes.subarray(i, Math.min(i + 8192, bytes.length))));
290
- }
291
- const binary = chunks.join('');
292
- return typeof btoa !== 'undefined' ? btoa(binary) : Buffer.from(bytes).toString('base64');
292
+ _uint8ArrayToBase64(/** @type {any} */ bytes) {
293
+ return base64.encode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
293
294
  }
294
295
  }
295
296
 
@@ -17,12 +17,12 @@ const { BLUETOOTH_STATE } = require('../../constants');
17
17
  class BLEAdapter {
18
18
  /**
19
19
  * Creates a new BLEAdapter instance
20
- * @param {Object} [options={}] - Adapter options
20
+ * @param {any} [options={}] - Adapter options
21
21
  */
22
22
  constructor(options = {}) {
23
23
  /**
24
24
  * Adapter options
25
- * @type {Object}
25
+ * @type {any}
26
26
  * @protected
27
27
  */
28
28
  this._options = options;
@@ -73,12 +73,12 @@ class BLEAdapter {
73
73
  /**
74
74
  * Starts scanning for BLE devices
75
75
  * @abstract
76
- * @param {string[]} serviceUUIDs - Service UUIDs to filter by
77
- * @param {Function} callback - Callback for discovered devices
76
+ * @param {string[]} _serviceUUIDs - Service UUIDs to filter by
77
+ * @param {Function} _callback - Callback for discovered devices
78
78
  * @returns {Promise<void>}
79
79
  * @throws {Error} If not implemented by subclass
80
80
  */
81
- async startScan(_serviceUUIDs, _callback) {
81
+ async startScan(/** @type {any} */ _serviceUUIDs, _callback) {
82
82
  throw new Error('BLEAdapter.startScan() must be implemented by subclass');
83
83
  }
84
84
 
@@ -94,50 +94,50 @@ class BLEAdapter {
94
94
  /**
95
95
  * Connects to a BLE device
96
96
  * @abstract
97
- * @param {string} deviceId - Device ID to connect to
97
+ * @param {string} _deviceId - Device ID to connect to
98
98
  * @returns {Promise<Object>} Connected device info
99
99
  * @throws {Error} If not implemented by subclass
100
100
  */
101
- async connect(_deviceId) {
101
+ async connect(/** @type {any} */ _deviceId) {
102
102
  throw new Error('BLEAdapter.connect() must be implemented by subclass');
103
103
  }
104
104
 
105
105
  /**
106
106
  * Disconnects from a BLE device
107
107
  * @abstract
108
- * @param {string} deviceId - Device ID to disconnect from
108
+ * @param {string} _deviceId - Device ID to disconnect from
109
109
  * @returns {Promise<void>}
110
110
  * @throws {Error} If not implemented by subclass
111
111
  */
112
- async disconnect(_deviceId) {
112
+ async disconnect(/** @type {any} */ _deviceId) {
113
113
  throw new Error('BLEAdapter.disconnect() must be implemented by subclass');
114
114
  }
115
115
 
116
116
  /**
117
117
  * Writes data to a characteristic
118
118
  * @abstract
119
- * @param {string} deviceId - Target device ID
120
- * @param {string} serviceUUID - Service UUID
121
- * @param {string} charUUID - Characteristic UUID
122
- * @param {Uint8Array} data - Data to write
119
+ * @param {string} _deviceId - Target device ID
120
+ * @param {string} _serviceUUID - Service UUID
121
+ * @param {string} _charUUID - Characteristic UUID
122
+ * @param {Uint8Array} _data - Data to write
123
123
  * @returns {Promise<void>}
124
124
  * @throws {Error} If not implemented by subclass
125
125
  */
126
- async write(_deviceId, _serviceUUID, _charUUID, _data) {
126
+ async write(/** @type {any} */ _deviceId, _serviceUUID, _charUUID, _data) {
127
127
  throw new Error('BLEAdapter.write() must be implemented by subclass');
128
128
  }
129
129
 
130
130
  /**
131
131
  * Subscribes to characteristic notifications
132
132
  * @abstract
133
- * @param {string} deviceId - Target device ID
134
- * @param {string} serviceUUID - Service UUID
135
- * @param {string} charUUID - Characteristic UUID
136
- * @param {Function} callback - Notification callback
133
+ * @param {string} _deviceId - Target device ID
134
+ * @param {string} _serviceUUID - Service UUID
135
+ * @param {string} _charUUID - Characteristic UUID
136
+ * @param {Function} _callback - Notification callback
137
137
  * @returns {Promise<void>}
138
138
  * @throws {Error} If not implemented by subclass
139
139
  */
140
- async subscribe(_deviceId, _serviceUUID, _charUUID, _callback) {
140
+ async subscribe(/** @type {any} */ _deviceId, _serviceUUID, _charUUID, _callback) {
141
141
  throw new Error('BLEAdapter.subscribe() must be implemented by subclass');
142
142
  }
143
143
 
@@ -21,35 +21,35 @@ class NodeBLEAdapter extends BLEAdapter {
21
21
  /**
22
22
  * Creates a new NodeBLEAdapter instance
23
23
  * @param {Object} [options={}] - Adapter options
24
- * @param {Object} [options.noble] - Noble instance
24
+ * @param {any} [options.noble] - Noble instance
25
25
  */
26
26
  constructor(options = {}) {
27
27
  super(options);
28
28
 
29
29
  /**
30
30
  * Noble instance
31
- * @type {Object|null}
31
+ * @type {any}
32
32
  * @private
33
33
  */
34
34
  this._noble = options.noble || null;
35
35
 
36
36
  /**
37
37
  * Connected peripherals map
38
- * @type {Map<string, Object>}
38
+ * @type {Map<string, any>}
39
39
  * @private
40
40
  */
41
41
  this._peripherals = new Map();
42
42
 
43
43
  /**
44
44
  * Discovered peripherals cache
45
- * @type {Map<string, Object>}
45
+ * @type {Map<string, any>}
46
46
  * @private
47
47
  */
48
48
  this._discoveredPeripherals = new Map();
49
49
 
50
50
  /**
51
51
  * Subscription handlers map
52
- * @type {Map<string, Object>}
52
+ * @type {Map<string, any>}
53
53
  * @private
54
54
  */
55
55
  this._subscriptions = new Map();
@@ -82,6 +82,7 @@ class NodeBLEAdapter extends BLEAdapter {
82
82
  // Try to load noble if not provided
83
83
  if (!this._noble) {
84
84
  try {
85
+ // @ts-ignore
85
86
  this._noble = require('@abandonware/noble');
86
87
  } catch (error) {
87
88
  throw new Error(
@@ -91,7 +92,7 @@ class NodeBLEAdapter extends BLEAdapter {
91
92
  }
92
93
 
93
94
  // Set up state change listener
94
- this._noble.on('stateChange', (state) => {
95
+ this._noble.on('stateChange', (/** @type {any} */ state) => {
95
96
  this._notifyStateChange(this._mapState(state));
96
97
  });
97
98
 
@@ -141,7 +142,7 @@ class NodeBLEAdapter extends BLEAdapter {
141
142
  uuid.toLowerCase().replace(/-/g, '')
142
143
  );
143
144
 
144
- this._noble.on('discover', (peripheral) => {
145
+ this._noble.on('discover', (/** @type {any} */ peripheral) => {
145
146
  this._discoveredPeripherals.set(peripheral.id, peripheral);
146
147
 
147
148
  if (this._scanCallback) {
@@ -284,7 +285,7 @@ class NodeBLEAdapter extends BLEAdapter {
284
285
  throw new Error(`Characteristic ${charUUID} not found`);
285
286
  }
286
287
 
287
- characteristic.on('data', (data) => {
288
+ characteristic.on('data', (/** @type {any} */ data) => {
288
289
  callback(new Uint8Array(data));
289
290
  });
290
291
 
@@ -318,7 +319,7 @@ class NodeBLEAdapter extends BLEAdapter {
318
319
  poweredOff: BLEAdapter.STATE.POWERED_OFF,
319
320
  poweredOn: BLEAdapter.STATE.POWERED_ON
320
321
  };
321
- return stateMap[state] || BLEAdapter.STATE.UNKNOWN;
322
+ return /** @type {any} */ (stateMap)[state] || BLEAdapter.STATE.UNKNOWN;
322
323
  }
323
324
 
324
325
  /**
@@ -336,7 +337,7 @@ class NodeBLEAdapter extends BLEAdapter {
336
337
  reject(new Error('Bluetooth initialization timeout'));
337
338
  }, 10000);
338
339
 
339
- this._noble.once('stateChange', (state) => {
340
+ this._noble.once('stateChange', (/** @type {any} */ state) => {
340
341
  clearTimeout(timeout);
341
342
  if (state === 'poweredOn') {
342
343
  resolve();
@@ -349,13 +350,13 @@ class NodeBLEAdapter extends BLEAdapter {
349
350
 
350
351
  /**
351
352
  * Connects to a peripheral
352
- * @param {Object} peripheral - Noble peripheral
353
+ * @param {any} peripheral - Noble peripheral
353
354
  * @returns {Promise<void>}
354
355
  * @private
355
356
  */
356
357
  _connectPeripheral(peripheral) {
357
358
  return new Promise((resolve, reject) => {
358
- peripheral.connect((error) => {
359
+ peripheral.connect((/** @type {any} */ error) => {
359
360
  if (error) { reject(error); } else { resolve(); }
360
361
  });
361
362
  });
@@ -363,7 +364,7 @@ class NodeBLEAdapter extends BLEAdapter {
363
364
 
364
365
  /**
365
366
  * Disconnects from a peripheral
366
- * @param {Object} peripheral - Noble peripheral
367
+ * @param {any} peripheral - Noble peripheral
367
368
  * @returns {Promise<void>}
368
369
  * @private
369
370
  */
@@ -375,13 +376,13 @@ class NodeBLEAdapter extends BLEAdapter {
375
376
 
376
377
  /**
377
378
  * Discovers services and characteristics
378
- * @param {Object} peripheral - Noble peripheral
379
+ * @param {any} peripheral - Noble peripheral
379
380
  * @returns {Promise<void>}
380
381
  * @private
381
382
  */
382
383
  _discoverServices(peripheral) {
383
384
  return new Promise((resolve, reject) => {
384
- peripheral.discoverAllServicesAndCharacteristics((error) => {
385
+ peripheral.discoverAllServicesAndCharacteristics((/** @type {any} */ error) => {
385
386
  if (error) { reject(error); } else { resolve(); }
386
387
  });
387
388
  });
@@ -389,10 +390,10 @@ class NodeBLEAdapter extends BLEAdapter {
389
390
 
390
391
  /**
391
392
  * Finds a characteristic on a peripheral
392
- * @param {Object} peripheral - Noble peripheral
393
+ * @param {any} peripheral - Noble peripheral
393
394
  * @param {string} serviceUUID - Service UUID
394
395
  * @param {string} charUUID - Characteristic UUID
395
- * @returns {Object|null} Characteristic or null
396
+ * @returns {any} Characteristic or null
396
397
  * @private
397
398
  */
398
399
  _findCharacteristic(peripheral, serviceUUID, charUUID) {
@@ -400,23 +401,23 @@ class NodeBLEAdapter extends BLEAdapter {
400
401
  const formattedCharUUID = charUUID.toLowerCase().replace(/-/g, '');
401
402
 
402
403
  const service = peripheral.services?.find(
403
- s => s.uuid === formattedServiceUUID
404
+ (/** @type {any} */ s) => s.uuid === formattedServiceUUID
404
405
  );
405
406
  return service?.characteristics?.find(
406
- c => c.uuid === formattedCharUUID
407
+ (/** @type {any} */ c) => c.uuid === formattedCharUUID
407
408
  ) || null;
408
409
  }
409
410
 
410
411
  /**
411
412
  * Writes to a characteristic
412
- * @param {Object} characteristic - Noble characteristic
413
+ * @param {any} characteristic - Noble characteristic
413
414
  * @param {Buffer} data - Data to write
414
415
  * @returns {Promise<void>}
415
416
  * @private
416
417
  */
417
418
  _writeCharacteristic(characteristic, data) {
418
419
  return new Promise((resolve, reject) => {
419
- characteristic.write(data, false, (error) => {
420
+ characteristic.write(data, false, (/** @type {any} */ error) => {
420
421
  if (error) { reject(error); } else { resolve(); }
421
422
  });
422
423
  });
@@ -424,13 +425,13 @@ class NodeBLEAdapter extends BLEAdapter {
424
425
 
425
426
  /**
426
427
  * Subscribes to a characteristic
427
- * @param {Object} characteristic - Noble characteristic
428
+ * @param {any} characteristic - Noble characteristic
428
429
  * @returns {Promise<void>}
429
430
  * @private
430
431
  */
431
432
  _subscribeCharacteristic(characteristic) {
432
433
  return new Promise((resolve, reject) => {
433
- characteristic.subscribe((error) => {
434
+ characteristic.subscribe((/** @type {any} */ error) => {
434
435
  if (error) { reject(error); } else { resolve(); }
435
436
  });
436
437
  });
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  const BLEAdapter = require('./BLEAdapter');
9
+ const base64 = require('../../utils/base64');
9
10
 
10
11
  /**
11
12
  * React Native BLE adapter implementation.
@@ -21,14 +22,14 @@ class RNBLEAdapter extends BLEAdapter {
21
22
  /**
22
23
  * Creates a new RNBLEAdapter instance
23
24
  * @param {Object} [options={}] - Adapter options
24
- * @param {Object} [options.BleManager] - BleManager class from react-native-ble-plx
25
+ * @param {any} [options.BleManager] - BleManager class from react-native-ble-plx
25
26
  */
26
27
  constructor(options = {}) {
27
28
  super(options);
28
29
 
29
30
  /**
30
31
  * BleManager instance
31
- * @type {Object|null}
32
+ * @type {any}
32
33
  * @private
33
34
  */
34
35
  this._manager = null;
@@ -45,32 +46,33 @@ class RNBLEAdapter extends BLEAdapter {
45
46
  * @type {string|null}
46
47
  * @private
47
48
  */
49
+ // @ts-ignore
48
50
  this._restoreIdentifier = options.restoreIdentifier || null;
49
51
 
50
52
  /**
51
53
  * Connected devices map
52
- * @type {Map<string, Object>}
54
+ * @type {Map<string, any>}
53
55
  * @private
54
56
  */
55
57
  this._devices = new Map();
56
58
 
57
59
  /**
58
60
  * Subscription handlers map
59
- * @type {Map<string, Object>}
61
+ * @type {Map<string, any>}
60
62
  * @private
61
63
  */
62
64
  this._subscriptions = new Map();
63
65
 
64
66
  /**
65
67
  * Scan subscription reference
66
- * @type {Object|null}
68
+ * @type {any}
67
69
  * @private
68
70
  */
69
71
  this._scanSubscription = null;
70
72
 
71
73
  /**
72
74
  * State subscription reference
73
- * @type {Object|null}
75
+ * @type {any}
74
76
  * @private
75
77
  */
76
78
  this._stateSubscription = null;
@@ -96,6 +98,7 @@ class RNBLEAdapter extends BLEAdapter {
96
98
  // Try to load BleManager if not provided
97
99
  if (!this._BleManager) {
98
100
  try {
101
+ // @ts-ignore
99
102
  const blePlx = require('react-native-ble-plx');
100
103
  this._BleManager = blePlx.BleManager;
101
104
  } catch (error) {
@@ -108,7 +111,7 @@ class RNBLEAdapter extends BLEAdapter {
108
111
  const managerOptions = {};
109
112
  if (this._restoreIdentifier) {
110
113
  managerOptions.restoreStateIdentifier = this._restoreIdentifier;
111
- managerOptions.restoreStateFunction = (restoredState) => {
114
+ managerOptions.restoreStateFunction = (/** @type {any} */ restoredState) => {
112
115
  // Re-populate devices from restored state
113
116
  if (restoredState && restoredState.connectedPeripherals) {
114
117
  for (const peripheral of restoredState.connectedPeripherals) {
@@ -117,10 +120,11 @@ class RNBLEAdapter extends BLEAdapter {
117
120
  }
118
121
  };
119
122
  }
123
+ // @ts-ignore
120
124
  this._manager = new this._BleManager(managerOptions);
121
125
 
122
126
  // Subscribe to state changes
123
- this._stateSubscription = this._manager.onStateChange((state) => {
127
+ this._stateSubscription = this._manager.onStateChange((/** @type {any} */ state) => {
124
128
  this._notifyStateChange(this._mapState(state));
125
129
  }, true);
126
130
 
@@ -174,7 +178,7 @@ class RNBLEAdapter extends BLEAdapter {
174
178
  async startScan(serviceUUIDs, callback) {
175
179
  this._ensureInitialized();
176
180
 
177
- this._manager.startDeviceScan(serviceUUIDs, null, (error, device) => {
181
+ this._manager.startDeviceScan(serviceUUIDs, null, (/** @type {any} */ error, /** @type {any} */ device) => {
178
182
  if (error) {
179
183
  return;
180
184
  }
@@ -292,7 +296,7 @@ class RNBLEAdapter extends BLEAdapter {
292
296
  deviceId,
293
297
  serviceUUID,
294
298
  charUUID,
295
- (error, characteristic) => {
299
+ (/** @type {any} */ error, /** @type {any} */ characteristic) => {
296
300
  if (!error && characteristic) {
297
301
  const data = this._base64ToUint8Array(characteristic.value);
298
302
  callback(data);
@@ -328,7 +332,7 @@ class RNBLEAdapter extends BLEAdapter {
328
332
  PoweredOff: BLEAdapter.STATE.POWERED_OFF,
329
333
  PoweredOn: BLEAdapter.STATE.POWERED_ON
330
334
  };
331
- return stateMap[state] || BLEAdapter.STATE.UNKNOWN;
335
+ return /** @type {any} */ (stateMap)[state] || BLEAdapter.STATE.UNKNOWN;
332
336
  }
333
337
 
334
338
  /**
@@ -357,26 +361,17 @@ class RNBLEAdapter extends BLEAdapter {
357
361
  * @private
358
362
  */
359
363
  _uint8ArrayToBase64(bytes) {
360
- let binary = '';
361
- for (let i = 0; i < bytes.length; i++) {
362
- binary += String.fromCharCode(bytes[i]);
363
- }
364
- return btoa(binary);
364
+ return base64.encode(bytes);
365
365
  }
366
366
 
367
367
  /**
368
368
  * Converts Base64 string to Uint8Array
369
- * @param {string} base64 - Base64 string
369
+ * @param {string} base64Str - Base64 string
370
370
  * @returns {Uint8Array} Byte array
371
371
  * @private
372
372
  */
373
- _base64ToUint8Array(base64) {
374
- const binary = atob(base64);
375
- const bytes = new Uint8Array(binary.length);
376
- for (let i = 0; i < binary.length; i++) {
377
- bytes[i] = binary.charCodeAt(i);
378
- }
379
- return bytes;
373
+ _base64ToUint8Array(base64Str) {
374
+ return base64.decode(base64Str);
380
375
  }
381
376
  }
382
377
 
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ /* global __DEV__ */
2
3
 
3
4
  /**
4
5
  * @fileoverview Enhanced EventEmitter class
@@ -12,8 +13,8 @@
12
13
  class EventEmitter {
13
14
  /**
14
15
  * Creates a new EventEmitter
15
- * @param {Object} [options] - Configuration options
16
- * @param {number} [options.maxListeners=10] - Maximum listeners per event
16
+ * @param {any} [options] - Configuration options
17
+ *
17
18
  */
18
19
  constructor(options = {}) {
19
20
  /**
@@ -47,14 +48,17 @@ class EventEmitter {
47
48
  }
48
49
 
49
50
  const listeners = this._events.get(event);
51
+ if (!listeners) { return this; }
50
52
 
51
53
  // Warn if max listeners exceeded
52
54
  if (listeners.length >= this._maxListeners) {
53
- console.warn(
54
- 'MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ' +
55
- `${listeners.length + 1} ${event} listeners added. ` +
56
- 'Use setMaxListeners() to increase limit'
57
- );
55
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
56
+ console.warn(
57
+ 'MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ' +
58
+ `${listeners.length + 1} ${event} listeners added. ` +
59
+ 'Use setMaxListeners() to increase limit'
60
+ );
61
+ }
58
62
  }
59
63
 
60
64
  listeners.push({ listener, once: false });
@@ -76,7 +80,7 @@ class EventEmitter {
76
80
  this._events.set(event, []);
77
81
  }
78
82
 
79
- this._events.get(event).push({ listener, once: true });
83
+ this._events.get(event)?.push({ listener, once: true });
80
84
  return this;
81
85
  }
82
86
 
@@ -92,13 +96,13 @@ class EventEmitter {
92
96
  }
93
97
 
94
98
  const listeners = this._events.get(event);
95
- const index = listeners.findIndex(entry => entry.listener === listener);
99
+ const index = listeners?.findIndex(entry => entry.listener === listener) ?? -1;
96
100
 
97
101
  if (index !== -1) {
98
- listeners.splice(index, 1);
102
+ listeners?.splice(index, 1);
99
103
  }
100
104
 
101
- if (listeners.length === 0) {
105
+ if (listeners?.length === 0) {
102
106
  this._events.delete(event);
103
107
  }
104
108
 
@@ -117,6 +121,7 @@ class EventEmitter {
117
121
  }
118
122
 
119
123
  const listeners = this._events.get(event);
124
+ if (!listeners) { return false; }
120
125
  const hasOnce = listeners.some(e => e.once);
121
126
  const iterList = hasOnce ? listeners.slice() : listeners;
122
127
 
@@ -169,7 +174,7 @@ class EventEmitter {
169
174
  if (!this._events.has(event)) {
170
175
  return 0;
171
176
  }
172
- return this._events.get(event).length;
177
+ return this._events.get(event)?.length ?? 0;
173
178
  }
174
179
 
175
180
  /**