react-native-ble-mesh 1.0.1
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/CHANGELOG.md +151 -0
- package/LICENSE +21 -0
- package/README.md +706 -0
- package/docs/API.md +462 -0
- package/docs/ARCHITECTURE.md +384 -0
- package/docs/CONTRIBUTING.md +244 -0
- package/docs/NODE_QUICKSTART.md +259 -0
- package/docs/PROTOCOL.md +195 -0
- package/docs/REACT_NATIVE.md +315 -0
- package/docs/SECURITY.md +152 -0
- package/docs/api/constants_audio.js.html +184 -0
- package/docs/api/constants_ble.js.html +165 -0
- package/docs/api/constants_crypto.js.html +107 -0
- package/docs/api/constants_errors.js.html +256 -0
- package/docs/api/constants_events.js.html +148 -0
- package/docs/api/constants_index.js.html +76 -0
- package/docs/api/constants_protocol.js.html +205 -0
- package/docs/api/crypto_aead.js.html +243 -0
- package/docs/api/crypto_chacha20.js.html +235 -0
- package/docs/api/crypto_hkdf.js.html +241 -0
- package/docs/api/crypto_hmac.js.html +197 -0
- package/docs/api/crypto_index.js.html +126 -0
- package/docs/api/crypto_keys_KeyManager.js.html +325 -0
- package/docs/api/crypto_keys_KeyPair.js.html +270 -0
- package/docs/api/crypto_keys_SecureStorage.js.html +273 -0
- package/docs/api/crypto_keys_index.js.html +86 -0
- package/docs/api/crypto_noise_handshake.js.html +464 -0
- package/docs/api/crypto_noise_index.js.html +81 -0
- package/docs/api/crypto_noise_session.js.html +307 -0
- package/docs/api/crypto_noise_state.js.html +322 -0
- package/docs/api/crypto_poly1305.js.html +167 -0
- package/docs/api/crypto_sha256.js.html +294 -0
- package/docs/api/crypto_x25519.js.html +208 -0
- package/docs/api/errors_AudioError.js.html +218 -0
- package/docs/api/errors_ConnectionError.js.html +163 -0
- package/docs/api/errors_CryptoError.js.html +157 -0
- package/docs/api/errors_HandshakeError.js.html +176 -0
- package/docs/api/errors_MeshError.js.html +154 -0
- package/docs/api/errors_MessageError.js.html +183 -0
- package/docs/api/errors_ValidationError.js.html +204 -0
- package/docs/api/errors_index.js.html +78 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Light-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/docs/api/fonts/OpenSans-Light-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/docs/api/hooks_AppStateManager.js.html +233 -0
- package/docs/api/hooks_index.js.html +87 -0
- package/docs/api/hooks_useMesh.js.html +213 -0
- package/docs/api/hooks_useMessages.js.html +263 -0
- package/docs/api/hooks_usePeers.js.html +165 -0
- package/docs/api/index.html +868 -0
- package/docs/api/index.js.html +236 -0
- package/docs/api/mesh_dedup_BloomFilter.js.html +261 -0
- package/docs/api/mesh_dedup_DedupManager.js.html +266 -0
- package/docs/api/mesh_dedup_MessageCache.js.html +273 -0
- package/docs/api/mesh_dedup_index.js.html +70 -0
- package/docs/api/mesh_fragment_Assembler.js.html +335 -0
- package/docs/api/mesh_fragment_Fragmenter.js.html +230 -0
- package/docs/api/mesh_fragment_index.js.html +75 -0
- package/docs/api/mesh_index.js.html +72 -0
- package/docs/api/mesh_peer_Peer.js.html +296 -0
- package/docs/api/mesh_peer_PeerDiscovery.js.html +334 -0
- package/docs/api/mesh_peer_PeerManager.js.html +320 -0
- package/docs/api/mesh_peer_index.js.html +70 -0
- package/docs/api/mesh_router_MessageRouter.js.html +411 -0
- package/docs/api/mesh_router_PathFinder.js.html +386 -0
- package/docs/api/mesh_router_RouteTable.js.html +346 -0
- package/docs/api/mesh_router_index.js.html +70 -0
- package/docs/api/module-audio_buffer.html +168 -0
- package/docs/api/module-audio_buffer_FrameBuffer-FrameBuffer.html +2971 -0
- package/docs/api/module-audio_buffer_FrameBuffer.html +178 -0
- package/docs/api/module-audio_buffer_JitterBuffer-JitterBuffer.html +2761 -0
- package/docs/api/module-audio_buffer_JitterBuffer.html +178 -0
- package/docs/api/module-audio_codec.html +168 -0
- package/docs/api/module-audio_codec_LC3Codec-LC3Codec.html +2876 -0
- package/docs/api/module-audio_codec_LC3Codec.html +178 -0
- package/docs/api/module-audio_codec_LC3Decoder-LC3Decoder.html +1788 -0
- package/docs/api/module-audio_codec_LC3Decoder.html +178 -0
- package/docs/api/module-audio_codec_LC3Encoder-LC3Encoder.html +1512 -0
- package/docs/api/module-audio_codec_LC3Encoder.html +178 -0
- package/docs/api/module-audio_session.html +168 -0
- package/docs/api/module-audio_session_AudioSession-AudioSession.html +3922 -0
- package/docs/api/module-audio_session_AudioSession.html +178 -0
- package/docs/api/module-audio_session_VoiceMessage-VoiceMessage.html +3690 -0
- package/docs/api/module-audio_session_VoiceMessage-VoiceMessageRecorder.html +1780 -0
- package/docs/api/module-audio_session_VoiceMessage.html +332 -0
- package/docs/api/module-audio_transport.html +168 -0
- package/docs/api/module-audio_transport_AudioFragmenter-AudioAssembler.html +1545 -0
- package/docs/api/module-audio_transport_AudioFragmenter-AudioFragmenter.html +658 -0
- package/docs/api/module-audio_transport_AudioFragmenter.html +181 -0
- package/docs/api/module-audio_transport_AudioFramer.html +1414 -0
- package/docs/api/module-constants.html +168 -0
- package/docs/api/module-constants_audio.html +1782 -0
- package/docs/api/module-constants_ble.html +940 -0
- package/docs/api/module-constants_crypto.html +823 -0
- package/docs/api/module-constants_errors.html +316 -0
- package/docs/api/module-constants_events.html +244 -0
- package/docs/api/module-constants_protocol.html +1534 -0
- package/docs/api/module-crypto.html +169 -0
- package/docs/api/module-crypto_aead.html +1625 -0
- package/docs/api/module-crypto_chacha20.html +1440 -0
- package/docs/api/module-crypto_hkdf.html +1421 -0
- package/docs/api/module-crypto_hmac.html +828 -0
- package/docs/api/module-crypto_keys.html +169 -0
- package/docs/api/module-crypto_keys_KeyManager-KeyManager.html +2364 -0
- package/docs/api/module-crypto_keys_KeyManager.html +252 -0
- package/docs/api/module-crypto_keys_KeyPair.html +245 -0
- package/docs/api/module-crypto_keys_SecureStorage-MemorySecureStorage.html +923 -0
- package/docs/api/module-crypto_keys_SecureStorage-SecureStorage.html +942 -0
- package/docs/api/module-crypto_keys_SecureStorage.html +516 -0
- package/docs/api/module-crypto_noise.html +169 -0
- package/docs/api/module-crypto_noise_handshake-NoiseHandshake.html +2240 -0
- package/docs/api/module-crypto_noise_handshake.html +782 -0
- package/docs/api/module-crypto_noise_session-NoiseSession.html +1804 -0
- package/docs/api/module-crypto_noise_session.html +325 -0
- package/docs/api/module-crypto_noise_state-SymmetricState.html +1387 -0
- package/docs/api/module-crypto_noise_state.html +324 -0
- package/docs/api/module-crypto_poly1305.html +884 -0
- package/docs/api/module-crypto_sha256-HashContext.html +447 -0
- package/docs/api/module-crypto_sha256.html +942 -0
- package/docs/api/module-crypto_x25519.html +1503 -0
- package/docs/api/module-errors.html +168 -0
- package/docs/api/module-errors_AudioError-AudioError.html +4711 -0
- package/docs/api/module-errors_AudioError.html +178 -0
- package/docs/api/module-errors_ConnectionError-ConnectionError.html +3649 -0
- package/docs/api/module-errors_ConnectionError.html +178 -0
- package/docs/api/module-errors_CryptoError-CryptoError.html +3453 -0
- package/docs/api/module-errors_CryptoError.html +178 -0
- package/docs/api/module-errors_HandshakeError-HandshakeError.html +4261 -0
- package/docs/api/module-errors_HandshakeError.html +178 -0
- package/docs/api/module-errors_MeshError-MeshError.html +2155 -0
- package/docs/api/module-errors_MeshError.html +178 -0
- package/docs/api/module-errors_MessageError-MessageError.html +4545 -0
- package/docs/api/module-errors_MessageError.html +178 -0
- package/docs/api/module-errors_ValidationError-ValidationError.html +3432 -0
- package/docs/api/module-errors_ValidationError.html +178 -0
- package/docs/api/module-hooks.html +182 -0
- package/docs/api/module-hooks_AppStateManager-AppStateManager.html +1620 -0
- package/docs/api/module-hooks_AppStateManager.html +178 -0
- package/docs/api/module-hooks_useMesh.html +457 -0
- package/docs/api/module-hooks_useMessages.html +466 -0
- package/docs/api/module-hooks_usePeers.html +348 -0
- package/docs/api/module-mesh.html +168 -0
- package/docs/api/module-mesh_dedup.html +168 -0
- package/docs/api/module-mesh_dedup_BloomFilter-BloomFilter.html +2158 -0
- package/docs/api/module-mesh_dedup_BloomFilter.html +178 -0
- package/docs/api/module-mesh_dedup_DedupManager-DedupManager.html +2880 -0
- package/docs/api/module-mesh_dedup_DedupManager.html +178 -0
- package/docs/api/module-mesh_dedup_MessageCache-CacheNode.html +246 -0
- package/docs/api/module-mesh_dedup_MessageCache-MessageCache.html +2314 -0
- package/docs/api/module-mesh_dedup_MessageCache.html +181 -0
- package/docs/api/module-mesh_fragment.html +168 -0
- package/docs/api/module-mesh_fragment_Assembler-Assembler.html +2869 -0
- package/docs/api/module-mesh_fragment_Assembler-PendingFragmentSet.html +895 -0
- package/docs/api/module-mesh_fragment_Assembler.html +181 -0
- package/docs/api/module-mesh_fragment_Fragmenter.html +1084 -0
- package/docs/api/module-mesh_peer.html +168 -0
- package/docs/api/module-mesh_peer_Peer-Peer.html +4986 -0
- package/docs/api/module-mesh_peer_Peer.html +178 -0
- package/docs/api/module-mesh_peer_PeerDiscovery-PeerDiscovery.html +3423 -0
- package/docs/api/module-mesh_peer_PeerDiscovery.html +438 -0
- package/docs/api/module-mesh_peer_PeerManager-PeerManager.html +5258 -0
- package/docs/api/module-mesh_peer_PeerManager.html +178 -0
- package/docs/api/module-mesh_router.html +168 -0
- package/docs/api/module-mesh_router_MessageRouter-MessageRouter.html +3285 -0
- package/docs/api/module-mesh_router_MessageRouter.html +178 -0
- package/docs/api/module-mesh_router_PathFinder-PathFinder.html +3323 -0
- package/docs/api/module-mesh_router_PathFinder.html +421 -0
- package/docs/api/module-mesh_router_RouteTable-RouteTable.html +4115 -0
- package/docs/api/module-mesh_router_RouteTable.html +421 -0
- package/docs/api/module-protocol.html +169 -0
- package/docs/api/module-protocol_crc32.html +815 -0
- package/docs/api/module-protocol_deserializer.html +1393 -0
- package/docs/api/module-protocol_header-MessageHeader.html +2879 -0
- package/docs/api/module-protocol_header.html +892 -0
- package/docs/api/module-protocol_message-Message.html +4682 -0
- package/docs/api/module-protocol_message.html +178 -0
- package/docs/api/module-protocol_serializer.html +911 -0
- package/docs/api/module-protocol_validator.html +1396 -0
- package/docs/api/module-rn-ble-mesh.html +866 -0
- package/docs/api/module-service.html +168 -0
- package/docs/api/module-service_HandshakeManager-HandshakeManager.html +185 -0
- package/docs/api/module-service_HandshakeManager.html +175 -0
- package/docs/api/module-service_MeshService-MeshService.html +185 -0
- package/docs/api/module-service_MeshService.html +175 -0
- package/docs/api/module-service_SessionManager-SessionManager.html +174 -0
- package/docs/api/module-service_SessionManager.html +175 -0
- package/docs/api/module-service_audio.html +168 -0
- package/docs/api/module-service_audio_AudioManager-AudioManager.html +4653 -0
- package/docs/api/module-service_audio_AudioManager.html +254 -0
- package/docs/api/module-service_text.html +168 -0
- package/docs/api/module-service_text_TextManager-TextManager.html +6104 -0
- package/docs/api/module-service_text_TextManager.html +254 -0
- package/docs/api/module-service_text_broadcast.html +168 -0
- package/docs/api/module-service_text_broadcast_BroadcastManager-BroadcastManager.html +2434 -0
- package/docs/api/module-service_text_broadcast_BroadcastManager.html +254 -0
- package/docs/api/module-service_text_channel.html +168 -0
- package/docs/api/module-service_text_channel_Channel-Channel.html +4337 -0
- package/docs/api/module-service_text_channel_Channel.html +178 -0
- package/docs/api/module-service_text_channel_ChannelManager-ChannelManager.html +1927 -0
- package/docs/api/module-service_text_channel_ChannelManager.html +175 -0
- package/docs/api/module-service_text_message.html +168 -0
- package/docs/api/module-service_text_message_TextMessage-TextMessage.html +4162 -0
- package/docs/api/module-service_text_message_TextMessage.html +178 -0
- package/docs/api/module-service_text_message_TextSerializer.html +1725 -0
- package/docs/api/module-storage.html +168 -0
- package/docs/api/module-storage_AsyncStorageAdapter-AsyncStorageAdapter.html +4159 -0
- package/docs/api/module-storage_AsyncStorageAdapter.html +178 -0
- package/docs/api/module-storage_MemoryStorage-MemoryStorage.html +3154 -0
- package/docs/api/module-storage_MemoryStorage.html +178 -0
- package/docs/api/module-storage_MessageStore-MessageStore.html +5299 -0
- package/docs/api/module-storage_MessageStore.html +178 -0
- package/docs/api/module-storage_Storage-Storage.html +4169 -0
- package/docs/api/module-storage_Storage.html +178 -0
- package/docs/api/module-transport.html +168 -0
- package/docs/api/module-transport_BLEAdapter-BLEAdapter.html +4724 -0
- package/docs/api/module-transport_BLEAdapter.html +178 -0
- package/docs/api/module-transport_BLETransport-BLETransport.html +3263 -0
- package/docs/api/module-transport_BLETransport.html +178 -0
- package/docs/api/module-transport_MockTransport-MockTransport.html +3947 -0
- package/docs/api/module-transport_MockTransport.html +178 -0
- package/docs/api/module-transport_NodeBLEAdapter-NodeBLEAdapter.html +3216 -0
- package/docs/api/module-transport_NodeBLEAdapter.html +178 -0
- package/docs/api/module-transport_RNBLEAdapter-RNBLEAdapter.html +3216 -0
- package/docs/api/module-transport_RNBLEAdapter.html +178 -0
- package/docs/api/module-transport_Transport-Transport.html +4071 -0
- package/docs/api/module-transport_Transport.html +254 -0
- package/docs/api/module-transport_adapters.html +168 -0
- package/docs/api/module-transport_adapters_BLEAdapter-BLEAdapter.html +4724 -0
- package/docs/api/module-transport_adapters_BLEAdapter.html +178 -0
- package/docs/api/module-transport_adapters_NodeBLEAdapter-NodeBLEAdapter.html +3216 -0
- package/docs/api/module-transport_adapters_NodeBLEAdapter.html +178 -0
- package/docs/api/module-transport_adapters_RNBLEAdapter-RNBLEAdapter.html +3216 -0
- package/docs/api/module-transport_adapters_RNBLEAdapter.html +178 -0
- package/docs/api/module-utils.html +168 -0
- package/docs/api/module-utils_BoundedMap-BoundedMap.html +3301 -0
- package/docs/api/module-utils_BoundedMap.html +178 -0
- package/docs/api/module-utils_EventEmitter-EventEmitter.html +3358 -0
- package/docs/api/module-utils_EventEmitter.html +178 -0
- package/docs/api/module-utils_LRUCache-LRUCache.html +4134 -0
- package/docs/api/module-utils_LRUCache.html +178 -0
- package/docs/api/module-utils_RateLimiter-RateLimiter.html +2176 -0
- package/docs/api/module-utils_RateLimiter.html +500 -0
- package/docs/api/module-utils_TimeoutManager-TimeoutManager.html +1781 -0
- package/docs/api/module-utils_TimeoutManager.html +175 -0
- package/docs/api/module-utils_bytes.html +1789 -0
- package/docs/api/module-utils_debug.html +837 -0
- package/docs/api/module-utils_encoding.html +1184 -0
- package/docs/api/module-utils_retry.html +1457 -0
- package/docs/api/module-utils_time.html +1665 -0
- package/docs/api/module-utils_uuid.html +1269 -0
- package/docs/api/module-utils_validation.html +2176 -0
- package/docs/api/protocol_crc32.js.html +147 -0
- package/docs/api/protocol_deserializer.js.html +295 -0
- package/docs/api/protocol_header.js.html +276 -0
- package/docs/api/protocol_index.js.html +120 -0
- package/docs/api/protocol_message.js.html +287 -0
- package/docs/api/protocol_serializer.js.html +240 -0
- package/docs/api/protocol_validator.js.html +330 -0
- package/docs/api/scripts/linenumber.js +25 -0
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/api/scripts/prettify/lang-css.js +2 -0
- package/docs/api/scripts/prettify/prettify.js +28 -0
- package/docs/api/service_HandshakeManager.js.html +232 -0
- package/docs/api/service_MeshService.js.html +371 -0
- package/docs/api/service_SessionManager.js.html +153 -0
- package/docs/api/service_audio_AudioManager.js.html +541 -0
- package/docs/api/service_audio_buffer_FrameBuffer.js.html +223 -0
- package/docs/api/service_audio_buffer_JitterBuffer.js.html +244 -0
- package/docs/api/service_audio_buffer_index.js.html +68 -0
- package/docs/api/service_audio_codec_LC3Codec.js.html +345 -0
- package/docs/api/service_audio_codec_LC3Decoder.js.html +185 -0
- package/docs/api/service_audio_codec_LC3Encoder.js.html +194 -0
- package/docs/api/service_audio_codec_index.js.html +70 -0
- package/docs/api/service_audio_index.js.html +96 -0
- package/docs/api/service_audio_session_AudioSession.js.html +348 -0
- package/docs/api/service_audio_session_VoiceMessage.js.html +432 -0
- package/docs/api/service_audio_session_index.js.html +70 -0
- package/docs/api/service_audio_transport_AudioFragmenter.js.html +314 -0
- package/docs/api/service_audio_transport_AudioFramer.js.html +236 -0
- package/docs/api/service_audio_transport_index.js.html +69 -0
- package/docs/api/service_index.js.html +93 -0
- package/docs/api/service_text_TextManager.js.html +578 -0
- package/docs/api/service_text_broadcast_BroadcastManager.js.html +276 -0
- package/docs/api/service_text_broadcast_index.js.html +66 -0
- package/docs/api/service_text_channel_Channel.js.html +280 -0
- package/docs/api/service_text_channel_ChannelManager.js.html +225 -0
- package/docs/api/service_text_channel_index.js.html +68 -0
- package/docs/api/service_text_index.js.html +85 -0
- package/docs/api/service_text_message_TextMessage.js.html +350 -0
- package/docs/api/service_text_message_TextSerializer.js.html +218 -0
- package/docs/api/service_text_message_index.js.html +68 -0
- package/docs/api/storage_AsyncStorageAdapter.js.html +357 -0
- package/docs/api/storage_MemoryStorage.js.html +279 -0
- package/docs/api/storage_MessageStore.js.html +369 -0
- package/docs/api/storage_Storage.js.html +214 -0
- package/docs/api/storage_index.js.html +72 -0
- package/docs/api/styles/jsdoc-default.css +358 -0
- package/docs/api/styles/prettify-jsdoc.css +111 -0
- package/docs/api/styles/prettify-tomorrow.css +132 -0
- package/docs/api/transport_BLEAdapter.js.html +231 -0
- package/docs/api/transport_BLETransport.js.html +411 -0
- package/docs/api/transport_MockTransport.js.html +339 -0
- package/docs/api/transport_NodeBLEAdapter.js.html +479 -0
- package/docs/api/transport_RNBLEAdapter.js.html +382 -0
- package/docs/api/transport_Transport.js.html +242 -0
- package/docs/api/transport_adapters_BLEAdapter.js.html +231 -0
- package/docs/api/transport_adapters_NodeBLEAdapter.js.html +479 -0
- package/docs/api/transport_adapters_RNBLEAdapter.js.html +382 -0
- package/docs/api/transport_adapters_index.js.html +70 -0
- package/docs/api/transport_index.js.html +87 -0
- package/docs/api/utils_BoundedMap.js.html +205 -0
- package/docs/api/utils_EventEmitter.js.html +259 -0
- package/docs/api/utils_LRUCache.js.html +256 -0
- package/docs/api/utils_RateLimiter.js.html +256 -0
- package/docs/api/utils_TimeoutManager.js.html +218 -0
- package/docs/api/utils_base64%0A%0AThis%20implementation%20avoids%20string%20concatenation%20in%20loops%20which%20is%20O(n%C2%B2).%0AUses%20array%20building%20which%20is%20O(n)%20-%20critical%20for%20React%20Native%20performance.module_.html +717 -0
- package/docs/api/utils_base64.js.html +205 -0
- package/docs/api/utils_bytes.js.html +241 -0
- package/docs/api/utils_debug.js.html +205 -0
- package/docs/api/utils_encoding.js.html +302 -0
- package/docs/api/utils_index.js.html +160 -0
- package/docs/api/utils_retry.js.html +200 -0
- package/docs/api/utils_time.js.html +220 -0
- package/docs/api/utils_uuid.js.html +199 -0
- package/docs/api/utils_validation.js.html +259 -0
- package/examples/node-chat/chat.js +220 -0
- package/examples/node-quickstart/index.js +94 -0
- package/examples/testing/test-helper.js +182 -0
- package/package.json +111 -0
- package/src/constants/audio.js +130 -0
- package/src/constants/ble.js +111 -0
- package/src/constants/crypto.js +53 -0
- package/src/constants/errors.js +202 -0
- package/src/constants/events.js +94 -0
- package/src/constants/index.js +22 -0
- package/src/constants/protocol.js +151 -0
- package/src/crypto/aead.js +189 -0
- package/src/crypto/chacha20.js +181 -0
- package/src/crypto/hkdf.js +187 -0
- package/src/crypto/hmac.js +143 -0
- package/src/crypto/index.js +72 -0
- package/src/crypto/keys/KeyManager.js +271 -0
- package/src/crypto/keys/KeyPair.js +216 -0
- package/src/crypto/keys/SecureStorage.js +219 -0
- package/src/crypto/keys/index.js +32 -0
- package/src/crypto/noise/handshake.js +410 -0
- package/src/crypto/noise/index.js +27 -0
- package/src/crypto/noise/session.js +253 -0
- package/src/crypto/noise/state.js +268 -0
- package/src/crypto/poly1305.js +113 -0
- package/src/crypto/sha256.js +240 -0
- package/src/crypto/x25519.js +154 -0
- package/src/errors/AudioError.js +164 -0
- package/src/errors/ConnectionError.js +109 -0
- package/src/errors/CryptoError.js +103 -0
- package/src/errors/HandshakeError.js +122 -0
- package/src/errors/MeshError.js +100 -0
- package/src/errors/MessageError.js +129 -0
- package/src/errors/ValidationError.js +150 -0
- package/src/errors/index.js +24 -0
- package/src/hooks/AppStateManager.js +179 -0
- package/src/hooks/index.js +33 -0
- package/src/hooks/useMesh.js +159 -0
- package/src/hooks/useMessages.js +209 -0
- package/src/hooks/usePeers.js +111 -0
- package/src/index.d.ts +494 -0
- package/src/index.js +182 -0
- package/src/index.mjs +62 -0
- package/src/mesh/dedup/BloomFilter.js +207 -0
- package/src/mesh/dedup/DedupManager.js +212 -0
- package/src/mesh/dedup/MessageCache.js +219 -0
- package/src/mesh/dedup/index.js +16 -0
- package/src/mesh/fragment/Assembler.js +281 -0
- package/src/mesh/fragment/Fragmenter.js +176 -0
- package/src/mesh/fragment/index.js +21 -0
- package/src/mesh/index.js +18 -0
- package/src/mesh/peer/Peer.js +242 -0
- package/src/mesh/peer/PeerDiscovery.js +280 -0
- package/src/mesh/peer/PeerManager.js +266 -0
- package/src/mesh/peer/index.js +16 -0
- package/src/mesh/router/MessageRouter.js +357 -0
- package/src/mesh/router/PathFinder.js +332 -0
- package/src/mesh/router/RouteTable.js +292 -0
- package/src/mesh/router/index.js +16 -0
- package/src/protocol/crc32.js +93 -0
- package/src/protocol/deserializer.js +241 -0
- package/src/protocol/header.js +222 -0
- package/src/protocol/index.js +66 -0
- package/src/protocol/message.js +233 -0
- package/src/protocol/serializer.js +186 -0
- package/src/protocol/validator.js +276 -0
- package/src/service/HandshakeManager.js +178 -0
- package/src/service/MeshService.js +317 -0
- package/src/service/SessionManager.js +99 -0
- package/src/service/audio/AudioManager.js +487 -0
- package/src/service/audio/buffer/FrameBuffer.js +169 -0
- package/src/service/audio/buffer/JitterBuffer.js +190 -0
- package/src/service/audio/buffer/index.js +14 -0
- package/src/service/audio/codec/LC3Codec.js +291 -0
- package/src/service/audio/codec/LC3Decoder.js +131 -0
- package/src/service/audio/codec/LC3Encoder.js +140 -0
- package/src/service/audio/codec/index.js +16 -0
- package/src/service/audio/index.js +42 -0
- package/src/service/audio/session/AudioSession.js +294 -0
- package/src/service/audio/session/VoiceMessage.js +378 -0
- package/src/service/audio/session/index.js +16 -0
- package/src/service/audio/transport/AudioFragmenter.js +260 -0
- package/src/service/audio/transport/AudioFramer.js +182 -0
- package/src/service/audio/transport/index.js +15 -0
- package/src/service/index.js +39 -0
- package/src/service/text/TextManager.js +524 -0
- package/src/service/text/broadcast/BroadcastManager.js +222 -0
- package/src/service/text/broadcast/index.js +12 -0
- package/src/service/text/channel/Channel.js +226 -0
- package/src/service/text/channel/ChannelManager.js +171 -0
- package/src/service/text/channel/index.js +14 -0
- package/src/service/text/index.js +31 -0
- package/src/service/text/message/TextMessage.js +296 -0
- package/src/service/text/message/TextSerializer.js +164 -0
- package/src/service/text/message/index.js +14 -0
- package/src/storage/AsyncStorageAdapter.js +303 -0
- package/src/storage/MemoryStorage.js +225 -0
- package/src/storage/MessageStore.js +315 -0
- package/src/storage/Storage.js +160 -0
- package/src/storage/index.js +18 -0
- package/src/transport/BLEAdapter.js +177 -0
- package/src/transport/BLETransport.js +357 -0
- package/src/transport/MockTransport.js +285 -0
- package/src/transport/NodeBLEAdapter.js +425 -0
- package/src/transport/RNBLEAdapter.js +328 -0
- package/src/transport/Transport.js +188 -0
- package/src/transport/adapters/BLEAdapter.js +177 -0
- package/src/transport/adapters/NodeBLEAdapter.js +425 -0
- package/src/transport/adapters/RNBLEAdapter.js +328 -0
- package/src/transport/adapters/index.js +16 -0
- package/src/transport/index.js +33 -0
- package/src/utils/BoundedMap.js +151 -0
- package/src/utils/EventEmitter.js +205 -0
- package/src/utils/LRUCache.js +202 -0
- package/src/utils/RateLimiter.js +202 -0
- package/src/utils/TimeoutManager.js +164 -0
- package/src/utils/base64.js +151 -0
- package/src/utils/bytes.js +187 -0
- package/src/utils/debug.js +151 -0
- package/src/utils/encoding.js +248 -0
- package/src/utils/index.js +106 -0
- package/src/utils/retry.js +146 -0
- package/src/utils/time.js +166 -0
- package/src/utils/uuid.js +145 -0
- package/src/utils/validation.js +205 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Enhanced EventEmitter class
|
|
5
|
+
* @module utils/EventEmitter
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enhanced EventEmitter with typed events and memory leak prevention
|
|
10
|
+
* @class EventEmitter
|
|
11
|
+
*/
|
|
12
|
+
class EventEmitter {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new EventEmitter
|
|
15
|
+
* @param {Object} [options] - Configuration options
|
|
16
|
+
* @param {number} [options.maxListeners=10] - Maximum listeners per event
|
|
17
|
+
*/
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
/**
|
|
20
|
+
* Event listeners map
|
|
21
|
+
* @type {Map<string, Array<{listener: Function, once: boolean}>>}
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
24
|
+
this._events = new Map();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Maximum listeners per event
|
|
28
|
+
* @type {number}
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
this._maxListeners = options.maxListeners || 10;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Adds an event listener
|
|
36
|
+
* @param {string} event - Event name
|
|
37
|
+
* @param {Function} listener - Event handler
|
|
38
|
+
* @returns {EventEmitter} This instance for chaining
|
|
39
|
+
*/
|
|
40
|
+
on(event, listener) {
|
|
41
|
+
if (typeof listener !== 'function') {
|
|
42
|
+
throw new TypeError('Listener must be a function');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!this._events.has(event)) {
|
|
46
|
+
this._events.set(event, []);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const listeners = this._events.get(event);
|
|
50
|
+
|
|
51
|
+
// Warn if max listeners exceeded
|
|
52
|
+
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
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
listeners.push({ listener, once: false });
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Adds a one-time event listener
|
|
66
|
+
* @param {string} event - Event name
|
|
67
|
+
* @param {Function} listener - Event handler
|
|
68
|
+
* @returns {EventEmitter} This instance for chaining
|
|
69
|
+
*/
|
|
70
|
+
once(event, listener) {
|
|
71
|
+
if (typeof listener !== 'function') {
|
|
72
|
+
throw new TypeError('Listener must be a function');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!this._events.has(event)) {
|
|
76
|
+
this._events.set(event, []);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this._events.get(event).push({ listener, once: true });
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Removes an event listener
|
|
85
|
+
* @param {string} event - Event name
|
|
86
|
+
* @param {Function} listener - Event handler to remove
|
|
87
|
+
* @returns {EventEmitter} This instance for chaining
|
|
88
|
+
*/
|
|
89
|
+
off(event, listener) {
|
|
90
|
+
if (!this._events.has(event)) {
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const listeners = this._events.get(event);
|
|
95
|
+
const index = listeners.findIndex(entry => entry.listener === listener);
|
|
96
|
+
|
|
97
|
+
if (index !== -1) {
|
|
98
|
+
listeners.splice(index, 1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (listeners.length === 0) {
|
|
102
|
+
this._events.delete(event);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Emits an event to all registered listeners
|
|
110
|
+
* @param {string} event - Event name
|
|
111
|
+
* @param {...*} args - Arguments to pass to listeners
|
|
112
|
+
* @returns {boolean} True if event had listeners
|
|
113
|
+
*/
|
|
114
|
+
emit(event, ...args) {
|
|
115
|
+
if (!this._events.has(event)) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const listeners = this._events.get(event).slice();
|
|
120
|
+
const toRemove = [];
|
|
121
|
+
|
|
122
|
+
for (const entry of listeners) {
|
|
123
|
+
try {
|
|
124
|
+
entry.listener.apply(this, args);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
// Emit error event or log if error event fails
|
|
127
|
+
if (event !== 'error') {
|
|
128
|
+
this.emit('error', error);
|
|
129
|
+
} else {
|
|
130
|
+
console.error('Error in error handler:', error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (entry.once) {
|
|
135
|
+
toRemove.push(entry);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Remove one-time listeners
|
|
140
|
+
if (toRemove.length > 0) {
|
|
141
|
+
const remaining = this._events.get(event).filter(e => !toRemove.includes(e));
|
|
142
|
+
if (remaining.length === 0) {
|
|
143
|
+
this._events.delete(event);
|
|
144
|
+
} else {
|
|
145
|
+
this._events.set(event, remaining);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Removes all listeners for an event or all events
|
|
154
|
+
* @param {string} [event] - Event name (optional, removes all if not provided)
|
|
155
|
+
* @returns {EventEmitter} This instance for chaining
|
|
156
|
+
*/
|
|
157
|
+
removeAllListeners(event) {
|
|
158
|
+
if (event === undefined) {
|
|
159
|
+
this._events.clear();
|
|
160
|
+
} else {
|
|
161
|
+
this._events.delete(event);
|
|
162
|
+
}
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Returns the number of listeners for an event
|
|
168
|
+
* @param {string} event - Event name
|
|
169
|
+
* @returns {number} Number of listeners
|
|
170
|
+
*/
|
|
171
|
+
listenerCount(event) {
|
|
172
|
+
if (!this._events.has(event)) {
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
return this._events.get(event).length;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Returns all event names with listeners
|
|
180
|
+
* @returns {string[]} Array of event names
|
|
181
|
+
*/
|
|
182
|
+
eventNames() {
|
|
183
|
+
return Array.from(this._events.keys());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Sets the maximum number of listeners per event
|
|
188
|
+
* @param {number} n - Maximum listeners
|
|
189
|
+
* @returns {EventEmitter} This instance for chaining
|
|
190
|
+
*/
|
|
191
|
+
setMaxListeners(n) {
|
|
192
|
+
this._maxListeners = n;
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Gets the maximum number of listeners per event
|
|
198
|
+
* @returns {number} Maximum listeners
|
|
199
|
+
*/
|
|
200
|
+
getMaxListeners() {
|
|
201
|
+
return this._maxListeners;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
module.exports = EventEmitter;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview LRU (Least Recently Used) cache implementation
|
|
5
|
+
* @module utils/LRUCache
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generic LRU cache with O(1) get/set operations
|
|
10
|
+
* @template K, V
|
|
11
|
+
* @class LRUCache
|
|
12
|
+
*/
|
|
13
|
+
class LRUCache {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new LRU cache
|
|
16
|
+
* @param {number} maxSize - Maximum number of items to store
|
|
17
|
+
* @throws {Error} If maxSize is not a positive integer
|
|
18
|
+
*/
|
|
19
|
+
constructor(maxSize) {
|
|
20
|
+
if (!Number.isInteger(maxSize) || maxSize <= 0) {
|
|
21
|
+
throw new Error('maxSize must be a positive integer');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Maximum cache size
|
|
26
|
+
* @type {number}
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
this._maxSize = maxSize;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Internal Map for storage (maintains insertion order)
|
|
33
|
+
* @type {Map<K, V>}
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
this._cache = new Map();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets a value from the cache
|
|
41
|
+
* @param {K} key - Key to look up
|
|
42
|
+
* @returns {V|undefined} Value or undefined if not found
|
|
43
|
+
*/
|
|
44
|
+
get(key) {
|
|
45
|
+
if (!this._cache.has(key)) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Move to end (most recently used)
|
|
50
|
+
const value = this._cache.get(key);
|
|
51
|
+
this._cache.delete(key);
|
|
52
|
+
this._cache.set(key, value);
|
|
53
|
+
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Sets a value in the cache
|
|
59
|
+
* @param {K} key - Key to set
|
|
60
|
+
* @param {V} value - Value to store
|
|
61
|
+
* @returns {LRUCache<K, V>} This instance for chaining
|
|
62
|
+
*/
|
|
63
|
+
set(key, value) {
|
|
64
|
+
// If key exists, delete it first to update order
|
|
65
|
+
if (this._cache.has(key)) {
|
|
66
|
+
this._cache.delete(key);
|
|
67
|
+
} else if (this._cache.size >= this._maxSize) {
|
|
68
|
+
// Remove least recently used (first item)
|
|
69
|
+
const firstKey = this._cache.keys().next().value;
|
|
70
|
+
this._cache.delete(firstKey);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this._cache.set(key, value);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a key exists in the cache
|
|
79
|
+
* Does not update access order
|
|
80
|
+
* @param {K} key - Key to check
|
|
81
|
+
* @returns {boolean} True if key exists
|
|
82
|
+
*/
|
|
83
|
+
has(key) {
|
|
84
|
+
return this._cache.has(key);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Removes a key from the cache
|
|
89
|
+
* @param {K} key - Key to remove
|
|
90
|
+
* @returns {boolean} True if key was removed
|
|
91
|
+
*/
|
|
92
|
+
delete(key) {
|
|
93
|
+
return this._cache.delete(key);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Clears all items from the cache
|
|
98
|
+
*/
|
|
99
|
+
clear() {
|
|
100
|
+
this._cache.clear();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Gets the current number of items in the cache
|
|
105
|
+
* @returns {number} Number of items
|
|
106
|
+
*/
|
|
107
|
+
get size() {
|
|
108
|
+
return this._cache.size;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Gets the maximum size of the cache
|
|
113
|
+
* @returns {number} Maximum size
|
|
114
|
+
*/
|
|
115
|
+
get maxSize() {
|
|
116
|
+
return this._maxSize;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns all keys in the cache (most recent last)
|
|
121
|
+
* @returns {K[]} Array of keys
|
|
122
|
+
*/
|
|
123
|
+
keys() {
|
|
124
|
+
return Array.from(this._cache.keys());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Returns all values in the cache (most recent last)
|
|
129
|
+
* @returns {V[]} Array of values
|
|
130
|
+
*/
|
|
131
|
+
values() {
|
|
132
|
+
return Array.from(this._cache.values());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns all entries in the cache (most recent last)
|
|
137
|
+
* @returns {Array} Array of [key, value] pairs
|
|
138
|
+
*/
|
|
139
|
+
entries() {
|
|
140
|
+
return Array.from(this._cache.entries());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Iterates over cache entries
|
|
145
|
+
* @param {function(V, K, Map<K, V>): void} callback - Callback function
|
|
146
|
+
*/
|
|
147
|
+
forEach(callback) {
|
|
148
|
+
this._cache.forEach(callback);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Peeks at a value without updating access order
|
|
153
|
+
* @param {K} key - Key to peek
|
|
154
|
+
* @returns {V|undefined} Value or undefined if not found
|
|
155
|
+
*/
|
|
156
|
+
peek(key) {
|
|
157
|
+
return this._cache.get(key);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Gets the oldest key (least recently used)
|
|
162
|
+
* @returns {K|undefined} Oldest key or undefined if empty
|
|
163
|
+
*/
|
|
164
|
+
getOldest() {
|
|
165
|
+
if (this._cache.size === 0) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
return this._cache.keys().next().value;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Gets the newest key (most recently used)
|
|
173
|
+
* @returns {K|undefined} Newest key or undefined if empty
|
|
174
|
+
*/
|
|
175
|
+
getNewest() {
|
|
176
|
+
if (this._cache.size === 0) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
const keys = Array.from(this._cache.keys());
|
|
180
|
+
return keys[keys.length - 1];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Updates max size and evicts items if necessary
|
|
185
|
+
* @param {number} newMaxSize - New maximum size
|
|
186
|
+
*/
|
|
187
|
+
resize(newMaxSize) {
|
|
188
|
+
if (!Number.isInteger(newMaxSize) || newMaxSize <= 0) {
|
|
189
|
+
throw new Error('maxSize must be a positive integer');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this._maxSize = newMaxSize;
|
|
193
|
+
|
|
194
|
+
// Evict oldest items if over new limit
|
|
195
|
+
while (this._cache.size > this._maxSize) {
|
|
196
|
+
const firstKey = this._cache.keys().next().value;
|
|
197
|
+
this._cache.delete(firstKey);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = LRUCache;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Token bucket rate limiter implementation
|
|
5
|
+
* @module utils/RateLimiter
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Token bucket rate limiter for controlling operation frequency
|
|
10
|
+
* @class RateLimiter
|
|
11
|
+
*/
|
|
12
|
+
class RateLimiter {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new RateLimiter
|
|
15
|
+
* @param {Object} options - Configuration options
|
|
16
|
+
* @param {number} options.tokensPerInterval - Number of tokens added per interval
|
|
17
|
+
* @param {number} options.interval - Interval in milliseconds
|
|
18
|
+
* @param {number} [options.maxTokens] - Maximum token bucket size (defaults to tokensPerInterval)
|
|
19
|
+
*/
|
|
20
|
+
constructor(options) {
|
|
21
|
+
const { tokensPerInterval, interval, maxTokens } = options;
|
|
22
|
+
|
|
23
|
+
if (!Number.isInteger(tokensPerInterval) || tokensPerInterval <= 0) {
|
|
24
|
+
throw new Error('tokensPerInterval must be a positive integer');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!Number.isInteger(interval) || interval <= 0) {
|
|
28
|
+
throw new Error('interval must be a positive integer');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Tokens added per interval
|
|
33
|
+
* @type {number}
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
this._tokensPerInterval = tokensPerInterval;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Interval in milliseconds
|
|
40
|
+
* @type {number}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
this._interval = interval;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Maximum tokens in bucket
|
|
47
|
+
* @type {number}
|
|
48
|
+
* @private
|
|
49
|
+
*/
|
|
50
|
+
this._maxTokens = maxTokens || tokensPerInterval;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Current token count
|
|
54
|
+
* @type {number}
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
this._tokens = this._maxTokens;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Last refill timestamp
|
|
61
|
+
* @type {number}
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
this._lastRefill = Date.now();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Refills tokens based on elapsed time
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
_refill() {
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
const elapsed = now - this._lastRefill;
|
|
74
|
+
const tokensToAdd = Math.floor(elapsed / this._interval) * this._tokensPerInterval;
|
|
75
|
+
|
|
76
|
+
if (tokensToAdd > 0) {
|
|
77
|
+
this._tokens = Math.min(this._maxTokens, this._tokens + tokensToAdd);
|
|
78
|
+
this._lastRefill = now - (elapsed % this._interval);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Attempts to consume tokens
|
|
84
|
+
* @param {number} [count=1] - Number of tokens to consume
|
|
85
|
+
* @returns {boolean} True if tokens were consumed, false if insufficient
|
|
86
|
+
*/
|
|
87
|
+
tryConsume(count = 1) {
|
|
88
|
+
if (!Number.isInteger(count) || count <= 0) {
|
|
89
|
+
throw new Error('count must be a positive integer');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this._refill();
|
|
93
|
+
|
|
94
|
+
if (this._tokens >= count) {
|
|
95
|
+
this._tokens -= count;
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Gets time until tokens are available
|
|
104
|
+
* @param {number} [count=1] - Number of tokens needed
|
|
105
|
+
* @returns {number} Time in milliseconds until tokens are available (0 if available now)
|
|
106
|
+
*/
|
|
107
|
+
getTimeUntilNext(count = 1) {
|
|
108
|
+
if (!Number.isInteger(count) || count <= 0) {
|
|
109
|
+
throw new Error('count must be a positive integer');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this._refill();
|
|
113
|
+
|
|
114
|
+
if (this._tokens >= count) {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const tokensNeeded = count - this._tokens;
|
|
119
|
+
const intervalsNeeded = Math.ceil(tokensNeeded / this._tokensPerInterval);
|
|
120
|
+
|
|
121
|
+
const elapsed = Date.now() - this._lastRefill;
|
|
122
|
+
const timeInCurrentInterval = this._interval - elapsed;
|
|
123
|
+
|
|
124
|
+
return timeInCurrentInterval + (intervalsNeeded - 1) * this._interval;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Waits until tokens are available, then consumes them
|
|
129
|
+
* @param {number} [count=1] - Number of tokens to consume
|
|
130
|
+
* @returns {Promise<void>} Resolves when tokens are consumed
|
|
131
|
+
*/
|
|
132
|
+
async consume(count = 1) {
|
|
133
|
+
const waitTime = this.getTimeUntilNext(count);
|
|
134
|
+
|
|
135
|
+
if (waitTime > 0) {
|
|
136
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Re-check and consume (another consumer may have taken tokens)
|
|
140
|
+
while (!this.tryConsume(count)) {
|
|
141
|
+
const retryWait = this.getTimeUntilNext(count);
|
|
142
|
+
await new Promise(resolve => setTimeout(resolve, retryWait || 1));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Gets the current number of available tokens
|
|
148
|
+
* @returns {number} Available tokens
|
|
149
|
+
*/
|
|
150
|
+
getAvailableTokens() {
|
|
151
|
+
this._refill();
|
|
152
|
+
return this._tokens;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Resets the rate limiter to full capacity
|
|
157
|
+
*/
|
|
158
|
+
reset() {
|
|
159
|
+
this._tokens = this._maxTokens;
|
|
160
|
+
this._lastRefill = Date.now();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Gets rate limiter configuration
|
|
165
|
+
* @returns {Object} Configuration object
|
|
166
|
+
*/
|
|
167
|
+
getConfig() {
|
|
168
|
+
return {
|
|
169
|
+
tokensPerInterval: this._tokensPerInterval,
|
|
170
|
+
interval: this._interval,
|
|
171
|
+
maxTokens: this._maxTokens
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Creates a rate limiter with per-second rate
|
|
178
|
+
* @param {number} requestsPerSecond - Maximum requests per second
|
|
179
|
+
* @returns {RateLimiter} New rate limiter
|
|
180
|
+
*/
|
|
181
|
+
function perSecond(requestsPerSecond) {
|
|
182
|
+
return new RateLimiter({
|
|
183
|
+
tokensPerInterval: requestsPerSecond,
|
|
184
|
+
interval: 1000
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Creates a rate limiter with per-minute rate
|
|
190
|
+
* @param {number} requestsPerMinute - Maximum requests per minute
|
|
191
|
+
* @returns {RateLimiter} New rate limiter
|
|
192
|
+
*/
|
|
193
|
+
function perMinute(requestsPerMinute) {
|
|
194
|
+
return new RateLimiter({
|
|
195
|
+
tokensPerInterval: requestsPerMinute,
|
|
196
|
+
interval: 60000
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = RateLimiter;
|
|
201
|
+
module.exports.perSecond = perSecond;
|
|
202
|
+
module.exports.perMinute = perMinute;
|