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.
Files changed (88) hide show
  1. package/package.json +1 -1
  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 +12 -7
  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 +2 -1
  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 +18 -25
  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 +18 -19
  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 +22 -17
  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 +14 -11
  81. package/src/utils/EventEmitter.js +9 -7
  82. package/src/utils/LRUCache.js +10 -4
  83. package/src/utils/RateLimiter.js +1 -1
  84. package/src/utils/compression.js +5 -5
  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
@@ -25,7 +25,9 @@ const SPKI_HEADER = Buffer.from('302a300506032b656e032100', 'hex');
25
25
  class QuickCryptoProvider extends CryptoProvider {
26
26
  constructor(options = {}) {
27
27
  super();
28
- this._crypto = options.crypto || null;
28
+ /** @type {any} */
29
+ const opts = options;
30
+ this._crypto = opts.crypto || null;
29
31
  this._nacl = null;
30
32
  }
31
33
 
@@ -36,6 +38,7 @@ class QuickCryptoProvider extends CryptoProvider {
36
38
  _getCrypto() {
37
39
  if (!this._crypto) {
38
40
  try {
41
+ // @ts-ignore
39
42
  this._crypto = require('react-native-quick-crypto');
40
43
  } catch (e) {
41
44
  throw new Error(
@@ -57,7 +60,7 @@ class QuickCryptoProvider extends CryptoProvider {
57
60
  }
58
61
 
59
62
  /** @inheritdoc */
60
- sharedSecret(secretKey, publicKey) {
63
+ sharedSecret(/** @type {any} */ secretKey, /** @type {any} */ publicKey) {
61
64
  const crypto = this._getCrypto();
62
65
  const privKey = crypto.createPrivateKey({
63
66
  key: Buffer.concat([
@@ -81,12 +84,13 @@ class QuickCryptoProvider extends CryptoProvider {
81
84
 
82
85
  /**
83
86
  * Lazily loads tweetnacl (cached)
84
- * @returns {Object} nacl module
87
+ * @returns {any} nacl module
85
88
  * @private
86
89
  */
87
90
  _getNacl() {
88
91
  if (!this._nacl) {
89
92
  try {
93
+ // @ts-ignore
90
94
  this._nacl = require('tweetnacl');
91
95
  } catch (e) {
92
96
  throw new Error(
@@ -98,7 +102,7 @@ class QuickCryptoProvider extends CryptoProvider {
98
102
  }
99
103
 
100
104
  /** @inheritdoc */
101
- encrypt(key, nonce, plaintext, _ad) {
105
+ encrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ plaintext, /** @type {any} */ _ad) {
102
106
  // Use tweetnacl for encryption to ensure cross-provider compatibility
103
107
  // QuickCrypto's advantage is in fast native key generation (X25519), not AEAD
104
108
  const nacl = this._getNacl();
@@ -114,7 +118,7 @@ class QuickCryptoProvider extends CryptoProvider {
114
118
  }
115
119
 
116
120
  /** @inheritdoc */
117
- decrypt(key, nonce, ciphertext, _ad) {
121
+ decrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ ciphertext, /** @type {any} */ _ad) {
118
122
  const nacl = this._getNacl();
119
123
 
120
124
  // Ensure 24-byte nonce for XSalsa20-Poly1305
@@ -132,7 +136,7 @@ class QuickCryptoProvider extends CryptoProvider {
132
136
  }
133
137
 
134
138
  /** @inheritdoc */
135
- hash(data) {
139
+ hash(/** @type {any} */ data) {
136
140
  // Use SHA-512 truncated to 32 bytes for cross-provider compatibility
137
141
  const nacl = this._getNacl();
138
142
  const full = nacl.hash(data); // SHA-512
@@ -140,13 +144,14 @@ class QuickCryptoProvider extends CryptoProvider {
140
144
  }
141
145
 
142
146
  /** @inheritdoc */
143
- randomBytes(length) {
147
+ randomBytes(/** @type {any} */ length) {
144
148
  const crypto = this._getCrypto();
145
149
  return new Uint8Array(crypto.randomBytes(length));
146
150
  }
147
151
 
148
152
  static isAvailable() {
149
153
  try {
154
+ // @ts-ignore
150
155
  require('react-native-quick-crypto');
151
156
  return true;
152
157
  } catch (e) {
@@ -20,7 +20,7 @@ const CryptoProvider = require('../CryptoProvider');
20
20
  class TweetNaClProvider extends CryptoProvider {
21
21
  /**
22
22
  * @param {Object} [options={}]
23
- * @param {Object} [options.nacl] - Injected tweetnacl instance (for testing)
23
+ * @param {any} [options.nacl] - Injected tweetnacl instance (for testing)
24
24
  */
25
25
  constructor(options = {}) {
26
26
  super();
@@ -33,12 +33,13 @@ class TweetNaClProvider extends CryptoProvider {
33
33
 
34
34
  /**
35
35
  * Lazily loads tweetnacl
36
- * @returns {Object} nacl module
36
+ * @returns {any} nacl module
37
37
  * @private
38
38
  */
39
39
  _getNacl() {
40
40
  if (!this._nacl) {
41
41
  try {
42
+ // @ts-ignore
42
43
  this._nacl = require('tweetnacl');
43
44
  } catch (e) {
44
45
  throw new Error(
@@ -57,13 +58,13 @@ class TweetNaClProvider extends CryptoProvider {
57
58
  }
58
59
 
59
60
  /** @inheritdoc */
60
- sharedSecret(secretKey, publicKey) {
61
+ sharedSecret(/** @type {any} */ secretKey, /** @type {any} */ publicKey) {
61
62
  const nacl = this._getNacl();
62
63
  return nacl.box.before(publicKey, secretKey);
63
64
  }
64
65
 
65
66
  /** @inheritdoc */
66
- encrypt(key, nonce, plaintext, _ad) {
67
+ encrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ plaintext, /** @type {any} */ _ad) {
67
68
  const nacl = this._getNacl();
68
69
  // tweetnacl uses XSalsa20-Poly1305 with 24-byte nonce
69
70
  // nacl.secretbox includes authentication
@@ -79,7 +80,7 @@ class TweetNaClProvider extends CryptoProvider {
79
80
  }
80
81
 
81
82
  /** @inheritdoc */
82
- decrypt(key, nonce, ciphertext, _ad) {
83
+ decrypt(/** @type {any} */ key, /** @type {any} */ nonce, /** @type {any} */ ciphertext, /** @type {any} */ _ad) {
83
84
  const nacl = this._getNacl();
84
85
 
85
86
  // Ensure 24-byte nonce (pad short nonces with zeros)
@@ -94,7 +95,7 @@ class TweetNaClProvider extends CryptoProvider {
94
95
  }
95
96
 
96
97
  /** @inheritdoc */
97
- hash(data) {
98
+ hash(/** @type {any} */ data) {
98
99
  const nacl = this._getNacl();
99
100
  // tweetnacl provides SHA-512; we return first 32 bytes for SHA-256 compatibility
100
101
  const full = nacl.hash(data);
@@ -102,7 +103,7 @@ class TweetNaClProvider extends CryptoProvider {
102
103
  }
103
104
 
104
105
  /** @inheritdoc */
105
- randomBytes(length) {
106
+ randomBytes(/** @type {any} */ length) {
106
107
  const nacl = this._getNacl();
107
108
  return nacl.randomBytes(length);
108
109
  }
@@ -113,6 +114,7 @@ class TweetNaClProvider extends CryptoProvider {
113
114
  */
114
115
  static isAvailable() {
115
116
  try {
117
+ // @ts-ignore
116
118
  require('tweetnacl');
117
119
  return true;
118
120
  } catch (e) {
@@ -32,7 +32,7 @@ class AudioError extends MeshError {
32
32
  * @returns {AudioError}
33
33
  */
34
34
  static fromCode(code, details = null) {
35
- const message = ERROR_MESSAGES[code] || 'Audio operation failed';
35
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || 'Audio operation failed';
36
36
  return new AudioError(message, code, details);
37
37
  }
38
38
 
@@ -73,6 +73,7 @@ class AudioError extends MeshError {
73
73
  return new AudioError(
74
74
  `Audio session failed with peer ${peerId}`,
75
75
  'EA04',
76
+ // @ts-ignore
76
77
  { peerId, ...details }
77
78
  );
78
79
  }
@@ -40,7 +40,7 @@ class ConnectionError extends MeshError {
40
40
  * @returns {ConnectionError} New ConnectionError instance
41
41
  */
42
42
  static fromCode(code, peerId = null, details = null) {
43
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E200;
43
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E200;
44
44
  return new ConnectionError(message, code, peerId, details);
45
45
  }
46
46
 
@@ -96,7 +96,7 @@ class ConnectionError extends MeshError {
96
96
 
97
97
  /**
98
98
  * Converts error to a JSON-serializable object
99
- * @returns {Object} JSON representation of the error
99
+ * @returns {any} JSON representation of the error
100
100
  */
101
101
  toJSON() {
102
102
  return {
@@ -32,7 +32,7 @@ class CryptoError extends MeshError {
32
32
  * @returns {CryptoError} New CryptoError instance
33
33
  */
34
34
  static fromCode(code, details = null) {
35
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E400;
35
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E400;
36
36
  return new CryptoError(message, code, details);
37
37
  }
38
38
 
@@ -48,7 +48,7 @@ class HandshakeError extends MeshError {
48
48
  * @returns {HandshakeError} New HandshakeError instance
49
49
  */
50
50
  static fromCode(code, peerId = null, step = null, details = null) {
51
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E300;
51
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E300;
52
52
  return new HandshakeError(message, code, peerId, step, details);
53
53
  }
54
54
 
@@ -108,7 +108,7 @@ class HandshakeError extends MeshError {
108
108
 
109
109
  /**
110
110
  * Converts error to a JSON-serializable object
111
- * @returns {Object} JSON representation of the error
111
+ * @returns {any} JSON representation of the error
112
112
  */
113
113
  toJSON() {
114
114
  return {
@@ -37,7 +37,7 @@ class MeshError extends Error {
37
37
 
38
38
  /**
39
39
  * Additional error details
40
- * @type {Object|null}
40
+ * @type {any}
41
41
  */
42
42
  this.details = details;
43
43
 
@@ -60,7 +60,7 @@ class MeshError extends Error {
60
60
  * @returns {MeshError} New MeshError instance
61
61
  */
62
62
  static fromCode(code, details = null) {
63
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E900;
63
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E900;
64
64
  return new MeshError(message, code, details);
65
65
  }
66
66
 
@@ -69,12 +69,12 @@ class MeshError extends Error {
69
69
  * @returns {string} Error type name
70
70
  */
71
71
  getTypeName() {
72
- return ERROR_CODE[this.code] || 'UNKNOWN_ERROR';
72
+ return /** @type {Record<string, string>} */ (ERROR_CODE)[this.code] || 'UNKNOWN_ERROR';
73
73
  }
74
74
 
75
75
  /**
76
76
  * Converts error to a JSON-serializable object
77
- * @returns {Object} JSON representation of the error
77
+ * @returns {any} JSON representation of the error
78
78
  */
79
79
  toJSON() {
80
80
  return {
@@ -40,7 +40,7 @@ class MessageError extends MeshError {
40
40
  * @returns {MessageError} New MessageError instance
41
41
  */
42
42
  static fromCode(code, messageId = null, details = null) {
43
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E500;
43
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E500;
44
44
  return new MessageError(message, code, messageId, details);
45
45
  }
46
46
 
@@ -116,7 +116,7 @@ class MessageError extends MeshError {
116
116
 
117
117
  /**
118
118
  * Converts error to a JSON-serializable object
119
- * @returns {Object} JSON representation of the error
119
+ * @returns {any} JSON representation of the error
120
120
  */
121
121
  toJSON() {
122
122
  return {
@@ -87,7 +87,7 @@ class ValidationError extends MeshError {
87
87
  * @returns {ValidationError} New ValidationError instance
88
88
  */
89
89
  static fromCode(code, field = null, value = undefined, details = null) {
90
- const message = ERROR_MESSAGES[code] || ERROR_MESSAGES.E800;
90
+ const message = /** @type {Record<string, string>} */ (ERROR_MESSAGES)[code] || /** @type {Record<string, string>} */ (ERROR_MESSAGES).E800;
91
91
  return new ValidationError(message, code, field, value, details);
92
92
  }
93
93
 
@@ -127,7 +127,7 @@ class ValidationError extends MeshError {
127
127
  * Creates an out of range error
128
128
  * @param {string} field - Name of the field
129
129
  * @param {*} value - The invalid value
130
- * @param {Object} range - Expected range { min, max }
130
+ * @param {any} range - Expected range { min, max }
131
131
  * @returns {ValidationError} New ValidationError instance
132
132
  */
133
133
  static outOfRange(field, value, range) {
@@ -136,7 +136,7 @@ class ValidationError extends MeshError {
136
136
 
137
137
  /**
138
138
  * Converts error to a JSON-serializable object
139
- * @returns {Object} JSON representation of the error
139
+ * @returns {any} JSON representation of the error
140
140
  */
141
141
  toJSON() {
142
142
  return {
@@ -22,7 +22,7 @@
22
22
 
23
23
  /**
24
24
  * Default configuration
25
- * @constant {Object}
25
+ * @constant {any}
26
26
  */
27
27
  const DEFAULT_OPTIONS = {
28
28
  /** iOS NSBluetoothAlwaysUsageDescription */
@@ -40,9 +40,9 @@ const DEFAULT_OPTIONS = {
40
40
 
41
41
  /**
42
42
  * Modifies the iOS Info.plist for BLE permissions.
43
- * @param {Object} config - Expo config
44
- * @param {Object} options - Plugin options
45
- * @returns {Object} Modified config
43
+ * @param {any} config - Expo config
44
+ * @param {any} options - Plugin options
45
+ * @returns {any} Modified config
46
46
  */
47
47
  function withBLEMeshIOS(config, options) {
48
48
  const opts = { ...DEFAULT_OPTIONS, ...options };
@@ -64,9 +64,9 @@ function withBLEMeshIOS(config, options) {
64
64
 
65
65
  /**
66
66
  * Modifies the Android manifest for BLE permissions.
67
- * @param {Object} config - Expo config
68
- * @param {Object} options - Plugin options
69
- * @returns {Object} Modified config
67
+ * @param {any} config - Expo config
68
+ * @param {any} options - Plugin options
69
+ * @returns {any} Modified config
70
70
  */
71
71
  function withBLEMeshAndroid(config, options) {
72
72
  const opts = { ...DEFAULT_OPTIONS, ...options };
@@ -86,9 +86,9 @@ function withBLEMeshAndroid(config, options) {
86
86
 
87
87
  /**
88
88
  * Main Expo config plugin.
89
- * @param {Object} config - Expo config
90
- * @param {Object} [options={}] - Plugin options
91
- * @returns {Object} Modified config
89
+ * @param {any} config - Expo config
90
+ * @param {any} [options={}] - Plugin options
91
+ * @returns {any} Modified config
92
92
  */
93
93
  function withBLEMesh(config, options = {}) {
94
94
  config = withBLEMeshIOS(config, options);
@@ -22,7 +22,7 @@
22
22
  class AppStateManager {
23
23
  /**
24
24
  * Creates a new AppStateManager
25
- * @param {MeshService} mesh - MeshService instance to manage
25
+ * @param {any} mesh - MeshService instance to manage
26
26
  * @param {Object} [options] - Configuration options
27
27
  * @param {string} [options.backgroundMode='ULTRA_POWER_SAVER'] - Power mode for background
28
28
  * @param {string} [options.foregroundMode='BALANCED'] - Power mode for foreground
@@ -58,6 +58,7 @@ class AppStateManager {
58
58
 
59
59
  // Try to get AppState from React Native
60
60
  try {
61
+ // @ts-ignore
61
62
  const { AppState } = require('react-native');
62
63
  this._AppState = AppState;
63
64
  } catch (e) {
@@ -9,10 +9,8 @@
9
9
  * React hook for managing MeshService lifecycle in React Native apps.
10
10
  * Handles initialization, cleanup, and state management.
11
11
  *
12
- * @param {Object} [config] - MeshService configuration
13
- * @param {string} [config.displayName] - Display name for this node
14
- * @param {Object} [config.storage] - Storage adapter
15
- * @returns {Object} Mesh state and controls
12
+ * @param {any} [config] - MeshService configuration
13
+ * @returns {any} Mesh state and controls
16
14
  *
17
15
  * @example
18
16
  * function App() {
@@ -35,6 +33,7 @@ function useMesh(config = {}) {
35
33
  // This hook requires React - check if available
36
34
  let React;
37
35
  try {
36
+ // @ts-ignore
38
37
  React = require('react');
39
38
  } catch (e) {
40
39
  throw new Error('useMesh requires React. Install react as a dependency.');
@@ -65,7 +64,7 @@ function useMesh(config = {}) {
65
64
  }, [config.displayName]);
66
65
 
67
66
  // Initialize mesh
68
- const initialize = useCallback(async (transport) => {
67
+ const initialize = useCallback(async (/** @type {any} */ transport) => {
69
68
  try {
70
69
  if (!mountedRef.current) { return; }
71
70
  setState('initializing');
@@ -82,13 +81,14 @@ function useMesh(config = {}) {
82
81
  }
83
82
 
84
83
  // Setup state change listener
84
+ // @ts-ignore
85
85
  stateHandlerRef.current = ({ newState }) => {
86
86
  if (mountedRef.current) {
87
87
  setState(newState);
88
88
  }
89
89
  };
90
90
 
91
- errorHandlerRef.current = (err) => {
91
+ errorHandlerRef.current = (/** @type {any} */ err) => {
92
92
  if (mountedRef.current) {
93
93
  setError(err);
94
94
  }
@@ -118,7 +118,7 @@ function useMesh(config = {}) {
118
118
  }, [getMesh, config.storage]);
119
119
 
120
120
  // Start with transport
121
- const start = useCallback(async (transport) => {
121
+ const start = useCallback(async (/** @type {any} */ transport) => {
122
122
  const mesh = getMesh();
123
123
  try {
124
124
  await mesh.start(transport);
@@ -9,10 +9,10 @@
9
9
  * React hook for sending and receiving messages in the mesh network.
10
10
  * Manages message state and provides send functions.
11
11
  *
12
- * @param {MeshService} mesh - MeshService instance
13
- * @param {Object} [options] - Options
14
- * @param {number} [options.maxMessages=100] - Maximum messages to keep in state
15
- * @returns {Object} Messages state and send functions
12
+ * @param {any} mesh - MeshService instance
13
+ * @param {any} [options] - Options
14
+ *
15
+ * @returns {any} Messages state and send functions
16
16
  *
17
17
  * @example
18
18
  * function Chat({ mesh, peerId }) {
@@ -38,6 +38,7 @@ function useMessages(mesh, options = {}) {
38
38
  // This hook requires React
39
39
  let React;
40
40
  try {
41
+ // @ts-ignore
41
42
  React = require('react');
42
43
  } catch (e) {
43
44
  throw new Error('useMessages requires React. Install react as a dependency.');
@@ -52,11 +53,11 @@ function useMessages(mesh, options = {}) {
52
53
  const messageIdRef = useRef(new Set());
53
54
 
54
55
  // Add message to state (with dedup)
55
- const addMessage = useCallback((msg) => {
56
+ const addMessage = useCallback((/** @type {any} */ msg) => {
56
57
  if (messageIdRef.current.has(msg.id)) { return; }
57
58
  messageIdRef.current.add(msg.id);
58
59
 
59
- setMessages(prev => {
60
+ setMessages((/** @type {any} */ prev) => {
60
61
  const updated = [msg, ...prev];
61
62
  if (updated.length > maxMessages) {
62
63
  for (let i = maxMessages; i < updated.length; i++) {
@@ -72,7 +73,7 @@ function useMessages(mesh, options = {}) {
72
73
  useEffect(() => {
73
74
  if (!mesh) { return; }
74
75
 
75
- const handleBroadcast = (data) => {
76
+ const handleBroadcast = (/** @type {any} */ data) => {
76
77
  addMessage({
77
78
  id: data.messageId,
78
79
  type: 'broadcast',
@@ -83,7 +84,7 @@ function useMessages(mesh, options = {}) {
83
84
  });
84
85
  };
85
86
 
86
- const handlePrivate = (data) => {
87
+ const handlePrivate = (/** @type {any} */ data) => {
87
88
  addMessage({
88
89
  id: data.messageId,
89
90
  type: 'private',
@@ -94,7 +95,7 @@ function useMessages(mesh, options = {}) {
94
95
  });
95
96
  };
96
97
 
97
- const handleChannel = (data) => {
98
+ const handleChannel = (/** @type {any} */ data) => {
98
99
  addMessage({
99
100
  id: data.messageId,
100
101
  type: 'channel',
@@ -120,7 +121,7 @@ function useMessages(mesh, options = {}) {
120
121
  }, [mesh, addMessage]);
121
122
 
122
123
  // Send broadcast message
123
- const sendBroadcast = useCallback((content) => {
124
+ const sendBroadcast = useCallback((/** @type {any} */ content) => {
124
125
  if (!mesh) { throw new Error('Mesh not initialized'); }
125
126
  setError(null);
126
127
 
@@ -142,7 +143,7 @@ function useMessages(mesh, options = {}) {
142
143
  }, [mesh, addMessage]);
143
144
 
144
145
  // Send private message
145
- const sendPrivate = useCallback(async (peerId, content) => {
146
+ const sendPrivate = useCallback(async (/** @type {any} */ peerId, /** @type {any} */ content) => {
146
147
  if (!mesh) { throw new Error('Mesh not initialized'); }
147
148
  setError(null);
148
149
  setSending(true);
@@ -168,7 +169,7 @@ function useMessages(mesh, options = {}) {
168
169
  }, [mesh, addMessage]);
169
170
 
170
171
  // Send channel message
171
- const sendToChannel = useCallback((channelId, content) => {
172
+ const sendToChannel = useCallback((/** @type {any} */ channelId, /** @type {any} */ content) => {
172
173
  if (!mesh) { throw new Error('Mesh not initialized'); }
173
174
  setError(null);
174
175
 
@@ -9,8 +9,8 @@
9
9
  * React hook for managing and observing peers in the mesh network.
10
10
  * Automatically updates when peers connect, disconnect, or change state.
11
11
  *
12
- * @param {MeshService} mesh - MeshService instance
13
- * @returns {Object} Peers state and utilities
12
+ * @param {any} mesh - MeshService instance
13
+ * @returns {any} Peers state and utilities
14
14
  *
15
15
  * @example
16
16
  * function PeerList({ mesh }) {
@@ -30,6 +30,7 @@ function usePeers(mesh) {
30
30
  // This hook requires React
31
31
  let React;
32
32
  try {
33
+ // @ts-ignore
33
34
  React = require('react');
34
35
  } catch (e) {
35
36
  throw new Error('usePeers requires React. Install react as a dependency.');
@@ -45,8 +46,8 @@ function usePeers(mesh) {
45
46
  if (mesh) {
46
47
  try {
47
48
  const allPeers = mesh.getPeers();
48
- setPeers(prev => {
49
- if (prev.length === allPeers.length && prev.every((p, i) => p.id === allPeers[i]?.id && p.connectionState === allPeers[i]?.connectionState)) {
49
+ setPeers((/** @type {any} */ prev) => {
50
+ if (prev.length === allPeers.length && prev.every((/** @type {any} */ p, /** @type {any} */ i) => p.id === allPeers[i]?.id && p.connectionState === allPeers[i]?.connectionState)) {
50
51
  return prev;
51
52
  }
52
53
  return allPeers;
@@ -82,19 +83,19 @@ function usePeers(mesh) {
82
83
 
83
84
  // Computed values
84
85
  const connectedPeers = useMemo(() => {
85
- return peers.filter(p => p.connectionState === 'connected' || p.connectionState === 'secured');
86
+ return peers.filter((/** @type {any} */ p) => p.connectionState === 'connected' || p.connectionState === 'secured');
86
87
  }, [peers]);
87
88
 
88
89
  const securedPeers = useMemo(() => {
89
- return peers.filter(p => p.connectionState === 'secured');
90
+ return peers.filter((/** @type {any} */ p) => p.connectionState === 'secured');
90
91
  }, [peers]);
91
92
 
92
93
  // Get single peer by ID (O(1) lookup via peerMap)
93
- const peerMap = useMemo(() => new Map(peers.map(p => [p.id, p])), [peers]);
94
- const getPeer = useCallback((peerId) => peerMap.get(peerId), [peerMap]);
94
+ const peerMap = useMemo(() => new Map(peers.map((/** @type {any} */ p) => [p.id, p])), [peers]);
95
+ const getPeer = useCallback((/** @type {any} */ peerId) => peerMap.get(peerId), [peerMap]);
95
96
 
96
97
  // Check if peer is connected
97
- const isConnected = useCallback((peerId) => {
98
+ const isConnected = useCallback((/** @type {any} */ peerId) => {
98
99
  const peer = getPeer(peerId);
99
100
  return peer && (peer.connectionState === 'connected' || peer.connectionState === 'secured');
100
101
  }, [getPeer]);
package/src/index.js CHANGED
@@ -69,7 +69,7 @@ function createMeshNetwork(config) {
69
69
 
70
70
  /**
71
71
  * Create a new MeshService instance
72
- * @param {Object} [config] - Configuration options
72
+ * @param {any} [config] - Configuration options
73
73
  * @returns {MeshService}
74
74
  */
75
75
  function createMeshService(config) {
@@ -80,7 +80,7 @@ function createMeshService(config) {
80
80
  * Create and initialize a MeshService for Node.js usage
81
81
  * @param {Object} [options] - Configuration options
82
82
  * @param {string} [options.displayName='MeshNode'] - Display name for this node
83
- * @param {Object} [options.storage=null] - Storage adapter (null for MemoryStorage)
83
+ * @param {any} [options.storage=null] - Storage adapter (null for MemoryStorage)
84
84
  * @returns {Promise<MeshService>} Initialized MeshService
85
85
  * @example
86
86
  * const mesh = await createNodeMesh({ displayName: 'Alice' });
@@ -14,6 +14,7 @@ const FNV_PRIME = 0x01000193;
14
14
  const FNV_OFFSET = 0x811c9dc5;
15
15
 
16
16
  // Cached TextEncoder singleton (avoids per-call allocation)
17
+ /** @type {any} */
17
18
  let _encoder = null;
18
19
  function _getEncoder() {
19
20
  if (!_encoder && typeof TextEncoder !== 'undefined') {
@@ -29,13 +29,10 @@ const DEFAULT_CONFIG = {
29
29
  class DedupManager {
30
30
  /**
31
31
  * Creates a new DedupManager
32
- * @param {Object} [options] - Configuration options
33
- * @param {number} [options.bloomFilterSize] - Size of Bloom filter in bits
34
- * @param {number} [options.bloomHashCount] - Number of hash functions
35
- * @param {number} [options.cacheSize] - Maximum LRU cache entries
36
- * @param {number} [options.autoResetThreshold] - Fill ratio for auto reset
32
+ * @param {any} [options] - Configuration options *
37
33
  */
38
34
  constructor(options = {}) {
35
+ /** @type {any} */
39
36
  const config = { ...DEFAULT_CONFIG, ...options };
40
37
 
41
38
  /**
@@ -78,7 +75,7 @@ class DedupManager {
78
75
 
79
76
  /**
80
77
  * Statistics for monitoring
81
- * @type {Object}
78
+ * @type {any}
82
79
  * @private
83
80
  */
84
81
  this._stats = {
@@ -200,7 +197,7 @@ class DedupManager {
200
197
 
201
198
  /**
202
199
  * Gets deduplication statistics
203
- * @returns {Object} Statistics object
200
+ * @returns {any} Statistics object
204
201
  */
205
202
  getStats() {
206
203
  return {
@@ -19,7 +19,9 @@ class CacheNode {
19
19
  constructor(key, timestamp) {
20
20
  this.key = key;
21
21
  this.timestamp = timestamp;
22
+ /** @type {CacheNode|null} */
22
23
  this.prev = null;
24
+ /** @type {CacheNode|null} */
23
25
  this.next = null;
24
26
  }
25
27
  }
@@ -207,6 +209,7 @@ class MessageCache {
207
209
  */
208
210
  getAll() {
209
211
  const result = [];
212
+ /** @type {CacheNode|null} */
210
213
  let node = this._head;
211
214
  while (node) {
212
215
  result.push(node.key);