react-native-ble-mesh 2.0.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.
Files changed (93) hide show
  1. package/README.md +2 -2
  2. package/docs/OPTIMIZATION.md +165 -52
  3. package/package.json +1 -1
  4. package/src/MeshNetwork.js +63 -53
  5. package/src/constants/audio.js +4 -4
  6. package/src/constants/ble.js +1 -1
  7. package/src/constants/crypto.js +1 -1
  8. package/src/constants/errors.js +2 -2
  9. package/src/constants/events.js +1 -1
  10. package/src/constants/protocol.js +2 -2
  11. package/src/crypto/AutoCrypto.js +16 -3
  12. package/src/crypto/CryptoProvider.js +17 -17
  13. package/src/crypto/providers/ExpoCryptoProvider.js +15 -9
  14. package/src/crypto/providers/QuickCryptoProvider.js +41 -12
  15. package/src/crypto/providers/TweetNaClProvider.js +10 -8
  16. package/src/errors/AudioError.js +2 -1
  17. package/src/errors/ConnectionError.js +2 -2
  18. package/src/errors/CryptoError.js +1 -1
  19. package/src/errors/HandshakeError.js +2 -2
  20. package/src/errors/MeshError.js +4 -4
  21. package/src/errors/MessageError.js +2 -2
  22. package/src/errors/ValidationError.js +3 -3
  23. package/src/expo/withBLEMesh.js +10 -10
  24. package/src/hooks/AppStateManager.js +11 -2
  25. package/src/hooks/useMesh.js +23 -10
  26. package/src/hooks/useMessages.js +17 -16
  27. package/src/hooks/usePeers.js +19 -14
  28. package/src/index.js +2 -2
  29. package/src/mesh/dedup/BloomFilter.js +45 -57
  30. package/src/mesh/dedup/DedupManager.js +36 -8
  31. package/src/mesh/dedup/MessageCache.js +3 -0
  32. package/src/mesh/fragment/Assembler.js +5 -4
  33. package/src/mesh/fragment/Fragmenter.js +3 -3
  34. package/src/mesh/monitor/ConnectionQuality.js +59 -25
  35. package/src/mesh/monitor/NetworkMonitor.js +80 -28
  36. package/src/mesh/peer/Peer.js +9 -11
  37. package/src/mesh/peer/PeerDiscovery.js +18 -19
  38. package/src/mesh/peer/PeerManager.js +29 -17
  39. package/src/mesh/router/MessageRouter.js +28 -20
  40. package/src/mesh/router/PathFinder.js +10 -13
  41. package/src/mesh/router/RouteTable.js +25 -14
  42. package/src/mesh/store/StoreAndForwardManager.js +32 -24
  43. package/src/protocol/deserializer.js +9 -10
  44. package/src/protocol/header.js +13 -7
  45. package/src/protocol/message.js +18 -14
  46. package/src/protocol/serializer.js +9 -12
  47. package/src/protocol/validator.js +29 -10
  48. package/src/service/BatteryOptimizer.js +22 -18
  49. package/src/service/EmergencyManager.js +18 -25
  50. package/src/service/HandshakeManager.js +112 -18
  51. package/src/service/MeshService.js +106 -22
  52. package/src/service/SessionManager.js +50 -13
  53. package/src/service/audio/AudioManager.js +80 -38
  54. package/src/service/audio/buffer/FrameBuffer.js +7 -8
  55. package/src/service/audio/buffer/JitterBuffer.js +1 -1
  56. package/src/service/audio/codec/LC3Codec.js +18 -19
  57. package/src/service/audio/codec/LC3Decoder.js +10 -10
  58. package/src/service/audio/codec/LC3Encoder.js +11 -9
  59. package/src/service/audio/session/AudioSession.js +14 -17
  60. package/src/service/audio/session/VoiceMessage.js +15 -22
  61. package/src/service/audio/transport/AudioFragmenter.js +17 -9
  62. package/src/service/audio/transport/AudioFramer.js +8 -12
  63. package/src/service/file/FileAssembler.js +4 -2
  64. package/src/service/file/FileChunker.js +1 -1
  65. package/src/service/file/FileManager.js +26 -20
  66. package/src/service/file/FileMessage.js +7 -12
  67. package/src/service/text/TextManager.js +75 -42
  68. package/src/service/text/broadcast/BroadcastManager.js +14 -17
  69. package/src/service/text/channel/Channel.js +10 -14
  70. package/src/service/text/channel/ChannelManager.js +10 -10
  71. package/src/service/text/message/TextMessage.js +12 -19
  72. package/src/service/text/message/TextSerializer.js +2 -2
  73. package/src/storage/AsyncStorageAdapter.js +17 -14
  74. package/src/storage/MemoryStorage.js +11 -8
  75. package/src/storage/MessageStore.js +77 -32
  76. package/src/storage/Storage.js +9 -9
  77. package/src/transport/BLETransport.js +27 -16
  78. package/src/transport/MockTransport.js +7 -2
  79. package/src/transport/MultiTransport.js +43 -11
  80. package/src/transport/Transport.js +9 -9
  81. package/src/transport/WiFiDirectTransport.js +26 -20
  82. package/src/transport/adapters/BLEAdapter.js +19 -19
  83. package/src/transport/adapters/NodeBLEAdapter.js +24 -23
  84. package/src/transport/adapters/RNBLEAdapter.js +14 -11
  85. package/src/utils/EventEmitter.js +15 -16
  86. package/src/utils/LRUCache.js +10 -4
  87. package/src/utils/RateLimiter.js +1 -1
  88. package/src/utils/bytes.js +12 -10
  89. package/src/utils/compression.js +10 -8
  90. package/src/utils/encoding.js +39 -8
  91. package/src/utils/retry.js +11 -13
  92. package/src/utils/time.js +9 -4
  93. package/src/utils/validation.js +1 -1
