unified-ble-manager 4.0.24 → 4.0.26
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 +118 -3
- package/MIGRATION_4.0.md +1 -1
- package/README.md +2 -2
- package/RELEASE.md +20 -3
- package/SBOM.cdx.json +4 -4
- package/THIRD_PARTY_LICENSES.json +1 -1
- package/android/build.gradle +4 -0
- package/android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcher.kt +27 -12
- package/android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidGattRadio.kt +286 -86
- package/android/src/test/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcherLifecycleTest.kt +98 -19
- package/android/src/test/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcherRadioIngressTest.kt +216 -0
- package/docs/BONDING.md +32 -32
- package/docs/ELECTRON.md +1 -1
- package/docs/EXPO_PLUGIN.md +1 -1
- package/docs/GAPS.4.0.md +1 -1
- package/docs/GETTING_STARTED.md +4 -3
- package/docs/NODE.md +1 -1
- package/docs/README.md +3 -0
- package/docs/TUTORIALS.md +2 -0
- package/docs/UNIFIED_SEMANTICS.md +4 -2
- package/docs/WEB.md +1 -1
- package/docs/generated/PLATFORM_SUPPORT.md +1 -1
- package/ios/Owned/OwnedCoreBluetoothProtocolRadio.swift +15 -11
- package/ios/Owned/OwnedCoreBluetoothProtocolRadioCancellation.swift +62 -0
- package/ios/Owned/OwnedCoreBluetoothProtocolRadioSupport.swift +71 -0
- package/lib/commonjs/backend-contract/errors.js +16 -0
- package/lib/commonjs/backend-contract/errors.js.map +1 -1
- package/lib/commonjs/backend-contract/index.js +7 -0
- package/lib/commonjs/backend-contract/index.js.map +1 -1
- package/lib/commonjs/backend-contract/security.js +10 -0
- package/lib/commonjs/backend-contract/security.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-backend-runtime.js +2 -0
- package/lib/commonjs/backends/bluez/bluez-backend-runtime.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-connection-runtime.js +304 -23
- package/lib/commonjs/backends/bluez/bluez-connection-runtime.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-property-waiters.js +4 -5
- package/lib/commonjs/backends/bluez/bluez-property-waiters.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-runtime-models.js +29 -0
- package/lib/commonjs/backends/bluez/bluez-runtime-models.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-runtime-types.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-scan-runtime.js +132 -10
- package/lib/commonjs/backends/bluez/bluez-scan-runtime.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-security.js +10 -7
- package/lib/commonjs/backends/bluez/bluez-security.js.map +1 -1
- package/lib/commonjs/backends/bluez/bluez-subscription-runtime.js +31 -22
- package/lib/commonjs/backends/bluez/bluez-subscription-runtime.js.map +1 -1
- package/lib/commonjs/backends/corebluetooth/corebluetooth-gatt-operations.js +12 -5
- package/lib/commonjs/backends/corebluetooth/corebluetooth-gatt-operations.js.map +1 -1
- package/lib/commonjs/backends/corebluetooth/corebluetooth-read-notify-provenance.js +89 -0
- package/lib/commonjs/backends/corebluetooth/corebluetooth-read-notify-provenance.js.map +1 -0
- package/lib/commonjs/backends/reactnative/react-native-android-security.js +32 -21
- package/lib/commonjs/backends/reactnative/react-native-android-security.js.map +1 -1
- package/lib/commonjs/backends/winrt/winrt-backend.js +17 -3
- package/lib/commonjs/backends/winrt/winrt-backend.js.map +1 -1
- package/lib/commonjs/backends/winrt/winrt-gatt-operations.js +10 -4
- package/lib/commonjs/backends/winrt/winrt-gatt-operations.js.map +1 -1
- package/lib/commonjs/backends/winrt/winrt-handles.js +2 -1
- package/lib/commonjs/backends/winrt/winrt-handles.js.map +1 -1
- package/lib/commonjs/backends/winrt/winrt-security.js +43 -24
- package/lib/commonjs/backends/winrt/winrt-security.js.map +1 -1
- package/lib/commonjs/backends/winrt/winrt-subscription-runtime.js +130 -28
- package/lib/commonjs/backends/winrt/winrt-subscription-runtime.js.map +1 -1
- package/lib/commonjs/core/bounded-stream.js +20 -10
- package/lib/commonjs/core/bounded-stream.js.map +1 -1
- package/lib/commonjs/core/core-discovery.js +4 -0
- package/lib/commonjs/core/core-discovery.js.map +1 -1
- package/lib/commonjs/core/core-lifecycle-observer.js +46 -0
- package/lib/commonjs/core/core-lifecycle-observer.js.map +1 -1
- package/lib/commonjs/core/owned-bounded-stream.js +4 -4
- package/lib/commonjs/core/owned-bounded-stream.js.map +1 -1
- package/lib/commonjs/core/unified-ble-core.js +260 -94
- package/lib/commonjs/core/unified-ble-core.js.map +1 -1
- package/lib/commonjs/electron/connection-event-stream-registry.js +4 -1
- package/lib/commonjs/electron/connection-event-stream-registry.js.map +1 -1
- package/lib/commonjs/electron/renderer-stream-registry.js +4 -1
- package/lib/commonjs/electron/renderer-stream-registry.js.map +1 -1
- package/lib/commonjs/implementation-version.js +1 -1
- package/lib/commonjs/ipc/manager.js +39 -1
- package/lib/commonjs/ipc/manager.js.map +1 -1
- package/lib/commonjs/ipc/public-manager.js +23 -10
- package/lib/commonjs/ipc/public-manager.js.map +1 -1
- package/lib/commonjs/native-protocol/rn-android-boundary.js +10 -0
- package/lib/commonjs/native-protocol/rn-android-boundary.js.map +1 -1
- package/lib/commonjs/public/ble-manager.js +152 -46
- package/lib/commonjs/public/ble-manager.js.map +1 -1
- package/lib/commonjs/public/cleanup.js +1 -0
- package/lib/commonjs/public/cleanup.js.map +1 -1
- package/lib/commonjs/public/scan-state.js +46 -0
- package/lib/commonjs/public/scan-state.js.map +1 -1
- package/lib/commonjs/public/streams.js +12 -7
- package/lib/commonjs/public/streams.js.map +1 -1
- package/lib/commonjs/tck/first-party/winrt-tck-registration.js +5 -0
- package/lib/commonjs/tck/first-party/winrt-tck-registration.js.map +1 -1
- package/lib/commonjs/tck/runner-public-scenarios.js +17 -2
- package/lib/commonjs/tck/runner-public-scenarios.js.map +1 -1
- package/lib/commonjs/testing/deterministic/deterministic-stream.js +16 -5
- package/lib/commonjs/testing/deterministic/deterministic-stream.js.map +1 -1
- package/lib/commonjs/web/navigator-web-bluetooth-boundary.js +20 -0
- package/lib/commonjs/web/navigator-web-bluetooth-boundary.js.map +1 -1
- package/lib/commonjs/web/web-bluetooth-backend.js +135 -6
- package/lib/commonjs/web/web-bluetooth-backend.js.map +1 -1
- package/lib/commonjs/web.js.map +1 -1
- package/lib/module/backend-contract/errors.js +15 -0
- package/lib/module/backend-contract/errors.js.map +1 -1
- package/lib/module/backend-contract/index.js +1 -0
- package/lib/module/backend-contract/index.js.map +1 -1
- package/lib/module/backend-contract/security.js +11 -0
- package/lib/module/backend-contract/security.js.map +1 -1
- package/lib/module/backends/bluez/bluez-backend-runtime.js +3 -1
- package/lib/module/backends/bluez/bluez-backend-runtime.js.map +1 -1
- package/lib/module/backends/bluez/bluez-connection-runtime.js +305 -25
- package/lib/module/backends/bluez/bluez-connection-runtime.js.map +1 -1
- package/lib/module/backends/bluez/bluez-property-waiters.js +4 -6
- package/lib/module/backends/bluez/bluez-property-waiters.js.map +1 -1
- package/lib/module/backends/bluez/bluez-runtime-models.js +27 -0
- package/lib/module/backends/bluez/bluez-runtime-models.js.map +1 -1
- package/lib/module/backends/bluez/bluez-runtime-types.js.map +1 -1
- package/lib/module/backends/bluez/bluez-scan-runtime.js +133 -11
- package/lib/module/backends/bluez/bluez-scan-runtime.js.map +1 -1
- package/lib/module/backends/bluez/bluez-security.js +10 -7
- package/lib/module/backends/bluez/bluez-security.js.map +1 -1
- package/lib/module/backends/bluez/bluez-subscription-runtime.js +31 -22
- package/lib/module/backends/bluez/bluez-subscription-runtime.js.map +1 -1
- package/lib/module/backends/corebluetooth/corebluetooth-gatt-operations.js +12 -5
- package/lib/module/backends/corebluetooth/corebluetooth-gatt-operations.js.map +1 -1
- package/lib/module/backends/corebluetooth/corebluetooth-read-notify-provenance.js +79 -0
- package/lib/module/backends/corebluetooth/corebluetooth-read-notify-provenance.js.map +1 -0
- package/lib/module/backends/reactnative/react-native-android-security.js +32 -21
- package/lib/module/backends/reactnative/react-native-android-security.js.map +1 -1
- package/lib/module/backends/winrt/winrt-backend.js +17 -3
- package/lib/module/backends/winrt/winrt-backend.js.map +1 -1
- package/lib/module/backends/winrt/winrt-gatt-operations.js +12 -6
- package/lib/module/backends/winrt/winrt-gatt-operations.js.map +1 -1
- package/lib/module/backends/winrt/winrt-handles.js +2 -1
- package/lib/module/backends/winrt/winrt-handles.js.map +1 -1
- package/lib/module/backends/winrt/winrt-security.js +43 -24
- package/lib/module/backends/winrt/winrt-security.js.map +1 -1
- package/lib/module/backends/winrt/winrt-subscription-runtime.js +128 -28
- package/lib/module/backends/winrt/winrt-subscription-runtime.js.map +1 -1
- package/lib/module/core/bounded-stream.js +20 -10
- package/lib/module/core/bounded-stream.js.map +1 -1
- package/lib/module/core/core-discovery.js +4 -0
- package/lib/module/core/core-discovery.js.map +1 -1
- package/lib/module/core/core-lifecycle-observer.js +45 -0
- package/lib/module/core/core-lifecycle-observer.js.map +1 -1
- package/lib/module/core/owned-bounded-stream.js +4 -4
- package/lib/module/core/owned-bounded-stream.js.map +1 -1
- package/lib/module/core/unified-ble-core.js +261 -95
- package/lib/module/core/unified-ble-core.js.map +1 -1
- package/lib/module/electron/connection-event-stream-registry.js +5 -2
- package/lib/module/electron/connection-event-stream-registry.js.map +1 -1
- package/lib/module/electron/renderer-stream-registry.js +5 -2
- package/lib/module/electron/renderer-stream-registry.js.map +1 -1
- package/lib/module/implementation-version.js +1 -1
- package/lib/module/ipc/manager.js +40 -2
- package/lib/module/ipc/manager.js.map +1 -1
- package/lib/module/ipc/public-manager.js +24 -11
- package/lib/module/ipc/public-manager.js.map +1 -1
- package/lib/module/native-protocol/rn-android-boundary.js +10 -0
- package/lib/module/native-protocol/rn-android-boundary.js.map +1 -1
- package/lib/module/public/ble-manager.js +153 -47
- package/lib/module/public/ble-manager.js.map +1 -1
- package/lib/module/public/cleanup.js +1 -1
- package/lib/module/public/cleanup.js.map +1 -1
- package/lib/module/public/scan-state.js +44 -0
- package/lib/module/public/scan-state.js.map +1 -1
- package/lib/module/public/streams.js +13 -8
- package/lib/module/public/streams.js.map +1 -1
- package/lib/module/tck/first-party/winrt-tck-registration.js +5 -0
- package/lib/module/tck/first-party/winrt-tck-registration.js.map +1 -1
- package/lib/module/tck/runner-public-scenarios.js +17 -2
- package/lib/module/tck/runner-public-scenarios.js.map +1 -1
- package/lib/module/testing/deterministic/deterministic-stream.js +16 -5
- package/lib/module/testing/deterministic/deterministic-stream.js.map +1 -1
- package/lib/module/web/navigator-web-bluetooth-boundary.js +20 -0
- package/lib/module/web/navigator-web-bluetooth-boundary.js.map +1 -1
- package/lib/module/web/web-bluetooth-backend.js +135 -6
- package/lib/module/web/web-bluetooth-backend.js.map +1 -1
- package/lib/module/web.js.map +1 -1
- package/lib/typescript/commonjs/src/backend-contract/errors.d.ts +2 -0
- package/lib/typescript/commonjs/src/backend-contract/errors.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backend-contract/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/backend-contract/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backend-contract/security.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backend-contract/streams.d.ts +5 -1
- package/lib/typescript/commonjs/src/backend-contract/streams.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-runtime.d.ts +2 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-runtime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-runtime.d.ts +1 -0
- package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-runtime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-property-waiters.d.ts +1 -0
- package/lib/typescript/commonjs/src/backends/bluez/bluez-property-waiters.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-models.d.ts +3 -0
- package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-models.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-types.d.ts +22 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-types.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-scan-runtime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-security.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-security.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-subscription-runtime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-gatt-operations.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-read-notify-provenance.d.ts +37 -0
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-read-notify-provenance.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-security.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-security.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-backend.d.ts +7 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-backend.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-boundary.d.ts +1 -0
- package/lib/typescript/commonjs/src/backends/winrt/winrt-boundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-gatt-operations.d.ts +1 -0
- package/lib/typescript/commonjs/src/backends/winrt/winrt-gatt-operations.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-handles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-security.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-security.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-subscription-runtime.d.ts +4 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-subscription-runtime.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/bounded-stream.d.ts +5 -3
- package/lib/typescript/commonjs/src/core/bounded-stream.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/core-discovery.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/core-lifecycle-observer.d.ts +10 -0
- package/lib/typescript/commonjs/src/core/core-lifecycle-observer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/owned-bounded-stream.d.ts +3 -3
- package/lib/typescript/commonjs/src/core/owned-bounded-stream.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/core/unified-ble-core.d.ts +6 -0
- package/lib/typescript/commonjs/src/core/unified-ble-core.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/electron/connection-event-stream-registry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/electron/renderer-stream-registry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/implementation-version.d.ts +1 -1
- package/lib/typescript/commonjs/src/ipc/manager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ipc/public-manager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/manager/consumer-handles.d.ts +1 -0
- package/lib/typescript/commonjs/src/manager/consumer-handles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/native-protocol/rn-android-boundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/public/ble-manager.d.ts +13 -2
- package/lib/typescript/commonjs/src/public/ble-manager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/public/cleanup.d.ts +3 -1
- package/lib/typescript/commonjs/src/public/cleanup.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/public/scan-state.d.ts +15 -0
- package/lib/typescript/commonjs/src/public/scan-state.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/public/streams.d.ts +1 -0
- package/lib/typescript/commonjs/src/public/streams.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/tck/first-party/winrt-tck-registration.d.ts +1 -0
- package/lib/typescript/commonjs/src/tck/first-party/winrt-tck-registration.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/tck/runner-public-scenarios.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/testing/deterministic/deterministic-stream.d.ts +4 -2
- package/lib/typescript/commonjs/src/testing/deterministic/deterministic-stream.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/navigator-web-bluetooth-boundary.d.ts +9 -1
- package/lib/typescript/commonjs/src/web/navigator-web-bluetooth-boundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/web-bluetooth-backend.d.ts +16 -0
- package/lib/typescript/commonjs/src/web/web-bluetooth-backend.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/web-bluetooth-boundary.d.ts +11 -0
- package/lib/typescript/commonjs/src/web/web-bluetooth-boundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web.d.ts +1 -1
- package/lib/typescript/commonjs/src/web.d.ts.map +1 -1
- package/lib/typescript/module/src/backend-contract/errors.d.ts +2 -0
- package/lib/typescript/module/src/backend-contract/errors.d.ts.map +1 -1
- package/lib/typescript/module/src/backend-contract/index.d.ts +1 -0
- package/lib/typescript/module/src/backend-contract/index.d.ts.map +1 -1
- package/lib/typescript/module/src/backend-contract/security.d.ts.map +1 -1
- package/lib/typescript/module/src/backend-contract/streams.d.ts +5 -1
- package/lib/typescript/module/src/backend-contract/streams.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-backend-runtime.d.ts +2 -1
- package/lib/typescript/module/src/backends/bluez/bluez-backend-runtime.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-connection-runtime.d.ts +1 -0
- package/lib/typescript/module/src/backends/bluez/bluez-connection-runtime.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-property-waiters.d.ts +1 -0
- package/lib/typescript/module/src/backends/bluez/bluez-property-waiters.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-runtime-models.d.ts +3 -0
- package/lib/typescript/module/src/backends/bluez/bluez-runtime-models.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-runtime-types.d.ts +22 -1
- package/lib/typescript/module/src/backends/bluez/bluez-runtime-types.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-scan-runtime.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-security.d.ts +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-security.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-subscription-runtime.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-gatt-operations.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-read-notify-provenance.d.ts +37 -0
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-read-notify-provenance.d.ts.map +1 -0
- package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-android-security.d.ts +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-android-security.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-backend.d.ts +7 -1
- package/lib/typescript/module/src/backends/winrt/winrt-backend.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-boundary.d.ts +1 -0
- package/lib/typescript/module/src/backends/winrt/winrt-boundary.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-gatt-operations.d.ts +1 -0
- package/lib/typescript/module/src/backends/winrt/winrt-gatt-operations.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-handles.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-security.d.ts +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-security.d.ts.map +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-subscription-runtime.d.ts +4 -1
- package/lib/typescript/module/src/backends/winrt/winrt-subscription-runtime.d.ts.map +1 -1
- package/lib/typescript/module/src/core/bounded-stream.d.ts +5 -3
- package/lib/typescript/module/src/core/bounded-stream.d.ts.map +1 -1
- package/lib/typescript/module/src/core/core-discovery.d.ts.map +1 -1
- package/lib/typescript/module/src/core/core-lifecycle-observer.d.ts +10 -0
- package/lib/typescript/module/src/core/core-lifecycle-observer.d.ts.map +1 -1
- package/lib/typescript/module/src/core/owned-bounded-stream.d.ts +3 -3
- package/lib/typescript/module/src/core/owned-bounded-stream.d.ts.map +1 -1
- package/lib/typescript/module/src/core/unified-ble-core.d.ts +6 -0
- package/lib/typescript/module/src/core/unified-ble-core.d.ts.map +1 -1
- package/lib/typescript/module/src/electron/connection-event-stream-registry.d.ts.map +1 -1
- package/lib/typescript/module/src/electron/renderer-stream-registry.d.ts.map +1 -1
- package/lib/typescript/module/src/implementation-version.d.ts +1 -1
- package/lib/typescript/module/src/ipc/manager.d.ts.map +1 -1
- package/lib/typescript/module/src/ipc/public-manager.d.ts.map +1 -1
- package/lib/typescript/module/src/manager/consumer-handles.d.ts +1 -0
- package/lib/typescript/module/src/manager/consumer-handles.d.ts.map +1 -1
- package/lib/typescript/module/src/native-protocol/rn-android-boundary.d.ts.map +1 -1
- package/lib/typescript/module/src/public/ble-manager.d.ts +13 -2
- package/lib/typescript/module/src/public/ble-manager.d.ts.map +1 -1
- package/lib/typescript/module/src/public/cleanup.d.ts +3 -1
- package/lib/typescript/module/src/public/cleanup.d.ts.map +1 -1
- package/lib/typescript/module/src/public/scan-state.d.ts +15 -0
- package/lib/typescript/module/src/public/scan-state.d.ts.map +1 -1
- package/lib/typescript/module/src/public/streams.d.ts +1 -0
- package/lib/typescript/module/src/public/streams.d.ts.map +1 -1
- package/lib/typescript/module/src/tck/first-party/winrt-tck-registration.d.ts +1 -0
- package/lib/typescript/module/src/tck/first-party/winrt-tck-registration.d.ts.map +1 -1
- package/lib/typescript/module/src/tck/runner-public-scenarios.d.ts.map +1 -1
- package/lib/typescript/module/src/testing/deterministic/deterministic-stream.d.ts +4 -2
- package/lib/typescript/module/src/testing/deterministic/deterministic-stream.d.ts.map +1 -1
- package/lib/typescript/module/src/web/navigator-web-bluetooth-boundary.d.ts +9 -1
- package/lib/typescript/module/src/web/navigator-web-bluetooth-boundary.d.ts.map +1 -1
- package/lib/typescript/module/src/web/web-bluetooth-backend.d.ts +16 -0
- package/lib/typescript/module/src/web/web-bluetooth-backend.d.ts.map +1 -1
- package/lib/typescript/module/src/web/web-bluetooth-boundary.d.ts +11 -0
- package/lib/typescript/module/src/web/web-bluetooth-boundary.d.ts.map +1 -1
- package/lib/typescript/module/src/web.d.ts +1 -1
- package/lib/typescript/module/src/web.d.ts.map +1 -1
- package/native/PREBUILDS.json +9 -9
- package/native/electron/corebluetooth/binding.gyp +2 -1
- package/native/electron/corebluetooth/prebuilds/darwin-arm64/unified_ble_corebluetooth.node +0 -0
- package/native/electron/corebluetooth/prebuilds/darwin-x64/unified_ble_corebluetooth.node +0 -0
- package/native/electron/corebluetooth/src/addon.mm +170 -24
- package/native/electron/winrt/prebuilds/win32-arm64/unified_ble_winrt.node +0 -0
- package/native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node +0 -0
- package/native/electron/winrt/src/addon.cpp +19 -0
- package/native/electron/winrt/src/winrt-boundary.inc +28 -3
- package/native/protocol/CMakeLists.txt +14 -0
- package/native/protocol/include/OwnedCoreBluetoothReadNotifyProvenance.hpp +61 -0
- package/native/tauri/src/btleplug_dispatcher.rs +1836 -243
- package/package.json +1 -1
- package/src/backend-contract/errors.ts +20 -0
- package/src/backend-contract/index.ts +1 -0
- package/src/backend-contract/security.ts +11 -0
- package/src/backend-contract/streams.ts +5 -1
- package/src/backends/bluez/bluez-backend-runtime.ts +8 -1
- package/src/backends/bluez/bluez-connection-runtime.ts +406 -27
- package/src/backends/bluez/bluez-property-waiters.ts +8 -6
- package/src/backends/bluez/bluez-runtime-models.ts +24 -0
- package/src/backends/bluez/bluez-runtime-types.ts +23 -1
- package/src/backends/bluez/bluez-scan-runtime.ts +170 -14
- package/src/backends/bluez/bluez-security.ts +10 -7
- package/src/backends/bluez/bluez-subscription-runtime.ts +41 -22
- package/src/backends/corebluetooth/corebluetooth-gatt-operations.ts +12 -5
- package/src/backends/corebluetooth/corebluetooth-read-notify-provenance.ts +133 -0
- package/src/backends/reactnative/react-native-android-security.ts +35 -17
- package/src/backends/winrt/winrt-backend.ts +27 -3
- package/src/backends/winrt/winrt-boundary.ts +1 -0
- package/src/backends/winrt/winrt-gatt-operations.ts +19 -5
- package/src/backends/winrt/winrt-handles.ts +2 -0
- package/src/backends/winrt/winrt-security.ts +55 -26
- package/src/backends/winrt/winrt-subscription-runtime.ts +201 -38
- package/src/core/bounded-stream.ts +27 -11
- package/src/core/core-discovery.ts +4 -0
- package/src/core/core-lifecycle-observer.ts +54 -1
- package/src/core/owned-bounded-stream.ts +5 -5
- package/src/core/unified-ble-core.ts +329 -118
- package/src/electron/connection-event-stream-registry.ts +3 -1
- package/src/electron/renderer-stream-registry.ts +3 -1
- package/src/implementation-version.ts +1 -1
- package/src/ipc/manager.ts +49 -2
- package/src/ipc/public-manager.ts +19 -7
- package/src/manager/consumer-handles.ts +1 -0
- package/src/native-protocol/rn-android-boundary.ts +10 -0
- package/src/public/ble-manager.ts +172 -58
- package/src/public/cleanup.ts +1 -1
- package/src/public/scan-state.ts +60 -0
- package/src/public/streams.ts +15 -8
- package/src/tck/first-party/winrt-tck-registration.ts +6 -0
- package/src/tck/runner-public-scenarios.ts +21 -5
- package/src/testing/deterministic/deterministic-stream.ts +19 -6
- package/src/web/navigator-web-bluetooth-boundary.ts +50 -0
- package/src/web/web-bluetooth-backend.ts +167 -6
- package/src/web/web-bluetooth-boundary.ts +11 -0
- package/src/web.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,121 @@ All notable changes to `unified-ble-manager` are documented here.
|
|
|
6
6
|
|
|
7
7
|
No changes yet.
|
|
8
8
|
|
|
9
|
+
## [4.0.26] - 2026-09-06
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- A third-party backend can now follow, and pass, the cancellation contract
|
|
14
|
+
4.0.7 introduced. `cancelOutcomeForPairResult` was exported from
|
|
15
|
+
`backend-contract/security` but re-exported type-only from the barrel, so it
|
|
16
|
+
never reached `/backend-sdk`; first-party backends imported it by deep
|
|
17
|
+
relative path and nothing failed. The TCK still hard-required
|
|
18
|
+
`outcome === 'cancelled'` from both `pair()` and `cancelPairing()`, so a
|
|
19
|
+
backend that correctly reported `'paired'` when the bond won the race failed
|
|
20
|
+
`security-pairing-cancellation-cleans-up` while conforming. The scenario now
|
|
21
|
+
asserts that the two calls do not contradict each other about one pairing,
|
|
22
|
+
checked through the shared mapper rather than against a fixed word.
|
|
23
|
+
`cancelOutcomeForPairResult` also gains a `default` branch so an out-of-contract
|
|
24
|
+
outcome from a third-party backend is named as `protocol.violation` instead of
|
|
25
|
+
surfacing as `undefined` and a raw TypeError several frames away. The `default`
|
|
26
|
+
routes through a `never` parameter, so a new first-party `SecurityPairResult`
|
|
27
|
+
variant is still a compile error (#167).
|
|
28
|
+
|
|
29
|
+
## [4.0.25] - 2026-09-05
|
|
30
|
+
|
|
31
|
+
### Fixes
|
|
32
|
+
|
|
33
|
+
- Tauri: separate live correlation capacity from 30s replay tombstones. Routed
|
|
34
|
+
cleanup still admits after a full replay window. Live exhaustion is retryable
|
|
35
|
+
backpressure, not `protocol.violation`. Replay of an old correlation still
|
|
36
|
+
rejects.
|
|
37
|
+
- Tauri: a native connect that completes after its caller/lease is gone gets an
|
|
38
|
+
orphan cleanup owner before compensating disconnect. Reservation and owner
|
|
39
|
+
release together, and only for the matching generation.
|
|
40
|
+
- Tauri: scan-stream failure keeps the scan owner in a stopping state until
|
|
41
|
+
native stop settles. A failed stop stays retryable and blocks a second scan.
|
|
42
|
+
Event and poll emit failures carry structured native diagnostics on the
|
|
43
|
+
shared `source-failed` terminal without inventing drop counters (#173).
|
|
44
|
+
- Tauri: post-await lease/generation checks on unsubscribe and scan stop.
|
|
45
|
+
Old-generation resources quarantine instead of attaching to a replacement
|
|
46
|
+
caller. Compensating unsubscribe after subscribe success uses the same orphan
|
|
47
|
+
owner instead of discarding the outcome.
|
|
48
|
+
- Tauri: overlapping stop requests for the same scan join one native
|
|
49
|
+
`stop_scan()`. Completions carry an attempt token, so a late stop of scan A
|
|
50
|
+
cannot take scan B’s stopping owner.
|
|
51
|
+
- Core: retain unadopted scan/connect leases when stale-admission `stop`/`release`
|
|
52
|
+
fails, and retry that exact lease on later manager cleanup. Aborted, destroyed,
|
|
53
|
+
or deadline-expired callers settle promptly; native work stays owned until
|
|
54
|
+
adopted or compensated.
|
|
55
|
+
- Core: coalesce concurrent `rediscoverGatt` waiters onto one replacement after
|
|
56
|
+
a shared in-flight discovery settles. A starter abort or timeout does not fail
|
|
57
|
+
a sibling waiter with its own admission.
|
|
58
|
+
- Public scan observation overflow is subscriber-local. Consuming only `events`
|
|
59
|
+
at full speed with `duplicates: 'all'` and `overflowPolicy: 'error'` no longer
|
|
60
|
+
terminates the scan because an unused observation queue filled.
|
|
61
|
+
- Drop-policy public scan overflow (`balanced` / `latest` / drop-*) reports an
|
|
62
|
+
overflow notice and keeps scanning. The radio stays up. `overflowPolicy:
|
|
63
|
+
'error'` (`lossless-bounded`) still fail-closes the consumed view as
|
|
64
|
+
`failed`/`overflow`; physical `stop()` remains cleanup.
|
|
65
|
+
- In-process and IPC scan sessions leave `active` when the host source ends
|
|
66
|
+
without `stop()`. An already-terminal source never publishes `active`; the
|
|
67
|
+
first state is the projected terminal (`failed` for `source-failed` /
|
|
68
|
+
`connection-lost` / `overflow`, `stopped` for ordinary close). That event is
|
|
69
|
+
ended delivery; `stop()` remains the physical cleanup path. The data pump
|
|
70
|
+
still drains advertisements already accepted by `finishWithReason` before
|
|
71
|
+
the observation terminal. Structured `source-failed` errors survive scan-state
|
|
72
|
+
binding and reach `scan.observations`.
|
|
73
|
+
- BlueZ `StopDiscovery` / `StopNotify` release this client’s session even if
|
|
74
|
+
another D-Bus client keeps `Discovering` / `Notifying` true.
|
|
75
|
+
- BlueZ `StartNotify` confirmation failure after native accept keeps a retryable
|
|
76
|
+
`StopNotify` owner instead of orphaning the notify session. A late enablement
|
|
77
|
+
success does not promote `removing` / `enabling-failed` back to `ready`.
|
|
78
|
+
- BlueZ `SetDiscoveryFilter`, `StartDiscovery`, and `ConnectDevice` honor caller
|
|
79
|
+
deadline/abort without dropping a later native allocation.
|
|
80
|
+
- BlueZ keeps a retryable compensating `Disconnect` when `ConnectDevice`
|
|
81
|
+
succeeds after the caller is gone. A failed first Disconnect is retried on
|
|
82
|
+
destroy instead of being logged and forgotten.
|
|
83
|
+
- BlueZ address-connect fallback checks scan-plan compatibility, waits out a
|
|
84
|
+
stopping scan, and widens an excluding live scan for concurrent address
|
|
85
|
+
waiters, restoring the owner filter only after the last borrower leaves
|
|
86
|
+
instead of waiting under a filter that cannot observe the target.
|
|
87
|
+
- Apple CoreBluetooth rejects an independent GATT read while that characteristic
|
|
88
|
+
is notifying, because `didUpdateValueFor` cannot distinguish a read response
|
|
89
|
+
from a notification. Electron/Node CoreBluetooth uses the same policy. A read
|
|
90
|
+
admitted while idle still completes from its ATT response if CCCD enable
|
|
91
|
+
races it; overlapping reads and subscribe-while-read are rejected; fused
|
|
92
|
+
values that cannot be attributed are dropped. Remaining native reject codes
|
|
93
|
+
(iOS 1031/1011/1032, Electron 413/414/415) map to `gatt.read-failed` or
|
|
94
|
+
`gatt.subscribe-failed`, not `platform.failure`.
|
|
95
|
+
- Android `setCharacteristicNotification(...) == false` is a local registration
|
|
96
|
+
failure, not proven link loss. Generation-matched disconnect and GATT status 19
|
|
97
|
+
remain the physical-loss authority. The 4.0.22 250 ms CCCD/disconnect two-signal
|
|
98
|
+
arbitration is unchanged. Notifications that arrive after the CCCD write and
|
|
99
|
+
before `onDescriptorWrite` SUCCESS are staged and flushed to admitted
|
|
100
|
+
subscribers. A later same-generation CCCD SUCCESS claims the arbiter instead
|
|
101
|
+
of leaving the peer enabled after a failed public subscribe.
|
|
102
|
+
- WinRT stages `ValueChanged` notifications that arrive before CCCD enablement
|
|
103
|
+
completes, then flushes them once and in order only to admitted subscribers.
|
|
104
|
+
Staging continues until every pending waiter is admitted, and a per-subscriber
|
|
105
|
+
overflow does not discard siblings’ pending buffer.
|
|
106
|
+
- WinRT subscription invalidation waits are bounded. If native `startNotify`
|
|
107
|
+
never settles, disconnect still completes within the cleanup budget. A late
|
|
108
|
+
enable issues a compensating `stopNotify` when the native CCCD key is vacant,
|
|
109
|
+
and skips that disable only when a replacement generation already occupies it.
|
|
110
|
+
Native notification map entries are keyed by connection generation.
|
|
111
|
+
- `cancelPairing()` honors abort and deadline on Android, WinRT, and BlueZ.
|
|
112
|
+
Admission runs before native cancellation. A timed-out wait is not reported as
|
|
113
|
+
`'cancelled'`. An abandoned waiter leaves the in-flight pairing owned.
|
|
114
|
+
`pair()` abort/deadline keeps the pairing owned until the native result;
|
|
115
|
+
a later native `paired`/`rejected` is authoritative for both `pair()` and
|
|
116
|
+
`cancelPairing()`.
|
|
117
|
+
- Web adapter `watchState()` follows browser `availabilitychanged` instead of
|
|
118
|
+
staying stale until another API samples availability. When that event is
|
|
119
|
+
missing, watches share one bounded `getAvailability()` poll. A completed
|
|
120
|
+
availability sample is applied unless a newer sample has already been applied,
|
|
121
|
+
so an outstanding later probe cannot make `attach()` throw `adapter.unavailable`
|
|
122
|
+
from a stale unavailable cache.
|
|
123
|
+
|
|
9
124
|
## [4.0.24] - 2026-09-05
|
|
10
125
|
|
|
11
126
|
### Fixes
|
|
@@ -254,7 +369,7 @@ hardware reproduced a later callback ordering that required the 4.0.22 fix.
|
|
|
254
369
|
|
|
255
370
|
### Changed behaviour
|
|
256
371
|
|
|
257
|
-
- `cancelPairing()` reports what the cancellation **achieved**, not what it requested, and can no longer contradict the pairing it cancelled. Every backend answered `'cancelled'` unconditionally the moment the cancel was dispatched, so a cancellation that lost the race told the caller no bond exists while one did — and a caller who believes that never looks again. It now reads the in-flight pairing's own result rather than forming a second opinion, which is what makes the two calls incapable of disagreeing: there is one source of truth and the cancellation reads it. `SecurityCancelPairingResult` gains the words to say so — `'paired'` when the bond completed before the cancellation arrived, and `'rejected'` (carrying the peer's reason) when the peer refused, because claiming credit for stopping something that stopped itself is the same substitution with the arrow reversed. A pairing that
|
|
372
|
+
- `cancelPairing()` reports what the cancellation **achieved**, not what it requested, and can no longer contradict the pairing it cancelled. Every backend answered `'cancelled'` unconditionally the moment the cancel was dispatched, so a cancellation that lost the race told the caller no bond exists while one did — and a caller who believes that never looks again. It now reads the in-flight pairing's own result rather than forming a second opinion, which is what makes the two calls incapable of disagreeing: there is one source of truth and the cancellation reads it. `SecurityCancelPairingResult` gains the words to say so — `'paired'` when the bond completed before the cancellation arrived, and `'rejected'` (carrying the peer's reason) when the peer refused, because claiming credit for stopping something that stopped itself is the same substitution with the arrow reversed. A pairing that _fails_ is not given an invented outcome: `cancelPairing()` rejects with the error the pairing rejected with. `'paired'` deliberately matches `SecurityPairResult`'s `'paired'` — a bond exists as a result of this operation — and is not `'already-paired'`, which in that type means the peer was bonded _before_ the call; one word, one meaning, in both types. Applies to BlueZ, Android, WinRT **and** the deterministic `/testing` backend, since a mock that answers differently from every real radio lets a consumer's suite pass against a contract no device honours. WinRT additionally short-circuited _upstream_ of the shared mapper — when its dispatcher reported the operation already terminal, which is exactly the lost race, it answered `'not-pairing'`, contradicting its own `pair()` and making that word mean both "there was nothing to stop" and "it was already over" (#159).
|
|
258
373
|
|
|
259
374
|
### Additions
|
|
260
375
|
|
|
@@ -262,13 +377,13 @@ hardware reproduced a later callback ordering that required the 4.0.22 fix.
|
|
|
262
377
|
|
|
263
378
|
This package never acquires that privilege: it opens no management socket, shells out to nothing, and does not assume it is root. A library that silently escalates hands an application capabilities its author did not choose and cannot audit. The **host** supplies the operation via `BluezBackendProviderOptions.pairingGeneration`, which makes the escalation visible in the application that opted into it. Omit it and `'require'`/`'disallow'` keep failing closed exactly as in 4.0.6 — the default posture is unchanged.
|
|
264
379
|
|
|
265
|
-
Three properties of the kernel setting a host must accept, documented in `docs/BONDING.md` rather than discovered: it is **adapter-wide**, not per-pairing, so every pairing on that controller uses the selected generation while it is held; it **outlives the process**, because the kernel keeps it until something sets it back; and a **failed restore never changes the pairing's outcome** — a bond that was created is reported as created, with the restore failure reported separately, because leaving a controller in LE Legacy and telling a caller they are not bonded are both serious and are different facts. Concurrent
|
|
380
|
+
Three properties of the kernel setting a host must accept, documented in `docs/BONDING.md` rather than discovered: it is **adapter-wide**, not per-pairing, so every pairing on that controller uses the selected generation while it is held; it **outlives the process**, because the kernel keeps it until something sets it back; and a **failed restore never changes the pairing's outcome** — a bond that was created is reported as created, with the restore failure reported separately, because leaving a controller in LE Legacy and telling a caller they are not bonded are both serious and are different facts. Concurrent _directed_ pairings on one adapter are serialised so they cannot corrupt each other's restore value; an undirected (`'prefer'`) pairing does not take that lock and uses whichever generation is held, which `docs/BONDING.md` states beside the option.
|
|
266
381
|
|
|
267
382
|
`security:pairing-generation` joins the capability catalog and is reported by the instantiated backend at runtime: `unsupported` with the platform reason when no operation was supplied, `limited` when one was — so two BlueZ backends on one machine legitimately answer differently. Evidence is deterministic tests only; this is **not** physical-radio proof, and the label says so (#144).
|
|
268
383
|
|
|
269
384
|
### Fixes
|
|
270
385
|
|
|
271
|
-
- A Tauri connect that succeeds physically but is then denied admission no longer strands the peer. Both compensation branches — the caller vanished, and the caller's lease went stale — removed the peer reservation
|
|
386
|
+
- A Tauri connect that succeeds physically but is then denied admission no longer strands the peer. Both compensation branches — the caller vanished, and the caller's lease went stale — removed the peer reservation _before_ attempting the disconnect and then discarded its result with `.ok()`. If that disconnect failed or hung while the peripheral stayed connected, the result was a connected peer with no owner and no handle: nothing could reach it, nothing could retry it, and the caller was told only that admission was denied. Compensation now follows the rule the explicit disconnect already follows — a bounded wait, a fresh state reading, and a D-Bus error naming a vanished device object read as evidence of release rather than as a failed question — and surrenders the reservation only when the platform proves the link is down. Genuine indeterminacy keeps it so a retry can reclaim the peer, and the admission error carries what compensation could not undo, which is the difference between "try again" and "a peer is stranded" (#146).
|
|
272
387
|
|
|
273
388
|
### Known limitations
|
|
274
389
|
|
package/MIGRATION_4.0.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Migrating from react-native-ble-plx
|
|
4
4
|
|
|
5
|
-
This source targets `4.0.
|
|
5
|
+
This source targets `4.0.26`. The `4.0.0` release is a new package and a new contract. It is **not a source-compatible rename**. There is no `new BleManager()` facade, no Base64 characteristic values, and no public transaction IDs.
|
|
6
6
|
|
|
7
7
|
This page is for a React Native app that already uses `react-native-ble-plx`. Web, Electron, Node, and Tauri are new hosts — use those pages after you understand the RN rewrite.
|
|
8
8
|
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ root import does not pick a radio. Package SemVer and backend support labels are
|
|
|
18
18
|
independent: each radio backend keeps its evidence-derived label. See
|
|
19
19
|
[`docs/PLATFORMS.md`](docs/PLATFORMS.md).
|
|
20
20
|
|
|
21
|
-
This source tree is versioned `4.0.
|
|
21
|
+
This source tree is versioned `4.0.26`. Install the exact version shown in the npm
|
|
22
22
|
registry. During release preparation, the version in `package.json` can be ahead
|
|
23
23
|
of npm until the matching tag-driven workflow publishes it; the registry and
|
|
24
24
|
GitHub release remain authoritative.
|
|
@@ -243,7 +243,7 @@ Web Bluetooth replaces the scan with `ble.choose(...)` from a user gesture. The
|
|
|
243
243
|
|
|
244
244
|
| Member | Use |
|
|
245
245
|
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
246
|
-
| `observations` | Bounded stream: `value`, `overflow`, or `terminal`
|
|
246
|
+
| `observations` | Bounded stream: `value`, `overflow`, or `terminal`. Drop-policy overflow means ads were missed; the scan stays up. `error` fail-closes. |
|
|
247
247
|
| `events` | Optional derived current-view events: `observed` and monotonic `lost` (`observation.reportLostAfterMs`); unsupported host façades reject this option |
|
|
248
248
|
| `plan` | Host-owned native/residual planning diagnostics, or `null` when this host has no planner |
|
|
249
249
|
| `stop()` | End the scan and return a cleanup receipt. `find` already does this. |
|
package/RELEASE.md
CHANGED
|
@@ -82,8 +82,9 @@ Active `4.0.0-rc.*` release-train candidates publish to npm `latest` so a bare `
|
|
|
82
82
|
On release day, set `release_candidate` to the exact candidate required by the
|
|
83
83
|
release plan. RC2, RC3, RC4, `4.0.0-rc.4.1`, and RC5 are already immutable
|
|
84
84
|
once tagged. Stable `4.0.0` through `4.0.20` are immutable. The unpublished
|
|
85
|
-
`v4.0.21` tag is also immutable after its cancelled workflow. `4.0.22
|
|
86
|
-
`4.0.23`
|
|
85
|
+
`v4.0.21` tag is also immutable after its cancelled workflow. `4.0.22`,
|
|
86
|
+
`4.0.23`, `4.0.24`, and `4.0.25` are immutable tagged history. This branch
|
|
87
|
+
prepares `4.0.26`.
|
|
87
88
|
|
|
88
89
|
```sh
|
|
89
90
|
release_candidate=4.0.0-rc.N
|
|
@@ -111,6 +112,22 @@ The first stable tag `v4.0.0` is immutable published history. Do not recreate or
|
|
|
111
112
|
git tag -a v4.0.0 -m "v4.0.0"
|
|
112
113
|
```
|
|
113
114
|
|
|
115
|
+
## Releasing 4.0.26
|
|
116
|
+
|
|
117
|
+
Release `v4.0.26` only from the exact current `main` commit after its canonical
|
|
118
|
+
CI succeeds. Verify `package.json` is `4.0.26`, the worktree is clean, and
|
|
119
|
+
release-note extraction finds `## [4.0.26]`. Push a new annotated `v4.0.26`
|
|
120
|
+
tag; never move the immutable `v4.0.25` tag. Follow the required local validation,
|
|
121
|
+
publish workflow, and registry verification below.
|
|
122
|
+
|
|
123
|
+
## Releasing 4.0.25
|
|
124
|
+
|
|
125
|
+
Release `v4.0.25` only from the exact current `main` commit after its canonical
|
|
126
|
+
CI succeeds. Verify `package.json` is `4.0.25`, the worktree is clean, and
|
|
127
|
+
release-note extraction finds `## [4.0.25]`. Push a new annotated `v4.0.25`
|
|
128
|
+
tag; never move the immutable `v4.0.24` tag. Follow the required local validation,
|
|
129
|
+
publish workflow, and registry verification below.
|
|
130
|
+
|
|
114
131
|
## Releasing 4.0.24
|
|
115
132
|
|
|
116
133
|
Release `v4.0.24` only from the exact current `main` commit after its canonical
|
|
@@ -491,7 +508,7 @@ a green publish job and a package a consumer can actually install are not the
|
|
|
491
508
|
same claim.
|
|
492
509
|
|
|
493
510
|
```sh
|
|
494
|
-
version=4.0.
|
|
511
|
+
version=4.0.26
|
|
495
512
|
|
|
496
513
|
npm view "unified-ble-manager@$version" version
|
|
497
514
|
npm view unified-ble-manager dist-tags --json
|
package/SBOM.cdx.json
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
"metadata": {
|
|
7
7
|
"component": {
|
|
8
8
|
"type": "library",
|
|
9
|
-
"bom-ref": "pkg:npm/unified-ble-manager@4.0.
|
|
9
|
+
"bom-ref": "pkg:npm/unified-ble-manager@4.0.26",
|
|
10
10
|
"name": "unified-ble-manager",
|
|
11
|
-
"version": "4.0.
|
|
11
|
+
"version": "4.0.26",
|
|
12
12
|
"licenses": [
|
|
13
13
|
{
|
|
14
14
|
"expression": "Apache-2.0"
|
|
15
15
|
}
|
|
16
16
|
],
|
|
17
|
-
"purl": "pkg:npm/unified-ble-manager@4.0.
|
|
17
|
+
"purl": "pkg:npm/unified-ble-manager@4.0.26"
|
|
18
18
|
},
|
|
19
19
|
"properties": [
|
|
20
20
|
{
|
|
@@ -537,7 +537,7 @@
|
|
|
537
537
|
"dependsOn": []
|
|
538
538
|
},
|
|
539
539
|
{
|
|
540
|
-
"ref": "pkg:npm/unified-ble-manager@4.0.
|
|
540
|
+
"ref": "pkg:npm/unified-ble-manager@4.0.26",
|
|
541
541
|
"dependsOn": [
|
|
542
542
|
"pkg:npm/%40babel/runtime@7.29.7",
|
|
543
543
|
"pkg:npm/node-addon-api@8.9.0",
|
package/android/build.gradle
CHANGED
|
@@ -89,6 +89,9 @@ android {
|
|
|
89
89
|
kotlinOptions {
|
|
90
90
|
jvmTarget = "17"
|
|
91
91
|
}
|
|
92
|
+
testOptions {
|
|
93
|
+
unitTests.returnDefaultValues = true
|
|
94
|
+
}
|
|
92
95
|
externalNativeBuild {
|
|
93
96
|
cmake {
|
|
94
97
|
path file("src/main/jni/CMakeLists.txt")
|
|
@@ -105,6 +108,7 @@ dependencies {
|
|
|
105
108
|
implementation "com.facebook.react:react-android"
|
|
106
109
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
107
110
|
testImplementation "junit:junit:4.13.2"
|
|
111
|
+
testImplementation "org.mockito:mockito-core:5.14.2"
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
react {
|
|
@@ -30,6 +30,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
30
30
|
private val establishedConnections = ConcurrentHashMap<String, ProtocolWireRecord>()
|
|
31
31
|
private val activeDatabases = ConcurrentHashMap<String, ProtocolWireRecord>()
|
|
32
32
|
private val activeSubscriptions = ConcurrentHashMap<String, SubscriptionRoute>()
|
|
33
|
+
private val pendingSubscriptions = ConcurrentHashMap<String, SubscriptionRoute>()
|
|
33
34
|
private val radioOperationIds = ConcurrentHashMap<String, Long>()
|
|
34
35
|
private val activeScanCommand = AtomicReference<ProtocolWireRecord?>(null)
|
|
35
36
|
private val cancelledScanCommands = ConcurrentHashMap<String, ProtocolWireRecord>()
|
|
@@ -78,11 +79,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
78
79
|
activeDatabases.remove(deviceKey)
|
|
79
80
|
failPendingCommandsForDevice(deviceKey, "Android GATT link was lost")
|
|
80
81
|
if (established != null) {
|
|
81
|
-
|
|
82
|
-
if (entry.value.endpoint.deviceId.equals(deviceId, ignoreCase = true)) {
|
|
83
|
-
activeSubscriptions.remove(entry.key, entry.value)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
82
|
+
clearSubscriptionRoutesForDevice(deviceId)
|
|
86
83
|
emitConnectionLost(established, status)
|
|
87
84
|
}
|
|
88
85
|
}
|
|
@@ -134,7 +131,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
134
131
|
}
|
|
135
132
|
}
|
|
136
133
|
radio.onProtocolNotification = { deviceId, characteristic, value ->
|
|
137
|
-
activeSubscriptions.values
|
|
134
|
+
(pendingSubscriptions.values.asSequence() + activeSubscriptions.values.asSequence())
|
|
138
135
|
.filter { route -> route.matches(deviceId, characteristic, radio) }
|
|
139
136
|
.forEach { route ->
|
|
140
137
|
UnifiedBleProtocolJsiBinding.emitNotification(nativeHandle, route.subscriptionId, value)
|
|
@@ -166,6 +163,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
166
163
|
}
|
|
167
164
|
establishedConnections.clear()
|
|
168
165
|
activeDatabases.clear()
|
|
166
|
+
pendingSubscriptions.clear()
|
|
169
167
|
activeSubscriptions.clear()
|
|
170
168
|
}
|
|
171
169
|
|
|
@@ -272,6 +270,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
272
270
|
pendingConnects.clear()
|
|
273
271
|
establishedConnections.clear()
|
|
274
272
|
activeDatabases.clear()
|
|
273
|
+
pendingSubscriptions.clear()
|
|
275
274
|
activeSubscriptions.clear()
|
|
276
275
|
activeScanCommand.set(null)
|
|
277
276
|
}
|
|
@@ -601,6 +600,14 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
601
600
|
return
|
|
602
601
|
}
|
|
603
602
|
val endpoint = characteristicEndpoint(command.requiredRecord(4))
|
|
603
|
+
val route = SubscriptionRoute(
|
|
604
|
+
subscriptionId,
|
|
605
|
+
endpoint,
|
|
606
|
+
command.optionalString(21)
|
|
607
|
+
)
|
|
608
|
+
if (enable) {
|
|
609
|
+
pendingSubscriptions[subscriptionId] = route
|
|
610
|
+
}
|
|
604
611
|
val radioOperationId = radio.setNotifyExact(
|
|
605
612
|
endpoint.deviceId,
|
|
606
613
|
endpoint.serviceUuid,
|
|
@@ -613,6 +620,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
613
620
|
result.fold(
|
|
614
621
|
onSuccess = {
|
|
615
622
|
if (!isPending(command)) {
|
|
623
|
+
pendingSubscriptions.remove(subscriptionId, route)
|
|
616
624
|
if (enable) {
|
|
617
625
|
radio.setNotifyExact(
|
|
618
626
|
endpoint.deviceId,
|
|
@@ -634,17 +642,16 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
634
642
|
return@fold
|
|
635
643
|
}
|
|
636
644
|
if (enable) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
endpoint,
|
|
640
|
-
command.optionalString(21)
|
|
641
|
-
)
|
|
645
|
+
pendingSubscriptions.remove(subscriptionId, route)
|
|
646
|
+
activeSubscriptions[subscriptionId] = route
|
|
642
647
|
} else {
|
|
648
|
+
pendingSubscriptions.remove(subscriptionId)
|
|
643
649
|
activeSubscriptions.remove(subscriptionId)
|
|
644
650
|
}
|
|
645
651
|
emitSuccess(command, if (enable) "subscribed" else "unsubscribed")
|
|
646
652
|
},
|
|
647
653
|
onFailure = { error ->
|
|
654
|
+
pendingSubscriptions.remove(subscriptionId, route)
|
|
648
655
|
emitGattOperationFailure(command, "subscriptionFailed", error, "Android CCCD operation failed")
|
|
649
656
|
}
|
|
650
657
|
)
|
|
@@ -665,6 +672,7 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
665
672
|
pendingConnects.clear()
|
|
666
673
|
establishedConnections.clear()
|
|
667
674
|
activeDatabases.clear()
|
|
675
|
+
pendingSubscriptions.clear()
|
|
668
676
|
activeSubscriptions.clear()
|
|
669
677
|
if (result.isSuccessful) {
|
|
670
678
|
activeScanCommand.set(null)
|
|
@@ -737,7 +745,9 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
737
745
|
}
|
|
738
746
|
if (commandKind == "subscribe") {
|
|
739
747
|
val endpoint = characteristicEndpoint(command.requiredRecord(4))
|
|
740
|
-
|
|
748
|
+
val subscriptionId = command.requiredString(7)
|
|
749
|
+
pendingSubscriptions.remove(subscriptionId)
|
|
750
|
+
activeSubscriptions.remove(subscriptionId)
|
|
741
751
|
radio.setNotifyExact(
|
|
742
752
|
endpoint.deviceId,
|
|
743
753
|
endpoint.serviceUuid,
|
|
@@ -1137,6 +1147,11 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
1137
1147
|
}
|
|
1138
1148
|
|
|
1139
1149
|
private fun clearSubscriptionRoutesForDevice(deviceId: String) {
|
|
1150
|
+
pendingSubscriptions.entries.forEach { entry ->
|
|
1151
|
+
if (entry.value.endpoint.deviceId.equals(deviceId, ignoreCase = true)) {
|
|
1152
|
+
pendingSubscriptions.remove(entry.key, entry.value)
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1140
1155
|
activeSubscriptions.entries.forEach { entry ->
|
|
1141
1156
|
if (entry.value.endpoint.deviceId.equals(deviceId, ignoreCase = true)) {
|
|
1142
1157
|
activeSubscriptions.remove(entry.key, entry.value)
|