@@ -16,6 +16,12 @@ const { randomBytes } = require('../utils/bytes');
16
16
  */
17
17
  const HEADER_SIZE = 48;
18
18
 
19
+ // Pre-computed hex lookup table (avoids Array.from().map().join() per call)
20
+ const HEX_TABLE = new Array(256);
21
+ for (let i = 0; i < 256; i++) {
22
+ HEX_TABLE[i] = (i < 16 ? '0' : '') + i.toString(16);
23
+ }
24
+
19
25
  /**
20
26
  * Message header class representing the 48-byte header structure.
21
27
  * @class MessageHeader
@@ -43,7 +49,6 @@ class MessageHeader {
43
49
  this.flags = options.flags ?? MESSAGE_FLAGS.NONE;
44
50
  this.hopCount = options.hopCount ?? 0;
45
51
  this.maxHops = options.maxHops ?? MESH_CONFIG.MAX_HOPS;
46
- this.reserved = new Uint8Array(3);
47
52
  this.messageId = options.messageId;
48
53
  this.timestamp = options.timestamp;
49
54
  this.expiresAt = options.expiresAt;
@@ -143,9 +148,8 @@ class MessageHeader {
143
148
  view.setUint16(40, header.payloadLength, false);
144
149
  buffer[42] = header.fragmentIndex;
145
150
  buffer[43] = header.fragmentTotal;
146
- // Calculate checksum over header without checksum field
147
- const checksumData = buffer.slice(0, 44);
148
- const checksum = crc32(checksumData);
151
+ // Calculate checksum over header without checksum field (subarray = zero-copy view)
152
+ const checksum = crc32(buffer.subarray(0, 44));
149
153
  view.setUint32(44, checksum, false);
150
154
  header.checksum = checksum;
151
155
 
@@ -204,9 +208,11 @@ function writeUint64BE(view, offset, value) {
204
208
  * @returns {string} Hex string
205
209
  */
206
210
  function bytesToHex(bytes) {
207
- return Array.from(bytes)
208
- .map(b => b.toString(16).padStart(2, '0'))
209
- .join('');
211
+ let hex = '';
212
+ for (let i = 0; i < bytes.length; i++) {
213
+ hex += HEX_TABLE[bytes[i]];
214
+ }
215
+ return hex;
210
216
  }
211
217
 
212
218
  module.exports = {
@@ -9,6 +9,18 @@ const { MessageHeader, HEADER_SIZE, generateUuid } = require('./header');
9
9
  const { MESSAGE_FLAGS, MESH_CONFIG } = require('../constants');
10
10
  const { MessageError } = require('../errors');
11
11
 
12
+ // Cached TextEncoder/TextDecoder singletons (avoids per-call allocation)
13
+ /** @type {any} */ let _encoder = null;
14
+ /** @type {any} */ let _decoder = null;
15
+ function _getEncoder() {
16
+ if (!_encoder) { _encoder = new TextEncoder(); }
17
+ return _encoder;
18
+ }
19
+ function _getDecoder() {
20
+ if (!_decoder) { _decoder = new TextDecoder(); }
21
+ return _decoder;
22
+ }
23
+
12
24
  /**
13
25
  * Message class representing a complete mesh network message.
14
26
  * @class Message
@@ -16,11 +28,11 @@ const { MessageError } = require('../errors');
16
28
  class Message {
17
29
  /**
18
30
  * Creates a new Message instance.
19
- * @param {MessageHeader} header - Message header
31
+ * @param {any} header - Message header
20
32
  * @param {Uint8Array} payload - Message payload
21
33
  */
22
34
  constructor(header, payload) {
23
- /** @type {MessageHeader} */
35
+ /** @type {any} */
24
36
  this.header = header;
25
37
  /** @type {Uint8Array} */
26
38
  this.payload = payload;
@@ -28,15 +40,7 @@ class Message {
28
40
 
29
41
  /**
30
42
  * Creates a new message with the given options.
31
- * @param {Object} options - Message options
32
- * @param {number} options.type - Message type from MESSAGE_TYPE
33
- * @param {Uint8Array|string} options.payload - Message payload
34
- * @param {number} [options.flags=0] - Message flags
35
- * @param {number} [options.maxHops=7] - Maximum hops
36
- * @param {number} [options.ttlMs] - Time-to-live in ms
37
- * @param {number} [options.fragmentIndex=0] - Fragment index
38
- * @param {number} [options.fragmentTotal=1] - Total fragments
39
- * @param {Uint8Array} [options.messageId] - Optional message ID
43
+ * @param {any} options - Message options *
40
44
  * @returns {Message} New message instance
41
45
  */
42
46
  static create(options) {
@@ -44,7 +48,7 @@ class Message {
44
48
 
45
49
  // Convert string payload to bytes
46
50
  if (typeof payload === 'string') {
47
- payload = new TextEncoder().encode(payload);
51
+ payload = _getEncoder().encode(payload);
48
52
  }
49
53
 
50
54
  if (!(payload instanceof Uint8Array)) {
@@ -99,7 +103,7 @@ class Message {
99
103
  });
100
104
  }
101
105
 
102
- const payload = data.slice(HEADER_SIZE, HEADER_SIZE + header.payloadLength);
106
+ const payload = data.subarray(HEADER_SIZE, HEADER_SIZE + header.payloadLength);
103
107
 
104
108
  return new Message(header, payload);
105
109
  }
@@ -171,7 +175,7 @@ class Message {
171
175
  * @returns {string} Decoded payload content
172
176
  */
173
177
  getContent() {
174
- return new TextDecoder().decode(this.payload);
178
+ return _getDecoder().decode(this.payload);
175
179
  }
176
180
 
177
181
  /**
@@ -15,7 +15,7 @@ const { MessageError } = require('../errors');
15
15
  * Serializes a message header to bytes.
16
16
  * Calculates CRC32 checksum and includes it in the output.
17
17
  *
18
- * @param {MessageHeader|Object} header - Header to serialize
18
+ * @param {any} header - Header to serialize
19
19
  * @returns {Uint8Array} 48-byte serialized header
20
20
  * @throws {MessageError} If header is invalid
21
21
  *
@@ -71,9 +71,8 @@ function serializeHeader(header) {
71
71
  // Byte 43: fragmentTotal
72
72
  buffer[43] = header.fragmentTotal ?? 1;
73
73
 
74
- // Bytes 44-47: checksum (calculated over bytes 0-43)
75
- const checksumData = buffer.slice(0, 44);
76
- const checksum = crc32(checksumData);
74
+ // Bytes 44-47: checksum (calculated over bytes 0-43, subarray = zero-copy view)
75
+ const checksum = crc32(buffer.subarray(0, 44));
77
76
  view.setUint32(44, checksum, false);
78
77
 
79
78
  return buffer;
@@ -82,7 +81,7 @@ function serializeHeader(header) {
82
81
  /**
83
82
  * Serializes a complete message (header + payload) to bytes.
84
83
  *
85
- * @param {Message|Object} message - Message to serialize
84
+ * @param {any} message - Message to serialize
86
85
  * @returns {Uint8Array} Serialized message bytes
87
86
  * @throws {MessageError} If message is invalid
88
87
  *
@@ -110,7 +109,8 @@ function serialize(message) {
110
109
 
111
110
  // Convert string payload to bytes
112
111
  if (typeof payload === 'string') {
113
- payload = new TextEncoder().encode(payload);
112
+ if (!(/** @type {any} */ (serialize))._encoder) { /** @type {any} */ (serialize)._encoder = new TextEncoder(); }
113
+ payload = /** @type {any} */ (serialize)._encoder.encode(payload);
114
114
  }
115
115
 
116
116
  // Default to empty payload
@@ -122,13 +122,10 @@ function serialize(message) {
122
122
  throw MessageError.invalidFormat(null, { reason: 'Payload must be Uint8Array or string' });
123
123
  }
124
124
 
125
- // Update payloadLength in header
126
- const headerWithLength = {
127
- ...header,
128
- payloadLength: payload.length
129
- };
125
+ // Update payloadLength directly (avoids object spread allocation)
126
+ header.payloadLength = payload.length;
130
127
 
131
- const headerBytes = serializeHeader(headerWithLength);
128
+ const headerBytes = serializeHeader(header);
132
129
  const result = new Uint8Array(headerBytes.length + payload.length);
133
130
 
134
131
  result.set(headerBytes, 0);
@@ -13,12 +13,19 @@ const { PROTOCOL_VERSION, MESSAGE_TYPE, MESH_CONFIG } = require('../constants');
13
13
  * Set of valid message type values for fast lookup.
14
14
  * @type {Set<number>}
15
15
  */
16
- const VALID_MESSAGE_TYPES = new Set(Object.values(MESSAGE_TYPE));
16
+ const VALID_MESSAGE_TYPES = new Set(/** @type {number[]} */ (Object.values(MESSAGE_TYPE)));
17
+
18
+ /**
19
+ * Cached frozen result for valid validations to avoid repeated allocations.
20
+ * @type {{ valid: boolean, errors: string[] }}
21
+ */
22
+ // @ts-ignore
23
+ const VALID_RESULT = /** @type {{ valid: boolean, errors: string[] }} */ (Object.freeze({ valid: true, errors: Object.freeze([]) }));
17
24
 
18
25
  /**
19
26
  * Validates a message header.
20
27
  *
21
- * @param {MessageHeader|Object} header - Header to validate
28
+ * @param {any} header - Header to validate
22
29
  * @returns {{ valid: boolean, errors: string[] }} Validation result
23
30
  *
24
31
  * @example
@@ -102,8 +109,12 @@ function validateHeader(header) {
102
109
  errors.push(`Fragment index (${header.fragmentIndex}) >= total (${header.fragmentTotal})`);
103
110
  }
104
111
 
112
+ if (errors.length === 0) {
113
+ return VALID_RESULT;
114
+ }
115
+
105
116
  return {
106
- valid: errors.length === 0,
117
+ valid: false,
107
118
  errors
108
119
  };
109
120
  }
@@ -111,7 +122,7 @@ function validateHeader(header) {
111
122
  /**
112
123
  * Validates a complete message (header + payload).
113
124
  *
114
- * @param {Message|Object} message - Message to validate
125
+ * @param {any} message - Message to validate
115
126
  * @returns {{ valid: boolean, errors: string[] }} Validation result
116
127
  *
117
128
  * @example
@@ -152,8 +163,12 @@ function validateMessage(message) {
152
163
  }
153
164
  }
154
165
 
166
+ if (errors.length === 0) {
167
+ return VALID_RESULT;
168
+ }
169
+
155
170
  return {
156
- valid: errors.length === 0,
171
+ valid: false,
157
172
  errors
158
173
  };
159
174
  }
@@ -171,7 +186,7 @@ function validateChecksum(headerBytes) {
171
186
 
172
187
  const view = new DataView(headerBytes.buffer, headerBytes.byteOffset, HEADER_SIZE);
173
188
  const storedChecksum = view.getUint32(44, false);
174
- const checksumData = headerBytes.slice(0, 44);
189
+ const checksumData = headerBytes.subarray(0, 44);
175
190
  const calculatedChecksum = crc32(checksumData);
176
191
 
177
192
  return {
@@ -194,7 +209,7 @@ function isValidMessageType(type) {
194
209
  /**
195
210
  * Checks if a message is expired.
196
211
  *
197
- * @param {Message|MessageHeader|Object} messageOrHeader - Message or header
212
+ * @param {any} messageOrHeader - Message or header
198
213
  * @returns {boolean} True if expired
199
214
  */
200
215
  function isExpired(messageOrHeader) {
@@ -205,7 +220,7 @@ function isExpired(messageOrHeader) {
205
220
  /**
206
221
  * Checks if hop count has exceeded maximum.
207
222
  *
208
- * @param {Message|MessageHeader|Object} messageOrHeader - Message or header
223
+ * @param {any} messageOrHeader - Message or header
209
224
  * @returns {boolean} True if exceeded
210
225
  */
211
226
  function hasExceededMaxHops(messageOrHeader) {
@@ -242,7 +257,7 @@ function validateRawMessage(data) {
242
257
  }
243
258
 
244
259
  // Validate checksum
245
- const checksumResult = validateChecksum(data.slice(0, HEADER_SIZE));
260
+ const checksumResult = validateChecksum(data.subarray(0, HEADER_SIZE));
246
261
  if (!checksumResult.valid) {
247
262
  errors.push(
248
263
  `Checksum mismatch: expected 0x${checksumResult.expected.toString(16)}, ` +
@@ -259,8 +274,12 @@ function validateRawMessage(data) {
259
274
  errors.push(`Incomplete message: expected ${expectedTotal} bytes, got ${data.length}`);
260
275
  }
261
276
 
277
+ if (errors.length === 0) {
278
+ return VALID_RESULT;
279
+ }
280
+
262
281
  return {
263
- valid: errors.length === 0,
282
+ valid: false,
264
283
  errors
265
284
  };
266
285
  }
@@ -14,7 +14,7 @@ const EventEmitter = require('../utils/EventEmitter');
14
14
 
15
15
  /**
16
16
  * Battery mode constants
17
- * @constant {Object}
17
+ * @constant {any}
18
18
  */
19
19
  const BATTERY_MODE = Object.freeze({
20
20
  HIGH_PERFORMANCE: 'high',
@@ -23,6 +23,9 @@ const BATTERY_MODE = Object.freeze({
23
23
  AUTO: 'auto'
24
24
  });
25
25
 
26
+ /** Pre-computed Set of valid battery modes for O(1) lookup */
27
+ const BATTERY_MODE_SET = new Set(Object.values(BATTERY_MODE));
28
+
26
29
  /**
27
30
  * Battery profile configuration
28
31
  * @typedef {Object} BatteryProfile
@@ -36,7 +39,7 @@ const BATTERY_MODE = Object.freeze({
36
39
 
37
40
  /**
38
41
  * Default battery profiles
39
- * @constant {Object.<string, BatteryProfile>}
42
+ * @constant {Record<string, BatteryProfile>}
40
43
  */
41
44
  const DEFAULT_PROFILES = Object.freeze({
42
45
  [BATTERY_MODE.HIGH_PERFORMANCE]: {
@@ -76,7 +79,7 @@ const DEFAULT_PROFILES = Object.freeze({
76
79
 
77
80
  /**
78
81
  * Battery level thresholds for auto mode
79
- * @constant {Object}
82
+ * @constant {any}
80
83
  */
81
84
  const BATTERY_THRESHOLDS = Object.freeze({
82
85
  HIGH: 50, // Above 50%: high performance
@@ -87,7 +90,7 @@ const BATTERY_THRESHOLDS = Object.freeze({
87
90
 
88
91
  /**
89
92
  * Default configuration
90
- * @constant {Object}
93
+ * @constant {any}
91
94
  */
92
95
  const DEFAULT_CONFIG = Object.freeze({
93
96
  /** Initial battery mode */
@@ -125,21 +128,21 @@ const DEFAULT_CONFIG = Object.freeze({
125
128
  class BatteryOptimizer extends EventEmitter {
126
129
  /**
127
130
  * Creates a new BatteryOptimizer instance.
128
- * @param {Object} [options={}] - Configuration options
131
+ * @param {any} [options] - Configuration options
129
132
  */
130
133
  constructor(options = {}) {
131
134
  super();
132
135
 
133
136
  /**
134
137
  * Configuration
135
- * @type {Object}
138
+ * @type {any}
136
139
  * @private
137
140
  */
138
141
  this._config = { ...DEFAULT_CONFIG, ...options };
139
142
 
140
143
  /**
141
144
  * Battery profiles
142
- * @type {Object.<string, BatteryProfile>}
145
+ * @type {Record<string, any>}
143
146
  * @private
144
147
  */
145
148
  this._profiles = { ...DEFAULT_PROFILES };
@@ -181,21 +184,21 @@ class BatteryOptimizer extends EventEmitter {
181
184
 
182
185
  /**
183
186
  * Battery check timer
184
- * @type {number|null}
187
+ * @type {any}
185
188
  * @private
186
189
  */
187
190
  this._batteryCheckTimer = null;
188
191
 
189
192
  /**
190
193
  * Transport reference for applying settings
191
- * @type {Object|null}
194
+ * @type {any}
192
195
  * @private
193
196
  */
194
197
  this._transport = null;
195
198
 
196
199
  /**
197
200
  * Statistics
198
- * @type {Object}
201
+ * @type {any}
199
202
  * @private
200
203
  */
201
204
  this._stats = {
@@ -212,7 +215,7 @@ class BatteryOptimizer extends EventEmitter {
212
215
 
213
216
  /**
214
217
  * Sets the transport to control.
215
- * @param {Object} transport - Transport instance
218
+ * @param {any} transport - Transport instance
216
219
  */
217
220
  setTransport(transport) {
218
221
  this._transport = transport;
@@ -224,7 +227,8 @@ class BatteryOptimizer extends EventEmitter {
224
227
  * @returns {Promise<void>}
225
228
  */
226
229
  async setMode(mode) {
227
- if (!Object.values(BATTERY_MODE).includes(mode)) {
230
+ // @ts-ignore
231
+ if (!BATTERY_MODE_SET.has(mode)) {
228
232
  throw new Error(`Invalid battery mode: ${mode}`);
229
233
  }
230
234
 
@@ -259,7 +263,7 @@ class BatteryOptimizer extends EventEmitter {
259
263
 
260
264
  /**
261
265
  * Gets the current active profile.
262
- * @returns {BatteryProfile} Active profile
266
+ * @returns {any} Active profile
263
267
  */
264
268
  getCurrentProfile() {
265
269
  if (this._currentMode === BATTERY_MODE.AUTO) {
@@ -270,7 +274,7 @@ class BatteryOptimizer extends EventEmitter {
270
274
 
271
275
  /**
272
276
  * Gets all available profiles.
273
- * @returns {Object.<string, BatteryProfile>} Profiles
277
+ * @returns {Record<string, any>} Profiles
274
278
  */
275
279
  getProfiles() {
276
280
  return { ...this._profiles };
@@ -347,7 +351,7 @@ class BatteryOptimizer extends EventEmitter {
347
351
 
348
352
  /**
349
353
  * Gets optimizer statistics.
350
- * @returns {Object} Statistics
354
+ * @returns {any} Statistics
351
355
  */
352
356
  getStats() {
353
357
  return {
@@ -371,7 +375,7 @@ class BatteryOptimizer extends EventEmitter {
371
375
  /**
372
376
  * Gets the appropriate profile for a battery level.
373
377
  * @param {number} level - Battery level
374
- * @returns {BatteryProfile} Profile
378
+ * @returns {any} Profile
375
379
  * @private
376
380
  */
377
381
  _getProfileForBatteryLevel(level) {
@@ -411,7 +415,7 @@ class BatteryOptimizer extends EventEmitter {
411
415
 
412
416
  /**
413
417
  * Applies a battery profile to the transport.
414
- * @param {BatteryProfile} profile - Profile to apply
418
+ * @param {any} profile - Profile to apply
415
419
  * @returns {Promise<void>}
416
420
  * @private
417
421
  */
@@ -442,7 +446,7 @@ class BatteryOptimizer extends EventEmitter {
442
446
  }
443
447
 
444
448
  this.emit('profile-applied', { profile });
445
- } catch (error) {
449
+ } catch (/** @type {any} */ error) {
446
450
  this.emit('error', {
447
451
  message: 'Failed to apply battery profile',
448
452
  error: error.message
@@ -13,7 +13,7 @@ const EventEmitter = require('../utils/EventEmitter');
13
13
 
14
14
  /**
15
15
  * Panic trigger types
16
- * @constant {Object}
16
+ * @constant {any}
17
17
  */
18
18
  const PANIC_TRIGGER = Object.freeze({
19
19
  TRIPLE_TAP: 'triple_tap',
@@ -24,7 +24,7 @@ const PANIC_TRIGGER = Object.freeze({
24
24
 
25
25
  /**
26
26
  * Default configuration
27
- * @constant {Object}
27
+ * @constant {any}
28
28
  */
29
29
  const DEFAULT_CONFIG = Object.freeze({
30
30
  /** Trigger type for panic mode */
@@ -63,18 +63,14 @@ const DEFAULT_CONFIG = Object.freeze({
63
63
  class EmergencyManager extends EventEmitter {
64
64
  /**
65
65
  * Creates a new EmergencyManager instance.
66
- * @param {Object} [options={}] - Configuration options
67
- * @param {string} [options.trigger='triple_tap'] - Panic trigger type
68
- * @param {number} [options.tapWindowMs=500] - Time window for taps
69
- * @param {number} [options.tapCount=3] - Required tap count
70
- * @param {boolean} [options.requireConfirmation=false] - Require confirmation
66
+ * @param {any} [options] - Configuration options
71
67
  */
72
68
  constructor(options = {}) {
73
69
  super();
74
70
 
75
71
  /**
76
72
  * Configuration
77
- * @type {Object}
73
+ * @type {any}
78
74
  * @private
79
75
  */
80
76
  this._config = { ...DEFAULT_CONFIG, ...options };
@@ -88,7 +84,7 @@ class EmergencyManager extends EventEmitter {
88
84
 
89
85
  /**
90
86
  * Tap tracking
91
- * @type {Object}
87
+ * @type {any}
92
88
  * @private
93
89
  */
94
90
  this._tapState = {
@@ -98,7 +94,7 @@ class EmergencyManager extends EventEmitter {
98
94
 
99
95
  /**
100
96
  * Shake tracking
101
- * @type {Object}
97
+ * @type {any}
102
98
  * @private
103
99
  */
104
100
  this._shakeState = {
@@ -122,7 +118,7 @@ class EmergencyManager extends EventEmitter {
122
118
 
123
119
  /**
124
120
  * Statistics
125
- * @type {Object}
121
+ * @type {any}
126
122
  * @private
127
123
  */
128
124
  this._stats = {
@@ -134,9 +130,7 @@ class EmergencyManager extends EventEmitter {
134
130
 
135
131
  /**
136
132
  * Enables panic mode.
137
- * @param {Object} [options={}] - Enable options
138
- * @param {Function} [options.onWipe] - Callback after wipe
139
- * @param {string} [options.trigger] - Override trigger type
133
+ * @param {any} [options] - Enable options
140
134
  */
141
135
  enablePanicMode(options = {}) {
142
136
  this._enabled = true;
@@ -208,10 +202,7 @@ class EmergencyManager extends EventEmitter {
208
202
 
209
203
  /**
210
204
  * Registers accelerometer data for shake detection.
211
- * @param {Object} data - Accelerometer data
212
- * @param {number} data.x - X acceleration
213
- * @param {number} data.y - Y acceleration
214
- * @param {number} data.z - Z acceleration
205
+ * @param {any} data - Accelerometer data
215
206
  */
216
207
  registerAccelerometer(data) {
217
208
  if (!this._enabled || this._config.trigger !== PANIC_TRIGGER.SHAKE) {
@@ -236,7 +227,7 @@ class EmergencyManager extends EventEmitter {
236
227
 
237
228
  /**
238
229
  * Manually triggers panic wipe.
239
- * @returns {Promise<Object>} Wipe result
230
+ * @returns {Promise<any>} Wipe result
240
231
  */
241
232
  async triggerManualWipe() {
242
233
  return this._executeWipe(PANIC_TRIGGER.MANUAL);
@@ -244,7 +235,7 @@ class EmergencyManager extends EventEmitter {
244
235
 
245
236
  /**
246
237
  * Wipes all registered data.
247
- * @returns {Promise<Object>} Wipe result with timing
238
+ * @returns {Promise<any>} Wipe result with timing
248
239
  */
249
240
  async wipeAllData() {
250
241
  return this._executeWipe(PANIC_TRIGGER.MANUAL);
@@ -252,7 +243,7 @@ class EmergencyManager extends EventEmitter {
252
243
 
253
244
  /**
254
245
  * Gets emergency statistics.
255
- * @returns {Object} Statistics
246
+ * @returns {any} Statistics
256
247
  */
257
248
  getStats() {
258
249
  return { ...this._stats };
@@ -280,7 +271,7 @@ class EmergencyManager extends EventEmitter {
280
271
 
281
272
  try {
282
273
  await this._executeWipe(trigger);
283
- } catch (error) {
274
+ } catch (/** @type {any} */ error) {
284
275
  this.emit('error', {
285
276
  message: 'Panic wipe failed',
286
277
  error: error.message,
@@ -292,7 +283,7 @@ class EmergencyManager extends EventEmitter {
292
283
  /**
293
284
  * Executes the data wipe.
294
285
  * @param {string} trigger - Trigger type
295
- * @returns {Promise<Object>} Wipe result
286
+ * @returns {Promise<any>} Wipe result
296
287
  * @private
297
288
  */
298
289
  async _executeWipe(trigger) {
@@ -300,6 +291,7 @@ class EmergencyManager extends EventEmitter {
300
291
 
301
292
  this.emit('panic-wipe-started', { trigger, timestamp: startTime });
302
293
 
294
+ /** @type {any} */
303
295
  const results = {
304
296
  trigger,
305
297
  startTime,
@@ -308,12 +300,13 @@ class EmergencyManager extends EventEmitter {
308
300
  };
309
301
 
310
302
  // Execute all clearers in parallel for speed
303
+ /** @type {any[]} */
311
304
  const clearerResults = new Array(this._clearers.length);
312
305
  const promises = this._clearers.map(async (clearer, index) => {
313
306
  try {
314
307
  await clearer();
315
308
  clearerResults[index] = { index, success: true };
316
- } catch (error) {
309
+ } catch (/** @type {any} */ error) {
317
310
  results.errors.push({ index, error: error.message });
318
311
  clearerResults[index] = { index, success: false, error: error.message };
319
312
  }
@@ -344,7 +337,7 @@ class EmergencyManager extends EventEmitter {
344
337
  if (this._onWipe) {
345
338
  try {
346
339
  this._onWipe(results);
347
- } catch (error) {
340
+ } catch (/** @type {any} */ error) {
348
341
  // Ignore callback errors
349
342
  }
350
343
  }