unified-ble-manager 4.0.4 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (653) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/MIGRATION_4.0.md +1 -1
  3. package/README.md +1 -1
  4. package/RELEASE.md +24 -16
  5. package/SBOM.cdx.json +29 -5
  6. package/THIRD_PARTY_LICENSES.json +9 -2
  7. package/android/src/main/java/com/sfourdrinier/unifiedblemanager/expo/UnifiedBleExpoRuntimeModule.java +18 -2
  8. package/android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcher.kt +15 -8
  9. package/android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/generated/NativeProtocolV2Schema.kt +2 -1
  10. package/android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidGattRadio.kt +30 -3
  11. package/android/src/main/jni/UnifiedBleProtocolJsiBinding.cpp +66 -0
  12. package/android/src/test/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidFindingsTest.kt +17 -0
  13. package/docs/ADR/2026-07-4.0-backend-contract.md +16 -4
  14. package/docs/BONDING.md +42 -7
  15. package/docs/ELECTRON.md +1 -1
  16. package/docs/EXPO_PLUGIN.md +2 -2
  17. package/docs/GAPS.4.0.md +1 -1
  18. package/docs/GETTING_STARTED.md +4 -4
  19. package/docs/NODE.md +2 -2
  20. package/docs/PLATFORMS.md +1 -1
  21. package/docs/UNIFIED_SEMANTICS.md +40 -5
  22. package/docs/WEB.md +1 -1
  23. package/docs/generated/PLATFORM_SUPPORT.md +1 -1
  24. package/ios/Generated/NativeProtocolV2Schema.swift +2 -1
  25. package/lib/commonjs/backend-contract/advertisement.js +19 -0
  26. package/lib/commonjs/backend-contract/advertisement.js.map +1 -1
  27. package/lib/commonjs/backend-contract/backend.js +6 -0
  28. package/lib/commonjs/backend-contract/backend.js.map +1 -1
  29. package/lib/commonjs/backend-contract/capabilities.js +7 -0
  30. package/lib/commonjs/backend-contract/capabilities.js.map +1 -1
  31. package/lib/commonjs/backend-contract/ipc.js +7 -0
  32. package/lib/commonjs/backend-contract/ipc.js.map +1 -1
  33. package/lib/commonjs/backend-contract/primitives.js +14 -0
  34. package/lib/commonjs/backend-contract/primitives.js.map +1 -1
  35. package/lib/commonjs/backend-contract/scan-planning.js +18 -2
  36. package/lib/commonjs/backend-contract/scan-planning.js.map +1 -1
  37. package/lib/commonjs/backend-contract/scan-query.js +18 -3
  38. package/lib/commonjs/backend-contract/scan-query.js.map +1 -1
  39. package/lib/commonjs/backends/bluez/bluez-backend-handles.js +62 -30
  40. package/lib/commonjs/backends/bluez/bluez-backend-handles.js.map +1 -1
  41. package/lib/commonjs/backends/bluez/bluez-backend-provider.js +1 -1
  42. package/lib/commonjs/backends/bluez/bluez-backend-provider.js.map +1 -1
  43. package/lib/commonjs/backends/bluez/bluez-backend-runtime.js +33 -1
  44. package/lib/commonjs/backends/bluez/bluez-backend-runtime.js.map +1 -1
  45. package/lib/commonjs/backends/bluez/bluez-backend.js +9 -1
  46. package/lib/commonjs/backends/bluez/bluez-backend.js.map +1 -1
  47. package/lib/commonjs/backends/bluez/bluez-connection-capabilities.js +110 -0
  48. package/lib/commonjs/backends/bluez/bluez-connection-capabilities.js.map +1 -0
  49. package/lib/commonjs/backends/bluez/bluez-connection-runtime.js +164 -2
  50. package/lib/commonjs/backends/bluez/bluez-connection-runtime.js.map +1 -1
  51. package/lib/commonjs/backends/bluez/bluez-dbus-next-boundary.js +200 -3
  52. package/lib/commonjs/backends/bluez/bluez-dbus-next-boundary.js.map +1 -1
  53. package/lib/commonjs/backends/bluez/bluez-operation-dispatcher.js +30 -20
  54. package/lib/commonjs/backends/bluez/bluez-operation-dispatcher.js.map +1 -1
  55. package/lib/commonjs/backends/bluez/bluez-property-waiters.js +55 -1
  56. package/lib/commonjs/backends/bluez/bluez-property-waiters.js.map +1 -1
  57. package/lib/commonjs/backends/bluez/bluez-runtime-models.js +7 -6
  58. package/lib/commonjs/backends/bluez/bluez-runtime-models.js.map +1 -1
  59. package/lib/commonjs/backends/bluez/bluez-scan-planner.js +1 -1
  60. package/lib/commonjs/backends/bluez/bluez-scan-planner.js.map +1 -1
  61. package/lib/commonjs/backends/bluez/bluez-security.js +69 -2
  62. package/lib/commonjs/backends/bluez/bluez-security.js.map +1 -1
  63. package/lib/commonjs/backends/corebluetooth/corebluetooth-adapter-loss-cleanup.js +4 -4
  64. package/lib/commonjs/backends/corebluetooth/corebluetooth-adapter-loss-cleanup.js.map +1 -1
  65. package/lib/commonjs/backends/corebluetooth/corebluetooth-backend.js +95 -56
  66. package/lib/commonjs/backends/corebluetooth/corebluetooth-backend.js.map +1 -1
  67. package/lib/commonjs/backends/corebluetooth/corebluetooth-cleanup.js +10 -2
  68. package/lib/commonjs/backends/corebluetooth/corebluetooth-cleanup.js.map +1 -1
  69. package/lib/commonjs/backends/corebluetooth/corebluetooth-connection-controls.js +65 -53
  70. package/lib/commonjs/backends/corebluetooth/corebluetooth-connection-controls.js.map +1 -1
  71. package/lib/commonjs/backends/corebluetooth/corebluetooth-gatt-operations.js +48 -48
  72. package/lib/commonjs/backends/corebluetooth/corebluetooth-gatt-operations.js.map +1 -1
  73. package/lib/commonjs/backends/corebluetooth/corebluetooth-handles.js +12 -12
  74. package/lib/commonjs/backends/corebluetooth/corebluetooth-handles.js.map +1 -1
  75. package/lib/commonjs/backends/corebluetooth/corebluetooth-late-connect-cleanup.js +1 -1
  76. package/lib/commonjs/backends/corebluetooth/corebluetooth-late-connect-cleanup.js.map +1 -1
  77. package/lib/commonjs/backends/corebluetooth/corebluetooth-provider.js +1 -1
  78. package/lib/commonjs/backends/corebluetooth/corebluetooth-provider.js.map +1 -1
  79. package/lib/commonjs/backends/corebluetooth/corebluetooth-runtime-capabilities.js +3 -3
  80. package/lib/commonjs/backends/corebluetooth/corebluetooth-runtime-capabilities.js.map +1 -1
  81. package/lib/commonjs/backends/reactnative/react-native-android-provider.js +26 -2
  82. package/lib/commonjs/backends/reactnative/react-native-android-provider.js.map +1 -1
  83. package/lib/commonjs/backends/reactnative/react-native-android-security.js +15 -1
  84. package/lib/commonjs/backends/reactnative/react-native-android-security.js.map +1 -1
  85. package/lib/commonjs/backends/reactnative/react-native-restoration.js +8 -0
  86. package/lib/commonjs/backends/reactnative/react-native-restoration.js.map +1 -1
  87. package/lib/commonjs/backends/reactnative/react-native-scan-planner.js +2 -1
  88. package/lib/commonjs/backends/reactnative/react-native-scan-planner.js.map +1 -1
  89. package/lib/commonjs/backends/scan-planning/service-uuid-scan-planner.js +36 -4
  90. package/lib/commonjs/backends/scan-planning/service-uuid-scan-planner.js.map +1 -1
  91. package/lib/commonjs/backends/winrt/winrt-backend-helpers.js +9 -0
  92. package/lib/commonjs/backends/winrt/winrt-backend-helpers.js.map +1 -1
  93. package/lib/commonjs/backends/winrt/winrt-security.js +7 -0
  94. package/lib/commonjs/backends/winrt/winrt-security.js.map +1 -1
  95. package/lib/commonjs/cli-json.js +7 -0
  96. package/lib/commonjs/cli-json.js.map +1 -1
  97. package/lib/commonjs/core/core-characteristic-operations.js +13 -0
  98. package/lib/commonjs/core/core-characteristic-operations.js.map +1 -1
  99. package/lib/commonjs/core/core-gatt-handles.js +10 -0
  100. package/lib/commonjs/core/core-gatt-handles.js.map +1 -1
  101. package/lib/commonjs/core/operation-coordinator.js +10 -1
  102. package/lib/commonjs/core/operation-coordinator.js.map +1 -1
  103. package/lib/commonjs/core/unified-ble-core.js +21 -0
  104. package/lib/commonjs/core/unified-ble-core.js.map +1 -1
  105. package/lib/commonjs/diagnostics/trace-format.js +12 -0
  106. package/lib/commonjs/diagnostics/trace-format.js.map +1 -1
  107. package/lib/commonjs/electron/connection-event-stream-registry.js +8 -0
  108. package/lib/commonjs/electron/connection-event-stream-registry.js.map +1 -1
  109. package/lib/commonjs/electron/main-binding.js +16 -0
  110. package/lib/commonjs/electron/main-binding.js.map +1 -1
  111. package/lib/commonjs/electron/main-router.js +11 -0
  112. package/lib/commonjs/electron/main-router.js.map +1 -1
  113. package/lib/commonjs/electron/renderer-stream-registry.js +8 -0
  114. package/lib/commonjs/electron/renderer-stream-registry.js.map +1 -1
  115. package/lib/commonjs/electron/renderer.js +11 -0
  116. package/lib/commonjs/electron/renderer.js.map +1 -1
  117. package/lib/commonjs/expo.js +37 -1
  118. package/lib/commonjs/expo.js.map +1 -1
  119. package/lib/commonjs/implementation-version.js +1 -1
  120. package/lib/commonjs/index.js.map +1 -1
  121. package/lib/commonjs/ipc/manager.js +86 -13
  122. package/lib/commonjs/ipc/manager.js.map +1 -1
  123. package/lib/commonjs/ipc/public-manager.js +229 -111
  124. package/lib/commonjs/ipc/public-manager.js.map +1 -1
  125. package/lib/commonjs/native-protocol/generated/native-protocol-v2-schema.js +2 -2
  126. package/lib/commonjs/native-protocol/generated/native-protocol-v2-schema.js.map +1 -1
  127. package/lib/commonjs/native-protocol/rn-android-boundary.js +32 -3
  128. package/lib/commonjs/native-protocol/rn-android-boundary.js.map +1 -1
  129. package/lib/commonjs/native-protocol/rn-apple-boundary.js +7 -1
  130. package/lib/commonjs/native-protocol/rn-apple-boundary.js.map +1 -1
  131. package/lib/commonjs/node-corebluetooth.js +15 -4
  132. package/lib/commonjs/node-corebluetooth.js.map +1 -1
  133. package/lib/commonjs/node-host-manager.js +14 -6
  134. package/lib/commonjs/node-host-manager.js.map +1 -1
  135. package/lib/commonjs/public/ble-manager.js +203 -63
  136. package/lib/commonjs/public/ble-manager.js.map +1 -1
  137. package/lib/commonjs/public/cleanup.js +154 -0
  138. package/lib/commonjs/public/cleanup.js.map +1 -0
  139. package/lib/commonjs/public/connection-supervisor.js +39 -3
  140. package/lib/commonjs/public/connection-supervisor.js.map +1 -1
  141. package/lib/commonjs/public/diagnostics.js +21 -0
  142. package/lib/commonjs/public/diagnostics.js.map +1 -1
  143. package/lib/commonjs/public/error-bridge.js +25 -9
  144. package/lib/commonjs/public/error-bridge.js.map +1 -1
  145. package/lib/commonjs/public/errors.js +2 -28
  146. package/lib/commonjs/public/errors.js.map +1 -1
  147. package/lib/commonjs/public/gatt.js +53 -77
  148. package/lib/commonjs/public/gatt.js.map +1 -1
  149. package/lib/commonjs/public/host-identity.js.map +1 -1
  150. package/lib/commonjs/public/index.js.map +1 -1
  151. package/lib/commonjs/public/scan-query.js +70 -3
  152. package/lib/commonjs/public/scan-query.js.map +1 -1
  153. package/lib/commonjs/public/scan-state-budget.js +11 -0
  154. package/lib/commonjs/public/scan-state-budget.js.map +1 -1
  155. package/lib/commonjs/public/security.js +4 -0
  156. package/lib/commonjs/public/security.js.map +1 -1
  157. package/lib/commonjs/public/stream-capacity.js +25 -0
  158. package/lib/commonjs/public/stream-capacity.js.map +1 -0
  159. package/lib/commonjs/public/stream-presets.js +9 -2
  160. package/lib/commonjs/public/stream-presets.js.map +1 -1
  161. package/lib/commonjs/public/streams.js +214 -0
  162. package/lib/commonjs/public/streams.js.map +1 -0
  163. package/lib/commonjs/react.js +63 -33
  164. package/lib/commonjs/react.js.map +1 -1
  165. package/lib/commonjs/tck/first-party/bluez-tck-registration.js +14 -2
  166. package/lib/commonjs/tck/first-party/bluez-tck-registration.js.map +1 -1
  167. package/lib/commonjs/testing/deterministic/deterministic-scan-planner.js +1 -1
  168. package/lib/commonjs/testing/deterministic/deterministic-scan-planner.js.map +1 -1
  169. package/lib/commonjs/testing/deterministic/deterministic-security.js +8 -0
  170. package/lib/commonjs/testing/deterministic/deterministic-security.js.map +1 -1
  171. package/lib/module/backend-contract/advertisement.js +19 -0
  172. package/lib/module/backend-contract/advertisement.js.map +1 -1
  173. package/lib/module/backend-contract/backend.js +6 -0
  174. package/lib/module/backend-contract/backend.js.map +1 -1
  175. package/lib/module/backend-contract/capabilities.js +7 -0
  176. package/lib/module/backend-contract/capabilities.js.map +1 -1
  177. package/lib/module/backend-contract/ipc.js +7 -0
  178. package/lib/module/backend-contract/ipc.js.map +1 -1
  179. package/lib/module/backend-contract/primitives.js +13 -0
  180. package/lib/module/backend-contract/primitives.js.map +1 -1
  181. package/lib/module/backend-contract/scan-planning.js +18 -2
  182. package/lib/module/backend-contract/scan-planning.js.map +1 -1
  183. package/lib/module/backend-contract/scan-query.js +19 -4
  184. package/lib/module/backend-contract/scan-query.js.map +1 -1
  185. package/lib/module/backends/bluez/bluez-backend-handles.js +62 -30
  186. package/lib/module/backends/bluez/bluez-backend-handles.js.map +1 -1
  187. package/lib/module/backends/bluez/bluez-backend-provider.js +1 -1
  188. package/lib/module/backends/bluez/bluez-backend-provider.js.map +1 -1
  189. package/lib/module/backends/bluez/bluez-backend-runtime.js +34 -2
  190. package/lib/module/backends/bluez/bluez-backend-runtime.js.map +1 -1
  191. package/lib/module/backends/bluez/bluez-backend.js +9 -1
  192. package/lib/module/backends/bluez/bluez-backend.js.map +1 -1
  193. package/lib/module/backends/bluez/bluez-connection-capabilities.js +105 -0
  194. package/lib/module/backends/bluez/bluez-connection-capabilities.js.map +1 -0
  195. package/lib/module/backends/bluez/bluez-connection-runtime.js +167 -5
  196. package/lib/module/backends/bluez/bluez-connection-runtime.js.map +1 -1
  197. package/lib/module/backends/bluez/bluez-dbus-next-boundary.js +200 -3
  198. package/lib/module/backends/bluez/bluez-dbus-next-boundary.js.map +1 -1
  199. package/lib/module/backends/bluez/bluez-operation-dispatcher.js +29 -20
  200. package/lib/module/backends/bluez/bluez-operation-dispatcher.js.map +1 -1
  201. package/lib/module/backends/bluez/bluez-property-waiters.js +54 -1
  202. package/lib/module/backends/bluez/bluez-property-waiters.js.map +1 -1
  203. package/lib/module/backends/bluez/bluez-runtime-models.js +7 -6
  204. package/lib/module/backends/bluez/bluez-runtime-models.js.map +1 -1
  205. package/lib/module/backends/bluez/bluez-scan-planner.js +1 -1
  206. package/lib/module/backends/bluez/bluez-scan-planner.js.map +1 -1
  207. package/lib/module/backends/bluez/bluez-security.js +69 -2
  208. package/lib/module/backends/bluez/bluez-security.js.map +1 -1
  209. package/lib/module/backends/corebluetooth/corebluetooth-adapter-loss-cleanup.js +4 -4
  210. package/lib/module/backends/corebluetooth/corebluetooth-adapter-loss-cleanup.js.map +1 -1
  211. package/lib/module/backends/corebluetooth/corebluetooth-backend.js +96 -57
  212. package/lib/module/backends/corebluetooth/corebluetooth-backend.js.map +1 -1
  213. package/lib/module/backends/corebluetooth/corebluetooth-cleanup.js +11 -2
  214. package/lib/module/backends/corebluetooth/corebluetooth-cleanup.js.map +1 -1
  215. package/lib/module/backends/corebluetooth/corebluetooth-connection-controls.js +66 -53
  216. package/lib/module/backends/corebluetooth/corebluetooth-connection-controls.js.map +1 -1
  217. package/lib/module/backends/corebluetooth/corebluetooth-gatt-operations.js +48 -48
  218. package/lib/module/backends/corebluetooth/corebluetooth-gatt-operations.js.map +1 -1
  219. package/lib/module/backends/corebluetooth/corebluetooth-handles.js +12 -12
  220. package/lib/module/backends/corebluetooth/corebluetooth-handles.js.map +1 -1
  221. package/lib/module/backends/corebluetooth/corebluetooth-late-connect-cleanup.js +1 -1
  222. package/lib/module/backends/corebluetooth/corebluetooth-late-connect-cleanup.js.map +1 -1
  223. package/lib/module/backends/corebluetooth/corebluetooth-provider.js +1 -1
  224. package/lib/module/backends/corebluetooth/corebluetooth-provider.js.map +1 -1
  225. package/lib/module/backends/corebluetooth/corebluetooth-runtime-capabilities.js +3 -3
  226. package/lib/module/backends/corebluetooth/corebluetooth-runtime-capabilities.js.map +1 -1
  227. package/lib/module/backends/reactnative/react-native-android-provider.js +26 -2
  228. package/lib/module/backends/reactnative/react-native-android-provider.js.map +1 -1
  229. package/lib/module/backends/reactnative/react-native-android-security.js +15 -1
  230. package/lib/module/backends/reactnative/react-native-android-security.js.map +1 -1
  231. package/lib/module/backends/reactnative/react-native-restoration.js +8 -0
  232. package/lib/module/backends/reactnative/react-native-restoration.js.map +1 -1
  233. package/lib/module/backends/reactnative/react-native-scan-planner.js +2 -1
  234. package/lib/module/backends/reactnative/react-native-scan-planner.js.map +1 -1
  235. package/lib/module/backends/scan-planning/service-uuid-scan-planner.js +36 -4
  236. package/lib/module/backends/scan-planning/service-uuid-scan-planner.js.map +1 -1
  237. package/lib/module/backends/winrt/winrt-backend-helpers.js +10 -0
  238. package/lib/module/backends/winrt/winrt-backend-helpers.js.map +1 -1
  239. package/lib/module/backends/winrt/winrt-security.js +7 -0
  240. package/lib/module/backends/winrt/winrt-security.js.map +1 -1
  241. package/lib/module/cli-json.js +7 -0
  242. package/lib/module/cli-json.js.map +1 -1
  243. package/lib/module/core/core-characteristic-operations.js +13 -0
  244. package/lib/module/core/core-characteristic-operations.js.map +1 -1
  245. package/lib/module/core/core-gatt-handles.js +10 -0
  246. package/lib/module/core/core-gatt-handles.js.map +1 -1
  247. package/lib/module/core/operation-coordinator.js +10 -1
  248. package/lib/module/core/operation-coordinator.js.map +1 -1
  249. package/lib/module/core/unified-ble-core.js +21 -0
  250. package/lib/module/core/unified-ble-core.js.map +1 -1
  251. package/lib/module/diagnostics/trace-format.js +12 -0
  252. package/lib/module/diagnostics/trace-format.js.map +1 -1
  253. package/lib/module/electron/connection-event-stream-registry.js +8 -0
  254. package/lib/module/electron/connection-event-stream-registry.js.map +1 -1
  255. package/lib/module/electron/main-binding.js +16 -0
  256. package/lib/module/electron/main-binding.js.map +1 -1
  257. package/lib/module/electron/main-router.js +11 -0
  258. package/lib/module/electron/main-router.js.map +1 -1
  259. package/lib/module/electron/renderer-stream-registry.js +8 -0
  260. package/lib/module/electron/renderer-stream-registry.js.map +1 -1
  261. package/lib/module/electron/renderer.js +11 -0
  262. package/lib/module/electron/renderer.js.map +1 -1
  263. package/lib/module/expo.js +37 -1
  264. package/lib/module/expo.js.map +1 -1
  265. package/lib/module/implementation-version.js +1 -1
  266. package/lib/module/index.js.map +1 -1
  267. package/lib/module/ipc/manager.js +86 -13
  268. package/lib/module/ipc/manager.js.map +1 -1
  269. package/lib/module/ipc/public-manager.js +232 -115
  270. package/lib/module/ipc/public-manager.js.map +1 -1
  271. package/lib/module/native-protocol/generated/native-protocol-v2-schema.js +2 -2
  272. package/lib/module/native-protocol/generated/native-protocol-v2-schema.js.map +1 -1
  273. package/lib/module/native-protocol/rn-android-boundary.js +32 -3
  274. package/lib/module/native-protocol/rn-android-boundary.js.map +1 -1
  275. package/lib/module/native-protocol/rn-apple-boundary.js +7 -1
  276. package/lib/module/native-protocol/rn-apple-boundary.js.map +1 -1
  277. package/lib/module/node-corebluetooth.js +15 -4
  278. package/lib/module/node-corebluetooth.js.map +1 -1
  279. package/lib/module/node-host-manager.js +14 -6
  280. package/lib/module/node-host-manager.js.map +1 -1
  281. package/lib/module/public/ble-manager.js +204 -65
  282. package/lib/module/public/ble-manager.js.map +1 -1
  283. package/lib/module/public/cleanup.js +150 -0
  284. package/lib/module/public/cleanup.js.map +1 -0
  285. package/lib/module/public/connection-supervisor.js +39 -3
  286. package/lib/module/public/connection-supervisor.js.map +1 -1
  287. package/lib/module/public/diagnostics.js +20 -0
  288. package/lib/module/public/diagnostics.js.map +1 -1
  289. package/lib/module/public/error-bridge.js +25 -9
  290. package/lib/module/public/error-bridge.js.map +1 -1
  291. package/lib/module/public/errors.js +2 -27
  292. package/lib/module/public/errors.js.map +1 -1
  293. package/lib/module/public/gatt.js +54 -78
  294. package/lib/module/public/gatt.js.map +1 -1
  295. package/lib/module/public/host-identity.js.map +1 -1
  296. package/lib/module/public/index.js.map +1 -1
  297. package/lib/module/public/scan-query.js +70 -4
  298. package/lib/module/public/scan-query.js.map +1 -1
  299. package/lib/module/public/scan-state-budget.js +11 -0
  300. package/lib/module/public/scan-state-budget.js.map +1 -1
  301. package/lib/module/public/security.js +4 -0
  302. package/lib/module/public/security.js.map +1 -1
  303. package/lib/module/public/stream-capacity.js +21 -0
  304. package/lib/module/public/stream-capacity.js.map +1 -0
  305. package/lib/module/public/stream-presets.js +9 -2
  306. package/lib/module/public/stream-presets.js.map +1 -1
  307. package/lib/module/public/streams.js +210 -0
  308. package/lib/module/public/streams.js.map +1 -0
  309. package/lib/module/react.js +63 -33
  310. package/lib/module/react.js.map +1 -1
  311. package/lib/module/tck/first-party/bluez-tck-registration.js +14 -2
  312. package/lib/module/tck/first-party/bluez-tck-registration.js.map +1 -1
  313. package/lib/module/testing/deterministic/deterministic-scan-planner.js +1 -1
  314. package/lib/module/testing/deterministic/deterministic-scan-planner.js.map +1 -1
  315. package/lib/module/testing/deterministic/deterministic-security.js +8 -0
  316. package/lib/module/testing/deterministic/deterministic-security.js.map +1 -1
  317. package/lib/typescript/commonjs/src/backend-contract/advertisement.d.ts +9 -0
  318. package/lib/typescript/commonjs/src/backend-contract/advertisement.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/src/backend-contract/backend.d.ts +15 -0
  320. package/lib/typescript/commonjs/src/backend-contract/backend.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/src/backend-contract/capabilities.d.ts +7 -0
  322. package/lib/typescript/commonjs/src/backend-contract/capabilities.d.ts.map +1 -1
  323. package/lib/typescript/commonjs/src/backend-contract/ipc.d.ts +7 -0
  324. package/lib/typescript/commonjs/src/backend-contract/ipc.d.ts.map +1 -1
  325. package/lib/typescript/commonjs/src/backend-contract/primitives.d.ts +8 -0
  326. package/lib/typescript/commonjs/src/backend-contract/primitives.d.ts.map +1 -1
  327. package/lib/typescript/commonjs/src/backend-contract/scan-planning.d.ts +2 -2
  328. package/lib/typescript/commonjs/src/backend-contract/scan-planning.d.ts.map +1 -1
  329. package/lib/typescript/commonjs/src/backend-contract/scan-query.d.ts +12 -0
  330. package/lib/typescript/commonjs/src/backend-contract/scan-query.d.ts.map +1 -1
  331. package/lib/typescript/commonjs/src/backend-contract/security.d.ts +7 -0
  332. package/lib/typescript/commonjs/src/backend-contract/security.d.ts.map +1 -1
  333. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-handles.d.ts +1 -1
  334. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-handles.d.ts.map +1 -1
  335. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
  336. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-runtime.d.ts +11 -2
  337. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-runtime.d.ts.map +1 -1
  338. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend.d.ts.map +1 -1
  339. package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-capabilities.d.ts +13 -0
  340. package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-capabilities.d.ts.map +1 -0
  341. package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-runtime.d.ts +1 -1
  342. package/lib/typescript/commonjs/src/backends/bluez/bluez-connection-runtime.d.ts.map +1 -1
  343. package/lib/typescript/commonjs/src/backends/bluez/bluez-dbus-contract.d.ts +3 -1
  344. package/lib/typescript/commonjs/src/backends/bluez/bluez-dbus-contract.d.ts.map +1 -1
  345. package/lib/typescript/commonjs/src/backends/bluez/bluez-dbus-next-boundary.d.ts.map +1 -1
  346. package/lib/typescript/commonjs/src/backends/bluez/bluez-operation-dispatcher.d.ts +12 -0
  347. package/lib/typescript/commonjs/src/backends/bluez/bluez-operation-dispatcher.d.ts.map +1 -1
  348. package/lib/typescript/commonjs/src/backends/bluez/bluez-property-waiters.d.ts +12 -0
  349. package/lib/typescript/commonjs/src/backends/bluez/bluez-property-waiters.d.ts.map +1 -1
  350. package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-models.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-types.d.ts +2 -0
  352. package/lib/typescript/commonjs/src/backends/bluez/bluez-runtime-types.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/src/backends/bluez/bluez-scan-planner.d.ts.map +1 -1
  354. package/lib/typescript/commonjs/src/backends/bluez/bluez-security.d.ts +0 -1
  355. package/lib/typescript/commonjs/src/backends/bluez/bluez-security.d.ts.map +1 -1
  356. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-backend.d.ts +9 -0
  357. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-backend.d.ts.map +1 -1
  358. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-boundary.d.ts +17 -1
  359. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-boundary.d.ts.map +1 -1
  360. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-cleanup.d.ts +10 -1
  361. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-cleanup.d.ts.map +1 -1
  362. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-connection-controls.d.ts.map +1 -1
  363. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
  364. package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
  365. package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts.map +1 -1
  366. package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-security.d.ts.map +1 -1
  367. package/lib/typescript/commonjs/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
  368. package/lib/typescript/commonjs/src/backends/reactnative/react-native-restoration.d.ts.map +1 -1
  369. package/lib/typescript/commonjs/src/backends/reactnative/react-native-scan-planner.d.ts.map +1 -1
  370. package/lib/typescript/commonjs/src/backends/scan-planning/service-uuid-scan-planner.d.ts.map +1 -1
  371. package/lib/typescript/commonjs/src/backends/winrt/winrt-backend-helpers.d.ts +9 -0
  372. package/lib/typescript/commonjs/src/backends/winrt/winrt-backend-helpers.d.ts.map +1 -1
  373. package/lib/typescript/commonjs/src/backends/winrt/winrt-provider.d.ts +1 -1
  374. package/lib/typescript/commonjs/src/backends/winrt/winrt-security.d.ts.map +1 -1
  375. package/lib/typescript/commonjs/src/cli-json.d.ts.map +1 -1
  376. package/lib/typescript/commonjs/src/core/core-characteristic-operations.d.ts.map +1 -1
  377. package/lib/typescript/commonjs/src/core/core-gatt-handles.d.ts.map +1 -1
  378. package/lib/typescript/commonjs/src/core/operation-coordinator.d.ts.map +1 -1
  379. package/lib/typescript/commonjs/src/core/unified-ble-core.d.ts +3 -1
  380. package/lib/typescript/commonjs/src/core/unified-ble-core.d.ts.map +1 -1
  381. package/lib/typescript/commonjs/src/diagnostics/trace-format.d.ts +12 -0
  382. package/lib/typescript/commonjs/src/diagnostics/trace-format.d.ts.map +1 -1
  383. package/lib/typescript/commonjs/src/electron/connection-event-stream-registry.d.ts.map +1 -1
  384. package/lib/typescript/commonjs/src/electron/main-binding.d.ts.map +1 -1
  385. package/lib/typescript/commonjs/src/electron/main-router.d.ts.map +1 -1
  386. package/lib/typescript/commonjs/src/electron/renderer-stream-registry.d.ts.map +1 -1
  387. package/lib/typescript/commonjs/src/electron/renderer.d.ts.map +1 -1
  388. package/lib/typescript/commonjs/src/expo.d.ts.map +1 -1
  389. package/lib/typescript/commonjs/src/implementation-version.d.ts +1 -1
  390. package/lib/typescript/commonjs/src/index.d.ts +3 -2
  391. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  392. package/lib/typescript/commonjs/src/ipc/manager.d.ts +5 -2
  393. package/lib/typescript/commonjs/src/ipc/manager.d.ts.map +1 -1
  394. package/lib/typescript/commonjs/src/ipc/public-manager.d.ts +13 -4
  395. package/lib/typescript/commonjs/src/ipc/public-manager.d.ts.map +1 -1
  396. package/lib/typescript/commonjs/src/native-protocol/generated/native-protocol-v2-schema.d.ts +1 -1
  397. package/lib/typescript/commonjs/src/native-protocol/generated/native-protocol-v2-schema.d.ts.map +1 -1
  398. package/lib/typescript/commonjs/src/native-protocol/rn-android-boundary.d.ts +2 -2
  399. package/lib/typescript/commonjs/src/native-protocol/rn-android-boundary.d.ts.map +1 -1
  400. package/lib/typescript/commonjs/src/native-protocol/rn-apple-boundary.d.ts +2 -2
  401. package/lib/typescript/commonjs/src/native-protocol/rn-apple-boundary.d.ts.map +1 -1
  402. package/lib/typescript/commonjs/src/node-corebluetooth.d.ts.map +1 -1
  403. package/lib/typescript/commonjs/src/public/ble-adapter.d.ts +3 -3
  404. package/lib/typescript/commonjs/src/public/ble-adapter.d.ts.map +1 -1
  405. package/lib/typescript/commonjs/src/public/ble-manager.d.ts +68 -14
  406. package/lib/typescript/commonjs/src/public/ble-manager.d.ts.map +1 -1
  407. package/lib/typescript/commonjs/src/public/cleanup.d.ts +35 -0
  408. package/lib/typescript/commonjs/src/public/cleanup.d.ts.map +1 -0
  409. package/lib/typescript/commonjs/src/public/connection-supervisor.d.ts +5 -5
  410. package/lib/typescript/commonjs/src/public/connection-supervisor.d.ts.map +1 -1
  411. package/lib/typescript/commonjs/src/public/diagnostics.d.ts +20 -2
  412. package/lib/typescript/commonjs/src/public/diagnostics.d.ts.map +1 -1
  413. package/lib/typescript/commonjs/src/public/error-bridge.d.ts +5 -11
  414. package/lib/typescript/commonjs/src/public/error-bridge.d.ts.map +1 -1
  415. package/lib/typescript/commonjs/src/public/errors.d.ts +4 -3
  416. package/lib/typescript/commonjs/src/public/errors.d.ts.map +1 -1
  417. package/lib/typescript/commonjs/src/public/gatt.d.ts +7 -13
  418. package/lib/typescript/commonjs/src/public/gatt.d.ts.map +1 -1
  419. package/lib/typescript/commonjs/src/public/host-identity.d.ts +7 -1
  420. package/lib/typescript/commonjs/src/public/host-identity.d.ts.map +1 -1
  421. package/lib/typescript/commonjs/src/public/index.d.ts +2 -0
  422. package/lib/typescript/commonjs/src/public/index.d.ts.map +1 -1
  423. package/lib/typescript/commonjs/src/public/scan-query.d.ts +8 -0
  424. package/lib/typescript/commonjs/src/public/scan-query.d.ts.map +1 -1
  425. package/lib/typescript/commonjs/src/public/scan-state-budget.d.ts +11 -0
  426. package/lib/typescript/commonjs/src/public/scan-state-budget.d.ts.map +1 -1
  427. package/lib/typescript/commonjs/src/public/security.d.ts +6 -0
  428. package/lib/typescript/commonjs/src/public/security.d.ts.map +1 -1
  429. package/lib/typescript/commonjs/src/public/stream-capacity.d.ts +16 -0
  430. package/lib/typescript/commonjs/src/public/stream-capacity.d.ts.map +1 -0
  431. package/lib/typescript/commonjs/src/public/stream-presets.d.ts +3 -2
  432. package/lib/typescript/commonjs/src/public/stream-presets.d.ts.map +1 -1
  433. package/lib/typescript/commonjs/src/public/streams.d.ts +44 -0
  434. package/lib/typescript/commonjs/src/public/streams.d.ts.map +1 -0
  435. package/lib/typescript/commonjs/src/react.d.ts.map +1 -1
  436. package/lib/typescript/commonjs/src/tck/first-party/bluez-tck-registration.d.ts +1 -1
  437. package/lib/typescript/commonjs/src/tck/first-party/bluez-tck-registration.d.ts.map +1 -1
  438. package/lib/typescript/commonjs/src/testing/deterministic/deterministic-security.d.ts.map +1 -1
  439. package/lib/typescript/module/src/backend-contract/advertisement.d.ts +9 -0
  440. package/lib/typescript/module/src/backend-contract/advertisement.d.ts.map +1 -1
  441. package/lib/typescript/module/src/backend-contract/backend.d.ts +15 -0
  442. package/lib/typescript/module/src/backend-contract/backend.d.ts.map +1 -1
  443. package/lib/typescript/module/src/backend-contract/capabilities.d.ts +7 -0
  444. package/lib/typescript/module/src/backend-contract/capabilities.d.ts.map +1 -1
  445. package/lib/typescript/module/src/backend-contract/ipc.d.ts +7 -0
  446. package/lib/typescript/module/src/backend-contract/ipc.d.ts.map +1 -1
  447. package/lib/typescript/module/src/backend-contract/primitives.d.ts +8 -0
  448. package/lib/typescript/module/src/backend-contract/primitives.d.ts.map +1 -1
  449. package/lib/typescript/module/src/backend-contract/scan-planning.d.ts +2 -2
  450. package/lib/typescript/module/src/backend-contract/scan-planning.d.ts.map +1 -1
  451. package/lib/typescript/module/src/backend-contract/scan-query.d.ts +12 -0
  452. package/lib/typescript/module/src/backend-contract/scan-query.d.ts.map +1 -1
  453. package/lib/typescript/module/src/backend-contract/security.d.ts +7 -0
  454. package/lib/typescript/module/src/backend-contract/security.d.ts.map +1 -1
  455. package/lib/typescript/module/src/backends/bluez/bluez-backend-handles.d.ts +1 -1
  456. package/lib/typescript/module/src/backends/bluez/bluez-backend-handles.d.ts.map +1 -1
  457. package/lib/typescript/module/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
  458. package/lib/typescript/module/src/backends/bluez/bluez-backend-runtime.d.ts +11 -2
  459. package/lib/typescript/module/src/backends/bluez/bluez-backend-runtime.d.ts.map +1 -1
  460. package/lib/typescript/module/src/backends/bluez/bluez-backend.d.ts.map +1 -1
  461. package/lib/typescript/module/src/backends/bluez/bluez-connection-capabilities.d.ts +13 -0
  462. package/lib/typescript/module/src/backends/bluez/bluez-connection-capabilities.d.ts.map +1 -0
  463. package/lib/typescript/module/src/backends/bluez/bluez-connection-runtime.d.ts +1 -1
  464. package/lib/typescript/module/src/backends/bluez/bluez-connection-runtime.d.ts.map +1 -1
  465. package/lib/typescript/module/src/backends/bluez/bluez-dbus-contract.d.ts +3 -1
  466. package/lib/typescript/module/src/backends/bluez/bluez-dbus-contract.d.ts.map +1 -1
  467. package/lib/typescript/module/src/backends/bluez/bluez-dbus-next-boundary.d.ts.map +1 -1
  468. package/lib/typescript/module/src/backends/bluez/bluez-operation-dispatcher.d.ts +12 -0
  469. package/lib/typescript/module/src/backends/bluez/bluez-operation-dispatcher.d.ts.map +1 -1
  470. package/lib/typescript/module/src/backends/bluez/bluez-property-waiters.d.ts +12 -0
  471. package/lib/typescript/module/src/backends/bluez/bluez-property-waiters.d.ts.map +1 -1
  472. package/lib/typescript/module/src/backends/bluez/bluez-runtime-models.d.ts.map +1 -1
  473. package/lib/typescript/module/src/backends/bluez/bluez-runtime-types.d.ts +2 -0
  474. package/lib/typescript/module/src/backends/bluez/bluez-runtime-types.d.ts.map +1 -1
  475. package/lib/typescript/module/src/backends/bluez/bluez-scan-planner.d.ts.map +1 -1
  476. package/lib/typescript/module/src/backends/bluez/bluez-security.d.ts +0 -1
  477. package/lib/typescript/module/src/backends/bluez/bluez-security.d.ts.map +1 -1
  478. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-backend.d.ts +9 -0
  479. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-backend.d.ts.map +1 -1
  480. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-boundary.d.ts +17 -1
  481. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-boundary.d.ts.map +1 -1
  482. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-cleanup.d.ts +10 -1
  483. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-cleanup.d.ts.map +1 -1
  484. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-connection-controls.d.ts.map +1 -1
  485. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
  486. package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
  487. package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts.map +1 -1
  488. package/lib/typescript/module/src/backends/reactnative/react-native-android-security.d.ts.map +1 -1
  489. package/lib/typescript/module/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
  490. package/lib/typescript/module/src/backends/reactnative/react-native-restoration.d.ts.map +1 -1
  491. package/lib/typescript/module/src/backends/reactnative/react-native-scan-planner.d.ts.map +1 -1
  492. package/lib/typescript/module/src/backends/scan-planning/service-uuid-scan-planner.d.ts.map +1 -1
  493. package/lib/typescript/module/src/backends/winrt/winrt-backend-helpers.d.ts +9 -0
  494. package/lib/typescript/module/src/backends/winrt/winrt-backend-helpers.d.ts.map +1 -1
  495. package/lib/typescript/module/src/backends/winrt/winrt-provider.d.ts +1 -1
  496. package/lib/typescript/module/src/backends/winrt/winrt-security.d.ts.map +1 -1
  497. package/lib/typescript/module/src/cli-json.d.ts.map +1 -1
  498. package/lib/typescript/module/src/core/core-characteristic-operations.d.ts.map +1 -1
  499. package/lib/typescript/module/src/core/core-gatt-handles.d.ts.map +1 -1
  500. package/lib/typescript/module/src/core/operation-coordinator.d.ts.map +1 -1
  501. package/lib/typescript/module/src/core/unified-ble-core.d.ts +3 -1
  502. package/lib/typescript/module/src/core/unified-ble-core.d.ts.map +1 -1
  503. package/lib/typescript/module/src/diagnostics/trace-format.d.ts +12 -0
  504. package/lib/typescript/module/src/diagnostics/trace-format.d.ts.map +1 -1
  505. package/lib/typescript/module/src/electron/connection-event-stream-registry.d.ts.map +1 -1
  506. package/lib/typescript/module/src/electron/main-binding.d.ts.map +1 -1
  507. package/lib/typescript/module/src/electron/main-router.d.ts.map +1 -1
  508. package/lib/typescript/module/src/electron/renderer-stream-registry.d.ts.map +1 -1
  509. package/lib/typescript/module/src/electron/renderer.d.ts.map +1 -1
  510. package/lib/typescript/module/src/expo.d.ts.map +1 -1
  511. package/lib/typescript/module/src/implementation-version.d.ts +1 -1
  512. package/lib/typescript/module/src/index.d.ts +3 -2
  513. package/lib/typescript/module/src/index.d.ts.map +1 -1
  514. package/lib/typescript/module/src/ipc/manager.d.ts +5 -2
  515. package/lib/typescript/module/src/ipc/manager.d.ts.map +1 -1
  516. package/lib/typescript/module/src/ipc/public-manager.d.ts +13 -4
  517. package/lib/typescript/module/src/ipc/public-manager.d.ts.map +1 -1
  518. package/lib/typescript/module/src/native-protocol/generated/native-protocol-v2-schema.d.ts +1 -1
  519. package/lib/typescript/module/src/native-protocol/generated/native-protocol-v2-schema.d.ts.map +1 -1
  520. package/lib/typescript/module/src/native-protocol/rn-android-boundary.d.ts +2 -2
  521. package/lib/typescript/module/src/native-protocol/rn-android-boundary.d.ts.map +1 -1
  522. package/lib/typescript/module/src/native-protocol/rn-apple-boundary.d.ts +2 -2
  523. package/lib/typescript/module/src/native-protocol/rn-apple-boundary.d.ts.map +1 -1
  524. package/lib/typescript/module/src/node-corebluetooth.d.ts.map +1 -1
  525. package/lib/typescript/module/src/public/ble-adapter.d.ts +3 -3
  526. package/lib/typescript/module/src/public/ble-adapter.d.ts.map +1 -1
  527. package/lib/typescript/module/src/public/ble-manager.d.ts +68 -14
  528. package/lib/typescript/module/src/public/ble-manager.d.ts.map +1 -1
  529. package/lib/typescript/module/src/public/cleanup.d.ts +35 -0
  530. package/lib/typescript/module/src/public/cleanup.d.ts.map +1 -0
  531. package/lib/typescript/module/src/public/connection-supervisor.d.ts +5 -5
  532. package/lib/typescript/module/src/public/connection-supervisor.d.ts.map +1 -1
  533. package/lib/typescript/module/src/public/diagnostics.d.ts +20 -2
  534. package/lib/typescript/module/src/public/diagnostics.d.ts.map +1 -1
  535. package/lib/typescript/module/src/public/error-bridge.d.ts +5 -11
  536. package/lib/typescript/module/src/public/error-bridge.d.ts.map +1 -1
  537. package/lib/typescript/module/src/public/errors.d.ts +4 -3
  538. package/lib/typescript/module/src/public/errors.d.ts.map +1 -1
  539. package/lib/typescript/module/src/public/gatt.d.ts +7 -13
  540. package/lib/typescript/module/src/public/gatt.d.ts.map +1 -1
  541. package/lib/typescript/module/src/public/host-identity.d.ts +7 -1
  542. package/lib/typescript/module/src/public/host-identity.d.ts.map +1 -1
  543. package/lib/typescript/module/src/public/index.d.ts +2 -0
  544. package/lib/typescript/module/src/public/index.d.ts.map +1 -1
  545. package/lib/typescript/module/src/public/scan-query.d.ts +8 -0
  546. package/lib/typescript/module/src/public/scan-query.d.ts.map +1 -1
  547. package/lib/typescript/module/src/public/scan-state-budget.d.ts +11 -0
  548. package/lib/typescript/module/src/public/scan-state-budget.d.ts.map +1 -1
  549. package/lib/typescript/module/src/public/security.d.ts +6 -0
  550. package/lib/typescript/module/src/public/security.d.ts.map +1 -1
  551. package/lib/typescript/module/src/public/stream-capacity.d.ts +16 -0
  552. package/lib/typescript/module/src/public/stream-capacity.d.ts.map +1 -0
  553. package/lib/typescript/module/src/public/stream-presets.d.ts +3 -2
  554. package/lib/typescript/module/src/public/stream-presets.d.ts.map +1 -1
  555. package/lib/typescript/module/src/public/streams.d.ts +44 -0
  556. package/lib/typescript/module/src/public/streams.d.ts.map +1 -0
  557. package/lib/typescript/module/src/react.d.ts.map +1 -1
  558. package/lib/typescript/module/src/tck/first-party/bluez-tck-registration.d.ts +1 -1
  559. package/lib/typescript/module/src/tck/first-party/bluez-tck-registration.d.ts.map +1 -1
  560. package/lib/typescript/module/src/testing/deterministic/deterministic-security.d.ts.map +1 -1
  561. package/native/PREBUILDS.json +5 -5
  562. package/native/electron/corebluetooth/prebuilds/darwin-arm64/unified_ble_corebluetooth.node +0 -0
  563. package/native/electron/corebluetooth/prebuilds/darwin-x64/unified_ble_corebluetooth.node +0 -0
  564. package/native/electron/winrt/prebuilds/win32-arm64/unified_ble_winrt.node +0 -0
  565. package/native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node +0 -0
  566. package/native/protocol/generated/NativeProtocolV2Schema.hpp +3 -2
  567. package/native/protocol/schema/native-protocol-v2-abi.json +9 -2
  568. package/native/protocol/schema/native-protocol-v2.json +3 -2
  569. package/native/protocol/src/NativeProtocolV2Codec.cpp +48 -4
  570. package/native/tauri/Cargo.toml +14 -0
  571. package/native/tauri/src/btleplug_dispatcher.rs +422 -10
  572. package/native/tauri/src/capabilities.rs +3 -1
  573. package/package.json +7 -4
  574. package/src/backend-contract/advertisement.ts +28 -0
  575. package/src/backend-contract/backend.ts +15 -0
  576. package/src/backend-contract/capabilities.ts +7 -0
  577. package/src/backend-contract/ipc.ts +7 -0
  578. package/src/backend-contract/primitives.ts +13 -0
  579. package/src/backend-contract/scan-planning.ts +15 -0
  580. package/src/backend-contract/scan-query.ts +33 -3
  581. package/src/backend-contract/security.ts +7 -0
  582. package/src/backends/bluez/bluez-backend-handles.ts +110 -49
  583. package/src/backends/bluez/bluez-backend-provider.ts +1 -1
  584. package/src/backends/bluez/bluez-backend-runtime.ts +36 -1
  585. package/src/backends/bluez/bluez-backend.ts +11 -1
  586. package/src/backends/bluez/bluez-connection-capabilities.ts +144 -0
  587. package/src/backends/bluez/bluez-connection-runtime.ts +203 -8
  588. package/src/backends/bluez/bluez-dbus-contract.ts +3 -1
  589. package/src/backends/bluez/bluez-dbus-next-boundary.ts +188 -3
  590. package/src/backends/bluez/bluez-operation-dispatcher.ts +39 -34
  591. package/src/backends/bluez/bluez-property-waiters.ts +60 -1
  592. package/src/backends/bluez/bluez-runtime-models.ts +6 -5
  593. package/src/backends/bluez/bluez-runtime-types.ts +2 -0
  594. package/src/backends/bluez/bluez-scan-planner.ts +6 -1
  595. package/src/backends/bluez/bluez-security.ts +72 -2
  596. package/src/backends/corebluetooth/corebluetooth-adapter-loss-cleanup.ts +4 -4
  597. package/src/backends/corebluetooth/corebluetooth-backend.ts +118 -58
  598. package/src/backends/corebluetooth/corebluetooth-boundary.ts +20 -1
  599. package/src/backends/corebluetooth/corebluetooth-cleanup.ts +12 -3
  600. package/src/backends/corebluetooth/corebluetooth-connection-controls.ts +65 -57
  601. package/src/backends/corebluetooth/corebluetooth-gatt-operations.ts +48 -48
  602. package/src/backends/corebluetooth/corebluetooth-handles.ts +12 -12
  603. package/src/backends/corebluetooth/corebluetooth-late-connect-cleanup.ts +1 -1
  604. package/src/backends/corebluetooth/corebluetooth-provider.ts +1 -1
  605. package/src/backends/corebluetooth/corebluetooth-runtime-capabilities.ts +3 -3
  606. package/src/backends/reactnative/react-native-android-provider.ts +38 -1
  607. package/src/backends/reactnative/react-native-android-security.ts +15 -1
  608. package/src/backends/reactnative/react-native-restoration.ts +8 -0
  609. package/src/backends/reactnative/react-native-scan-planner.ts +11 -1
  610. package/src/backends/scan-planning/service-uuid-scan-planner.ts +54 -3
  611. package/src/backends/winrt/winrt-backend-helpers.ts +9 -0
  612. package/src/backends/winrt/winrt-security.ts +9 -0
  613. package/src/cli-json.ts +7 -0
  614. package/src/core/core-characteristic-operations.ts +13 -0
  615. package/src/core/core-gatt-handles.ts +10 -0
  616. package/src/core/operation-coordinator.ts +10 -1
  617. package/src/core/unified-ble-core.ts +22 -0
  618. package/src/diagnostics/trace-format.ts +12 -0
  619. package/src/electron/connection-event-stream-registry.ts +8 -0
  620. package/src/electron/main-binding.ts +16 -0
  621. package/src/electron/main-router.ts +11 -0
  622. package/src/electron/renderer-stream-registry.ts +8 -0
  623. package/src/electron/renderer.ts +11 -0
  624. package/src/expo.ts +44 -1
  625. package/src/implementation-version.ts +1 -1
  626. package/src/index.ts +26 -2
  627. package/src/ipc/manager.ts +76 -18
  628. package/src/ipc/public-manager.ts +311 -121
  629. package/src/native-protocol/generated/native-protocol-v2-schema.ts +2 -1
  630. package/src/native-protocol/rn-android-boundary.ts +42 -6
  631. package/src/native-protocol/rn-apple-boundary.ts +11 -2
  632. package/src/node-corebluetooth.ts +15 -4
  633. package/src/node-host-manager.ts +14 -6
  634. package/src/public/ble-adapter.ts +5 -3
  635. package/src/public/ble-manager.ts +304 -99
  636. package/src/public/cleanup.ts +255 -0
  637. package/src/public/connection-supervisor.ts +62 -28
  638. package/src/public/diagnostics.ts +46 -2
  639. package/src/public/error-bridge.ts +40 -24
  640. package/src/public/errors.ts +5 -35
  641. package/src/public/gatt.ts +60 -104
  642. package/src/public/host-identity.ts +7 -1
  643. package/src/public/index.ts +19 -0
  644. package/src/public/scan-query.ts +82 -4
  645. package/src/public/scan-state-budget.ts +11 -0
  646. package/src/public/security.ts +15 -0
  647. package/src/public/stream-capacity.ts +18 -0
  648. package/src/public/stream-presets.ts +21 -3
  649. package/src/public/streams.ts +315 -0
  650. package/src/react.ts +81 -38
  651. package/src/tck/first-party/bluez-tck-registration.ts +19 -3
  652. package/src/testing/deterministic/deterministic-scan-planner.ts +1 -0
  653. package/src/testing/deterministic/deterministic-security.ts +8 -0
package/CHANGELOG.md CHANGED
@@ -2,7 +2,64 @@
2
2
 
3
3
  All notable changes to `unified-ble-manager` are documented here.
4
4
 
5
- ## [Unreleased]
5
+ ## [4.0.6] - 2026-08-26
6
+
7
+ The first release cut against a live peripheral on Android as well as Linux. Most of it is defects that only real hardware surfaced, several of them boundaries that discarded evidence and so presented a specific fault as silence. Does not retag `v4.0.5`.
8
+
9
+ ### Fixes
10
+
11
+ - A Tauri disconnect that fails no longer leaves the peer owned when the platform can prove it was released. btleplug's CoreBluetooth `disconnect()` never resolves once the peripheral has left its internal map, so the call is bounded and the outcome decided by a fresh state reading: gone means released, still connected means the retry keeps ownership. On BlueZ the state reading is classified before it is stringified, because a removed D-Bus device object is not a failed question but the answer to it - previously that case was treated as unknowable and the peer stayed owned until the process restarted. Genuine indeterminacy - a D-Bus timeout, the daemon gone, the adapter pulled - still retains ownership (#145, #154).
12
+
13
+ - BlueZ no longer reports a pairing it could not stop as `cancelled`. `Device1.CancelPairing` rejections were all swallowed, so a refusal from bluetoothd — `org.bluez.Error.Failed`, `NotAuthorized`, a D-Bus timeout, the daemon gone — left the in-flight `Pair` running while `cancelPairing()` returned `cancelled` and the abort/deadline path did the same. A caller told no bond exists while one is still being made cannot recover, because it never learns to look. Only the two rejections that prove nothing is left running are treated as success — `org.bluez.Error.DoesNotExist` and `org.freedesktop.DBus.Error.UnknownObject`, an answer to the question rather than a failure to answer it, the same pair the Tauri disconnect path classifies for the same reason. Anything else now surfaces as `platform.failure` carrying the D-Bus error name (#143).
14
+
15
+ - `scan()` works on React Native Android again, and so does every other control-plane operation there. The Android dispatcher stamped a hardcoded `1` on field 1 of every result and event it built while the native codec has required version 2 since the schema was frozen, so all of them — `scanStarted`, a connect completing, a connect failing, a cancellation, a bond state change, a lost link — were rejected at the JSI boundary as version-incompatible and dropped. A scan therefore never received its terminal: the radio discovered the peripheral 38 times in one four-minute capture and the application was handed nothing. The stamp now comes from the generated `NATIVE_PROTOCOL_VERSION`, so it cannot drift from the version the codec validates against (#140).
16
+ - A record the codec refuses is no longer only written to logcat: the Android binding counts quarantined records per attachment and emits a `recordQuarantined` diagnostic in place of the record it could not deliver, so an application learns that the boundary discarded something it was asked to deliver (#140).
17
+ - A version-incompatible record names its kind, the version it carried and the version expected, so a quarantined record identifies its emitter instead of leaving four record kinds to choose between (#140).
18
+ - `adapter.waitUntilReady()` no longer reports a radio that is still starting up as one the caller is not permitted to use. The React Native Android boundary answers `authorization: 'unavailable'` until the radio publishes its first authoritative state, and the readiness gate maps that value to `permission.denied` — so the one API whose purpose is to wait that window out failed on the very state it exists to wait for, on a phone with Bluetooth switched on and all four runtime permissions granted. The pending snapshot now reports `authorization: 'unknown'`, the value its `availability` and `power` siblings already carried for the same reason: the absence of a measurement is never a denial, so no readiness gate may block on it (#156).
19
+ - BlueZ states its connection-control truth instead of omitting the concept: `connection:priority` and `connection:parameters` are now registered as explicitly `unsupported`, with limitations naming the BlueZ D-Bus gap (no LE connection-parameter API on `org.bluez.Device1`/`Adapter1`, BlueZ 5.85), the privilege requirement of the alternatives (`CAP_NET_ADMIN` kernel mgmt socket and root-only debugfs — neither a live per-connection update), and the consequence that GATT traffic may run at a multi-hundred-millisecond peer-negotiated interval. `requestPriority()`, `parameters()`, and `parameterEvents()` fail closed with that reason attached (`BleError.limitations` and `platform.safeMessage`) instead of a bare `capability.unsupported` that taught nothing while a slow link looked like a peripheral fault (#149).
20
+ - BlueZ `security.pair()` no longer fires `Device1.Pair` when the operation is aborted or times out while the just-works agent is still registering; it re-checks cancellation after agent registration so a cancelled pairing never proceeds on the daemon (#143).
21
+ - BlueZ `security.pair()` reports `paired` (not `cancelled`) when an abort or deadline lands after `Device1.Pair` has already completed the bond, so a bond that was actually created is never reported as if it never happened (#143).
22
+ - Android `security.pair()` no longer reports a timed-out pairing as `cancelled` when native cancellation is unavailable and it cannot actually stop the in-flight bond; the deadline path now fails closed with `capability.unsupported`, matching the abort path, so a bond that may still complete is never misreported as cancelled (#143).
23
+
24
+ ### Additions
25
+
26
+ - `FindOptions` accepts `duplicates` and `delivery`, so the `find()` convenience can be pointed at a peripheral that advertises in dense bursts instead of being abandoned for a hand-driven `scan()`. Both default to the values `find()` has always used (`'coalesced'` and `'latest'`), so nothing changes for existing callers (#148).
27
+ - BlueZ pairing dispatch: `org.bluez.Device1.Pair`, `org.bluez.Device1.CancelPairing`, and `org.bluez.Adapter1.RemoveDevice` are now allowed through the dbus-next boundary, and the backend registers a just-works (`NoInputNoOutput`) `org.bluez.Agent1` on its own bus (not the system default) so a client-initiated pairing can complete without an external agent (#141, #143).
28
+
29
+ ### Changes
30
+
31
+ - The Node convenience factories (`createBluezBleManager` and siblings) now select the first adapter (ordered deterministically by id) when the caller names no `adapterId`, instead of failing on a multi-adapter host. A single-adapter machine needs no configuration and a multi-adapter host picks the same controller every run; pass `adapterId` to target a specific controller (e.g. a second USB dongle used for debugging). The low-level provider is unchanged: it still requires an explicit selection and never silently substitutes one (#143).
32
+ - `PairOptions.secureConnections` (`'require' | 'prefer' | 'disallow'`, default `'prefer'`): request an LE pairing generation. `'prefer'` defers to the platform. No current backend exposes per-pairing generation selection, so `'require'` and `'disallow'` fail closed with `capability.unsupported` on BlueZ, WinRT, Android **and the deterministic `/testing` backend** rather than being silently ignored; the contract is in place for a backend that can honour it. The deterministic backend previously ignored the field and reported a Secure Connections bond under the exact option that forbids one, so a consumer's suite could pass against a contract every real radio rejects — the one way test infrastructure can actively mislead. A test that asserted a successful pair under `'require'` or `'disallow'` now sees `capability.unsupported`, which is what production would have done (#144, #143).
33
+
34
+ ### Documentation
35
+
36
+ - Every hardcoded timing and capacity constant in `src/` is now classified as a protocol invariant, a safety bound, or host policy, and each one that stays fixed carries a comment at its definition saying why. Undocumented constants were the defect: a fixed deadline that is never explained reads as a device fault when a slower host misses it (#148).
37
+ - `find()`'s 10 s fallback deadline and `adapter.waitUntilReady()`'s 10 s fallback deadline are named constants shared between the in-process and IPC managers, so the same logical operation cannot expire at two different times either side of the IPC boundary (#148).
38
+
39
+ ## [4.0.5] - 2026-08-25
40
+
41
+ First release cut against a live peripheral. Every fix below came from driving a real CGM from an Android phone and a Linux/BlueZ host, and several are defects no unit test had reason to catch. Does not retag `v4.0.4`.
42
+
43
+ ### Fixes
44
+
45
+ - `readiness()` no longer reports a working radio as `unavailable` before the Android adapter publishes its authoritative state; a boundary that has not yet been told the radio's state is a pending condition, not an absent radio (#116, #128).
46
+ - The direct-GATT backend is shared by CoreBluetooth and React Native Android, so its diagnostics now name the platform that is actually running — `[unified-ble:android-gatt.*]` rather than `[CoreBluetoothBackend.*]` — and its operation ids are `direct-gatt.*` instead of `corebluetooth.*`. Scan-stop cleanup timeouts carry the platform identity instead of `platform: null` (#117, #128, #132).
47
+ - An address known out of band can now enter the system: `ScanClause.addresses` and `connect({ address })`, gated on the reported `peer:address-targeting` capability, with pending BlueZ semantics that complete whenever the peripheral next advertises, and Android `ScanFilter.setDeviceAddress`. Hosts that cannot express a radio address — CoreBluetooth, Web, and the IPC transport — report the capability unsupported and fail closed rather than advertising something they cannot honour (#118, #128, #131, #133).
48
+ - `ScanOptions.platform` is honoured instead of unconditionally rejected, so consumers can select Android scan mode; peripherals that advertise infrequently are no longer effectively undiscoverable behind the platform default duty cycle. Gated on `scan:platform-options` in the public, core and IPC paths; `match-lost` and pre-26 `legacy: false` fail closed rather than silently doing something else (#120, #130).
49
+ - BlueZ GATT works again: occurrences are decimal indices rather than D-Bus object paths, so `discover()` no longer fails with `protocol.violation: public-gatt.occurrence` on every device — a regression introduced when the public validator was tightened without migrating the backend. Two same-UUID services are now distinctly addressable, which neither the old leniency nor the strict check managed (#123, #129).
50
+ - The BlueZ boundary decodes the `y` and `a{qv}` D-Bus variants that BlueZ 5.85 actually sends, and routes `Adapter1.ConnectDevice` through the boundary instead of rejecting it as locally unsupported; without these the backend could not attach at all (#128).
51
+ - Public BLE resources are portable across copies, and closing an adapter watch's value stream tears the watch down instead of leaving a 25 ms poll timer and an abort listener alive (#122).
52
+ - `@babel/runtime` is declared as a production dependency. The emitted CommonJS imports its helpers, so an external linked checkout failed with `MODULE_NOT_FOUND` while repository-local tests passed against a transitive copy — a packaging gap only a real consumer could surface (#134, #135).
53
+ - A database stream is finalized after an invalidation retry succeeds, and per-subscription React cleanup and failed IPC CCCDs stay owned (#127).
54
+
55
+ ### Compatibility
56
+
57
+ - Native protocol ABI 3 → 4. A JavaScript bundle carrying the new scan fields now fails attachment negotiation against an older native binary instead of failing at scan-start — or, worse, silently selecting the opposite scan mode.
58
+
59
+ ### Release integrity
60
+
61
+ - Cut from the exact `main` merge commit through the tag-driven trusted-publishing workflow.
62
+ - Intended for publication as `latest`; this does not promote backend support labels. The live-hardware runs behind these fixes are development evidence, not qualification evidence.
6
63
 
7
64
  ## [4.0.4] - 2026-08-25
8
65
 
package/MIGRATION_4.0.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Migrating from react-native-ble-plx
4
4
 
5
- The current package is `4.0.4`. 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.
5
+ The current package is `4.0.6`. 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
@@ -6,7 +6,7 @@
6
6
 
7
7
  It is an evolution of `react-native-ble-plx`, rewritten as a **cross-platform unified product**. One bytes-first BLE model and lifecycle semantics across hosts, with host-specific construction and ownership. The root package never picks a radio for you, and it will not quietly fall back to a simulator or a different backend.
8
8
 
9
- Install `unified-ble-manager` from npm (`4.0.4` on `latest`). The root import does not pick a radio. Package SemVer and backend support labels are independent: each radio backend stays Experimental until live-radio evidence says otherwise. See [`docs/PLATFORMS.md`](docs/PLATFORMS.md).
9
+ Install `unified-ble-manager` from npm (`4.0.6` on `latest`). The root import does not pick a radio. Package SemVer and backend support labels are independent: each radio backend stays Experimental until live-radio evidence says otherwise. See [`docs/PLATFORMS.md`](docs/PLATFORMS.md).
10
10
 
11
11
  > Sponsored by [Imagi Explain](https://imagiexplain.com) — researched, narrated whiteboard explainers from a prompt, a PDF, or your notes.
12
12
 
package/RELEASE.md CHANGED
@@ -81,7 +81,7 @@ Active `4.0.0-rc.*` release-train candidates publish to npm `latest` so a bare `
81
81
 
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
- once tagged. Stable `4.0.0`, `4.0.1`, `4.0.2`, and `4.0.3` are immutable. `4.0.4` is the current train head.
84
+ once tagged. Stable `4.0.0`, `4.0.1`, `4.0.2`, `4.0.3`, `4.0.4`, and `4.0.5` are immutable. `4.0.6` is the current train head.
85
85
 
86
86
  ```sh
87
87
  release_candidate=4.0.0-rc.N
@@ -133,7 +133,7 @@ The `v4.0.3` tag is immutable published history. Do not recreate or move it.
133
133
  git tag -a v4.0.3 -m "v4.0.3"
134
134
  ```
135
135
 
136
- ## Releasing 4.0.4
136
+ ## Releasing 4.0.6
137
137
 
138
138
  The source version is prepared on `main` before the tag. The release workflow verifies that every initial release tag points at the exact current `main` commit before publication; do not create that tag from a side branch or an older commit. Do not retag immutable `v4.0.0`, `v4.0.1`, `v4.0.2`, or `v4.0.3`.
139
139
 
@@ -145,12 +145,12 @@ git checkout main
145
145
  git pull --ff-only origin main
146
146
 
147
147
  test "$(git branch --show-current)" = "main"
148
- test "$(node -p "require('./package.json').version")" = "4.0.4"
148
+ test "$(node -p "require('./package.json').version")" = "4.0.6"
149
149
  git diff --exit-code
150
150
  git diff --cached --exit-code
151
151
 
152
- git tag -a v4.0.4 -m "v4.0.4"
153
- git push origin v4.0.4
152
+ git tag -a v4.0.6 -m "v4.0.6"
153
+ git push origin v4.0.6
154
154
  ```
155
155
 
156
156
  Do not push another commit to `main` between the final verification and the tag push.
@@ -178,26 +178,34 @@ Stable versions publish to `latest`. Active `4.0.0-rc.*` candidates also publish
178
178
 
179
179
  ## Post-release verification
180
180
 
181
- After the workflow succeeds:
181
+ After the workflow succeeds, verify the registry rather than the workflow log:
182
+ a green publish job and a package a consumer can actually install are not the
183
+ same claim.
182
184
 
183
185
  ```sh
184
- release_candidate=4.0.0-rc.N
186
+ version=4.0.6
185
187
 
186
- npm view "unified-ble-manager@$release_candidate" version
188
+ npm view "unified-ble-manager@$version" version
187
189
  npm view unified-ble-manager dist-tags --json
188
- npm view "unified-ble-manager@$release_candidate" repository --json
189
- npm view "unified-ble-manager@$release_candidate" license
190
+ npm view "unified-ble-manager@$version" repository --json
191
+ npm view "unified-ble-manager@$version" license
192
+ npm view "unified-ble-manager@$version" dist.integrity
190
193
  ```
191
194
 
192
195
  Then verify:
193
196
 
194
- - npm `latest` resolves to the selected release candidate;
197
+ - npm `latest` resolves to the released version (a stable release moves
198
+ `latest`; a prerelease must leave it alone and publish to `next`);
195
199
  - the npm package page shows provenance for the published artifact;
196
- - the GitHub Release exists at the selected candidate tag and is marked prerelease;
197
- - its attached tarball/SBOM/license artifacts correspond to the release workflow output;
198
- - a clean consumer can install `unified-ble-manager` (no version pin) and import the documented host entrypoints.
199
-
200
- After the later stable tag, repeat the same checks for `4.0.0`. `latest` then moves to `4.0.0`.
200
+ - the GitHub Release exists at that tag, and is marked prerelease only if the
201
+ version is one;
202
+ - its attached tarball/SBOM/license artifacts correspond to the release
203
+ workflow output;
204
+ - a clean consumer, in a directory outside this repository, can install
205
+ `unified-ble-manager` with no version pin and import the documented host
206
+ entrypoints. This is the check that catches a packaging gap the repository's
207
+ own tests cannot see: `@babel/runtime` shipped undeclared in 4.0.4 and only a
208
+ real external consumer surfaced it.
201
209
 
202
210
  ## Failed release or partial publish
203
211
 
package/SBOM.cdx.json CHANGED
@@ -6,20 +6,20 @@
6
6
  "metadata": {
7
7
  "component": {
8
8
  "type": "library",
9
- "bom-ref": "pkg:npm/unified-ble-manager@4.0.4",
9
+ "bom-ref": "pkg:npm/unified-ble-manager@4.0.6",
10
10
  "name": "unified-ble-manager",
11
- "version": "4.0.4",
11
+ "version": "4.0.6",
12
12
  "licenses": [
13
13
  {
14
14
  "expression": "Apache-2.0"
15
15
  }
16
16
  ],
17
- "purl": "pkg:npm/unified-ble-manager@4.0.4"
17
+ "purl": "pkg:npm/unified-ble-manager@4.0.6"
18
18
  },
19
19
  "properties": [
20
20
  {
21
21
  "name": "unified-ble-manager:pnpm-lock-sha256",
22
- "value": "95b40628ee5be6e80662325b6f7c09547541957e885f4bb714fe1aca28f4153f"
22
+ "value": "5fb778bd200cb93f552ec61264d53829dca5bdd27623ccc692d4d9bcbf9ec296"
23
23
  },
24
24
  {
25
25
  "name": "unified-ble-manager:dependency-scope",
@@ -28,6 +28,25 @@
28
28
  ]
29
29
  },
30
30
  "components": [
31
+ {
32
+ "type": "library",
33
+ "bom-ref": "pkg:npm/%40babel/runtime@7.29.7",
34
+ "group": "@babel",
35
+ "name": "runtime",
36
+ "version": "7.29.7",
37
+ "licenses": [
38
+ {
39
+ "expression": "MIT"
40
+ }
41
+ ],
42
+ "purl": "pkg:npm/%40babel/runtime@7.29.7",
43
+ "properties": [
44
+ {
45
+ "name": "unified-ble-manager:license-source",
46
+ "value": "package-metadata"
47
+ }
48
+ ]
49
+ },
31
50
  {
32
51
  "type": "library",
33
52
  "bom-ref": "pkg:npm/%40isaacs/fs-minipass@4.0.1",
@@ -428,6 +447,10 @@
428
447
  }
429
448
  ],
430
449
  "dependencies": [
450
+ {
451
+ "ref": "pkg:npm/%40babel/runtime@7.29.7",
452
+ "dependsOn": []
453
+ },
431
454
  {
432
455
  "ref": "pkg:npm/%40isaacs/fs-minipass@4.0.1",
433
456
  "dependsOn": [
@@ -537,8 +560,9 @@
537
560
  "dependsOn": []
538
561
  },
539
562
  {
540
- "ref": "pkg:npm/unified-ble-manager@4.0.4",
563
+ "ref": "pkg:npm/unified-ble-manager@4.0.6",
541
564
  "dependsOn": [
565
+ "pkg:npm/%40babel/runtime@7.29.7",
542
566
  "pkg:npm/%40tauri-apps/api@2.11.1",
543
567
  "pkg:npm/node-addon-api@8.9.0",
544
568
  "pkg:npm/node-gyp@12.4.0"
@@ -4,12 +4,12 @@
4
4
  "schemaVersion": "1.0.0",
5
5
  "package": {
6
6
  "name": "unified-ble-manager",
7
- "version": "4.0.4"
7
+ "version": "4.0.6"
8
8
  },
9
9
  "source": {
10
10
  "method": "pnpm-lock production graph with installed-manifest license audit",
11
11
  "lockfile": "pnpm-lock.yaml",
12
- "lockfileSha256": "95b40628ee5be6e80662325b6f7c09547541957e885f4bb714fe1aca28f4153f"
12
+ "lockfileSha256": "5fb778bd200cb93f552ec61264d53829dca5bdd27623ccc692d4d9bcbf9ec296"
13
13
  },
14
14
  "reviewedOverrides": [
15
15
  {
@@ -27,6 +27,13 @@
27
27
  ],
28
28
  "unresolved": [],
29
29
  "packages": [
30
+ {
31
+ "name": "@babel/runtime",
32
+ "version": "7.29.7",
33
+ "license": "MIT",
34
+ "licenseSource": "package-metadata",
35
+ "purl": "pkg:npm/%40babel/runtime@7.29.7"
36
+ },
30
37
  {
31
38
  "name": "@isaacs/fs-minipass",
32
39
  "version": "4.0.1",
@@ -247,13 +247,29 @@ public final class UnifiedBleExpoRuntimeModule extends NativeUnifiedBleExpoRunti
247
247
  }
248
248
  }
249
249
 
250
+ /**
251
+ * Read a manifest meta-data flag without assuming how the platform typed it.
252
+ *
253
+ * <p>The config plugin writes {@code android:value="true"}, but the Android manifest parser
254
+ * coerces the literals {@code "true"} and {@code "false"} into a {@link Boolean} before they
255
+ * reach the {@link Bundle}. Reading such an entry with {@code getString} logs a type warning and
256
+ * yields {@code null}, so the caller silently falls back to its default and every configuration
257
+ * digests identically - which defeats the purpose of a digest that exists to detect drift.
258
+ */
259
+ private static boolean metadataFlag(Bundle metadata, String key, boolean fallback) {
260
+ final Object value = metadata.get(key);
261
+ if (value instanceof Boolean) return (Boolean) value;
262
+ if (value instanceof String) return Boolean.parseBoolean((String) value);
263
+ return fallback;
264
+ }
265
+
250
266
  private String configurationDigest(String legacyLocationPolicy) {
251
267
  final Bundle metadata = applicationMetadata();
252
268
  final String canonical = "unified-ble-expo-runtime-v1\n"
253
269
  + "platform=android\n"
254
270
  + "legacyLocationPolicy=" + legacyLocationPolicy + "\n"
255
- + "neverForLocation=" + metadata.getString(NEVER_FOR_LOCATION_METADATA, "false") + "\n"
256
- + "requiredHardware=" + metadata.getString(REQUIRED_HARDWARE_METADATA, "false") + "\n";
271
+ + "neverForLocation=" + metadataFlag(metadata, NEVER_FOR_LOCATION_METADATA, false) + "\n"
272
+ + "requiredHardware=" + metadataFlag(metadata, REQUIRED_HARDWARE_METADATA, false) + "\n";
257
273
  try {
258
274
  final byte[] digest = MessageDigest.getInstance("SHA-256")
259
275
  .digest(canonical.getBytes(StandardCharsets.UTF_8));
@@ -6,6 +6,7 @@ import android.bluetooth.BluetoothGattCharacteristic
6
6
  import android.content.Context
7
7
  import android.os.Build
8
8
  import android.os.SystemClock
9
+ import com.sfourdrinier.unifiedblemanager.protocol.generated.NATIVE_PROTOCOL_VERSION
9
10
  import com.sfourdrinier.unifiedblemanager.protocol.generated.RecordKind
10
11
  import com.sfourdrinier.unifiedblemanager.radio.OwnedAndroidGattRadio
11
12
  import com.sfourdrinier.unifiedblemanager.radio.OwnedRadioTeardownFailure
@@ -255,7 +256,8 @@ class UnifiedBleProtocolAndroidDispatcher(
255
256
  scanMode = options.requiredSignedInteger(3).toInt(),
256
257
  callbackType = options.requiredSignedInteger(4).toInt(),
257
258
  legacyScan = options.requiredBoolean(5),
258
- allowDuplicates = options.requiredBoolean(2)
259
+ allowDuplicates = options.requiredBoolean(2),
260
+ deviceAddresses = options.optionalStringList(6).toTypedArray()
259
261
  )
260
262
  emitSuccess(command, "scanStarted")
261
263
  } catch (error: Exception) {
@@ -765,7 +767,7 @@ class UnifiedBleProtocolAndroidDispatcher(
765
767
  private fun emitSuccess(command: ProtocolWireRecord, kind: String, additions: Map<Int, ProtocolWireValue> = emptyMap()) {
766
768
  if (!isPending(command)) return
767
769
  val fields = mutableMapOf<Int, ProtocolWireValue>(
768
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
770
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
769
771
  2 to ProtocolWireValue.StringValue(kind),
770
772
  3 to ProtocolWireValue.RecordValue(terminal(command, "succeeded"))
771
773
  )
@@ -797,7 +799,7 @@ class UnifiedBleProtocolAndroidDispatcher(
797
799
  val result = ProtocolWireRecord(
798
800
  RecordKind.RESULT,
799
801
  mapOf(
800
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
802
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
801
803
  2 to ProtocolWireValue.StringValue(dispatcherResultKindFor(command.requiredString(3))),
802
804
  3 to ProtocolWireValue.RecordValue(terminal(command, "failed", code)),
803
805
  10 to ProtocolWireValue.RecordValue(error)
@@ -813,7 +815,7 @@ class UnifiedBleProtocolAndroidDispatcher(
813
815
  val result = ProtocolWireRecord(
814
816
  RecordKind.RESULT,
815
817
  mapOf(
816
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
818
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
817
819
  2 to ProtocolWireValue.StringValue("cancelled"),
818
820
  3 to ProtocolWireValue.RecordValue(terminal(command, "failed", "cancelled")),
819
821
  10 to ProtocolWireValue.RecordValue(
@@ -840,7 +842,7 @@ class UnifiedBleProtocolAndroidDispatcher(
840
842
  val result = ProtocolWireRecord(
841
843
  RecordKind.RESULT,
842
844
  mapOf(
843
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
845
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
844
846
  2 to ProtocolWireValue.StringValue("cancelled"),
845
847
  3 to ProtocolWireValue.RecordValue(terminal(command, "succeeded")),
846
848
  8 to ProtocolWireValue.StringValue(state)
@@ -865,7 +867,7 @@ class UnifiedBleProtocolAndroidDispatcher(
865
867
  val event = ProtocolWireRecord(
866
868
  RecordKind.EVENT,
867
869
  mapOf(
868
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
870
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
869
871
  2 to ProtocolWireValue.StringValue("native-security-state-${SystemClock.elapsedRealtimeNanos()}"),
870
872
  3 to ProtocolWireValue.StringValue("securityStateChanged"),
871
873
  4 to ProtocolWireValue.RecordValue(attachment),
@@ -1111,7 +1113,7 @@ internal fun connectionLostEvent(
1111
1113
  return ProtocolWireRecord(
1112
1114
  RecordKind.EVENT,
1113
1115
  mapOf(
1114
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
1116
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
1115
1117
  2 to ProtocolWireValue.StringValue("native-connection-lost-$nativeHandle-$ingressOrdinal"),
1116
1118
  3 to ProtocolWireValue.StringValue("connectionLost"),
1117
1119
  4 to ProtocolWireValue.RecordValue(connection.requiredRecord(1)),
@@ -1133,7 +1135,7 @@ internal fun databaseChangedEvent(
1133
1135
  return ProtocolWireRecord(
1134
1136
  RecordKind.EVENT,
1135
1137
  mapOf(
1136
- 1 to ProtocolWireValue.UnsignedIntegerValue(1),
1138
+ 1 to ProtocolWireValue.UnsignedIntegerValue(NATIVE_PROTOCOL_VERSION.toLong()),
1137
1139
  2 to ProtocolWireValue.StringValue("native-database-changed-$nativeHandle-$ingressOrdinal"),
1138
1140
  3 to ProtocolWireValue.StringValue("databaseChanged"),
1139
1141
  4 to ProtocolWireValue.RecordValue(attachment),
@@ -1180,6 +1182,11 @@ private fun ProtocolWireRecord.requiredStringList(fieldId: Int): List<String> {
1180
1182
  return if (value is ProtocolWireValue.StringListValue) value.value else throw IllegalArgumentException("String list field is missing")
1181
1183
  }
1182
1184
 
1185
+ private fun ProtocolWireRecord.optionalStringList(fieldId: Int): List<String> {
1186
+ val value = fields[fieldId] ?: return emptyList()
1187
+ return if (value is ProtocolWireValue.StringListValue) value.value else throw IllegalArgumentException("String list field is malformed")
1188
+ }
1189
+
1183
1190
  private fun Boolean?.toNativeConnectableState(): Int = when (this) {
1184
1191
  true -> 1
1185
1192
  false -> 0
@@ -3,7 +3,7 @@
3
3
  package com.sfourdrinier.unifiedblemanager.protocol.generated
4
4
 
5
5
  const val NATIVE_PROTOCOL_VERSION: Int = 2
6
- const val NATIVE_PROTOCOL_ABI_VERSION: Int = 3
6
+ const val NATIVE_PROTOCOL_ABI_VERSION: Int = 4
7
7
  const val NATIVE_PROTOCOL_CONTROL_SURFACE_VERSION: Int = 2
8
8
  const val MAXIMUM_CONTROL_RECORD_BYTES: Int = 262144
9
9
  const val MAXIMUM_BINARY_PAYLOAD_BYTES: Int = 524288
@@ -223,6 +223,7 @@ val NATIVE_PROTOCOL_FIELDS: List<FieldDescriptor> = listOf(
223
223
  FieldDescriptor(RecordKind.SCAN_OPTIONS, 3, "scanMode", "int64", true),
224
224
  FieldDescriptor(RecordKind.SCAN_OPTIONS, 4, "callbackType", "int64", true),
225
225
  FieldDescriptor(RecordKind.SCAN_OPTIONS, 5, "legacyScan", "boolean", true),
226
+ FieldDescriptor(RecordKind.SCAN_OPTIONS, 6, "deviceAddresses", "strings", false),
226
227
  FieldDescriptor(RecordKind.ADAPTER_STATE_SNAPSHOT, 1, "availability", "enum:adapterAvailability", true),
227
228
  FieldDescriptor(RecordKind.ADAPTER_STATE_SNAPSHOT, 2, "authorization", "enum:adapterAuthorization", true),
228
229
  FieldDescriptor(RecordKind.ADAPTER_STATE_SNAPSHOT, 3, "power", "enum:adapterPower", true),
@@ -394,8 +394,16 @@ class OwnedAndroidGattRadio(private val context: Context) {
394
394
  scanMode: Int,
395
395
  callbackType: Int = ScanSettings.CALLBACK_TYPE_ALL_MATCHES,
396
396
  legacyScan: Boolean = true,
397
- allowDuplicates: Boolean = true
397
+ allowDuplicates: Boolean = true,
398
+ deviceAddresses: Array<out String> = emptyArray()
398
399
  ) {
400
+ // ScanSettings.Builder.setLegacy exists only on API 26+; below that the
401
+ // platform can only run a legacy scan, so accepting legacyScan=false would
402
+ // silently ignore the caller's extended-advertising request. Fail closed
403
+ // before any scan state is touched.
404
+ require(legacyScan || Build.VERSION.SDK_INT >= 26) {
405
+ "legacyScan=false requires ScanSettings.Builder.setLegacy (API 26+); this device cannot honour it"
406
+ }
399
407
  val normalizedServiceUuids = normalizeScanServiceUuids(serviceUuids?.toList() ?: emptyList())
400
408
  check(scanCallback == null) { "Android scan cleanup is still owned by a prior scan" }
401
409
  scanSeenDeviceIds.clear()
@@ -404,6 +412,7 @@ class OwnedAndroidGattRadio(private val context: Context) {
404
412
  val builder = ScanSettings.Builder()
405
413
  .setScanMode(
406
414
  when (scanMode) {
415
+ -1 -> ScanSettings.SCAN_MODE_OPPORTUNISTIC
407
416
  0 -> ScanSettings.SCAN_MODE_LOW_POWER
408
417
  1 -> ScanSettings.SCAN_MODE_BALANCED
409
418
  2 -> ScanSettings.SCAN_MODE_LOW_LATENCY
@@ -417,8 +426,26 @@ class OwnedAndroidGattRadio(private val context: Context) {
417
426
  }
418
427
  val settings = builder.build()
419
428
  val filters = mutableListOf<ScanFilter>()
420
- normalizedServiceUuids.forEach { uuid ->
421
- filters.add(ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid)).build())
429
+ val normalizedAddresses = deviceAddresses.map { it.uppercase() }.distinct()
430
+ if (normalizedAddresses.isEmpty()) {
431
+ normalizedServiceUuids.forEach { uuid ->
432
+ filters.add(ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid)).build())
433
+ }
434
+ } else if (normalizedServiceUuids.isEmpty()) {
435
+ normalizedAddresses.forEach { address ->
436
+ filters.add(ScanFilter.Builder().setDeviceAddress(address).build())
437
+ }
438
+ } else {
439
+ normalizedAddresses.forEach { address ->
440
+ normalizedServiceUuids.forEach { uuid ->
441
+ filters.add(
442
+ ScanFilter.Builder()
443
+ .setDeviceAddress(address)
444
+ .setServiceUuid(ParcelUuid.fromString(uuid))
445
+ .build()
446
+ )
447
+ }
448
+ }
422
449
  }
423
450
  val cb = object : ScanCallback() {
424
451
  override fun onScanResult(callbackType: Int, result: AndroidScanResult) {
@@ -67,6 +67,10 @@ struct JsiEventSinkState final {
67
67
  protocol::AndroidIngressOrdinalAllocator ingressOrdinalAllocator{1U};
68
68
  protocol::AndroidJsiBinaryCleanupLedger binaryCleanupLedger{
69
69
  kMaximumBinaryCleanupReferences};
70
+ // A record the codec refuses never reaches JavaScript, so nothing downstream
71
+ // can count it. The tally lives here so the diagnostic that replaces the
72
+ // dropped record can say how many have been lost on this attachment.
73
+ std::atomic<std::uint64_t> quarantinedRecords{0U};
70
74
  };
71
75
 
72
76
  std::mutex eventSinkStatesMutex;
@@ -1339,6 +1343,30 @@ bool deliverNativeResult(
1339
1343
  const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
1340
1344
  const protocol::ProtocolRecord& result);
1341
1345
 
1346
+ bool deliverNativeEvent(
1347
+ const std::shared_ptr<JsiEventSinkState>& state,
1348
+ const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
1349
+ const protocol::ProtocolRecord& event);
1350
+
1351
+ protocol::ProtocolRecord diagnosticEvent(
1352
+ jlong nativeHandle,
1353
+ const std::shared_ptr<JsiEventSinkState>& state,
1354
+ const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
1355
+ const std::string& code,
1356
+ const std::string& message);
1357
+
1358
+ // Report a record the codec refused. The dropped record cannot be recovered --
1359
+ // it is malformed by definition -- but the application is entitled to learn
1360
+ // that the boundary discarded something it was asked to deliver, which a
1361
+ // logcat line alone does not tell it. The diagnostic is built natively, so it
1362
+ // carries a correct version stamp and survives the validation that the
1363
+ // quarantined record failed.
1364
+ void reportQuarantinedRecord(
1365
+ jlong nativeHandle,
1366
+ const std::shared_ptr<JsiEventSinkState>& state,
1367
+ const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
1368
+ const char* reason);
1369
+
1342
1370
  bool emitRecordFromJava(JNIEnv* environment, jlong nativeHandle, jbyteArray encodedRecord) {
1343
1371
  if (encodedRecord == nullptr) {
1344
1372
  return false;
@@ -1403,6 +1431,7 @@ bool emitRecordFromJava(JNIEnv* environment, jlong nativeHandle, jbyteArray enco
1403
1431
  "UnifiedBleProtocol",
1404
1432
  "emitRecordNative quarantined invalid Android record: %s",
1405
1433
  error.what());
1434
+ reportQuarantinedRecord(nativeHandle, state, activeRuntime, error.what());
1406
1435
  if (decodedRecord.has_value() && decodedRecord->kind == protocol::RecordKind::result) {
1407
1436
  requestFatalAttachment(
1408
1437
  state,
@@ -1412,6 +1441,43 @@ bool emitRecordFromJava(JNIEnv* environment, jlong nativeHandle, jbyteArray enco
1412
1441
  }
1413
1442
  }
1414
1443
 
1444
+ void reportQuarantinedRecord(
1445
+ jlong nativeHandle,
1446
+ const std::shared_ptr<JsiEventSinkState>& state,
1447
+ const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
1448
+ const char* reason) {
1449
+ const auto quarantined = state->quarantinedRecords.fetch_add(1U) + 1U;
1450
+ try {
1451
+ if (!deliverNativeEvent(
1452
+ state,
1453
+ activeRuntime,
1454
+ diagnosticEvent(
1455
+ nativeHandle,
1456
+ state,
1457
+ activeRuntime,
1458
+ "recordQuarantined",
1459
+ std::string("Android record was quarantined and not delivered (") +
1460
+ std::to_string(quarantined) + " on this attachment): " +
1461
+ (reason == nullptr ? "unknown error" : reason)))) {
1462
+ __android_log_print(
1463
+ ANDROID_LOG_ERROR,
1464
+ "UnifiedBleProtocol",
1465
+ "Android quarantine diagnostic was rejected handle=%lld quarantined=%llu",
1466
+ static_cast<long long>(nativeHandle),
1467
+ static_cast<unsigned long long>(quarantined));
1468
+ }
1469
+ } catch (const std::exception& error) {
1470
+ // The quarantine path is already the failure path; a diagnostic that cannot
1471
+ // be built must not replace the original record's failure with its own.
1472
+ __android_log_print(
1473
+ ANDROID_LOG_ERROR,
1474
+ "UnifiedBleProtocol",
1475
+ "Android quarantine diagnostic could not be built handle=%lld: %s",
1476
+ static_cast<long long>(nativeHandle),
1477
+ error.what());
1478
+ }
1479
+ }
1480
+
1415
1481
  bool deliverNativeResult(
1416
1482
  const std::shared_ptr<JsiEventSinkState>& state,
1417
1483
  const std::shared_ptr<protocol::NativeProtocolControlRuntime>& activeRuntime,
@@ -231,6 +231,23 @@ class UnifiedBleProtocolAndroidFindingsTest {
231
231
  assertTrue(Regex("return device.getAddress\\(\\)").containsMatchIn(addressProjection))
232
232
  }
233
233
 
234
+ // Regression guard for issue #140: the dispatcher stamped a literal 1 on
235
+ // field 1 of every control-plane record while the codec required 2, so every
236
+ // result it emitted -- including the one describing a failed connect -- was
237
+ // quarantined by the native codec and never reached JavaScript. The stamp has
238
+ // to follow the generated schema, not a number typed next to the field id.
239
+ @Test
240
+ fun `dispatcher records stamp the generated protocol version`() {
241
+ val source = readAndroidSource(
242
+ "android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcher.kt"
243
+ )
244
+
245
+ assertTrue(source.contains("import com.sfourdrinier.unifiedblemanager.protocol.generated.NATIVE_PROTOCOL_VERSION"))
246
+ val stamps = Regex("""\n\s*1 to ProtocolWireValue\.UnsignedIntegerValue\((.+)\),""").findAll(source).toList()
247
+ assertTrue(stamps.isNotEmpty())
248
+ assertTrue(stamps.all { it.groupValues[1] == "NATIVE_PROTOCOL_VERSION.toLong()" })
249
+ }
250
+
234
251
  private fun readAndroidSource(relativePath: String): String {
235
252
  val candidates = listOf(
236
253
  File(relativePath),
@@ -23,10 +23,22 @@ normative behavioral authority.
23
23
  ## Contract shape and version skew
24
24
 
25
25
  `BackendProvider` reports loadability, lists adapters, requires a stable
26
- host-scoped adapter selection where necessary, and creates one backend bound to
27
- that adapter. Loadability, adapter presence, adapter power, and authorization
28
- are different states. Selecting ambiguously fails `adapter.selection-required`
29
- or `adapter.ambiguous`; a provider never chooses a convenient default.
26
+ host-scoped adapter selection, and creates one backend bound to that adapter.
27
+ Loadability, adapter presence, adapter power, and authorization are different
28
+ states. The low-level provider never silently substitutes a different adapter:
29
+ a named selection that is absent or stale fails `adapter.unavailable`.
30
+
31
+ Choosing a *default* adapter when the caller names none is an ergonomics
32
+ concern that belongs one layer up, not in the provider. The Node convenience
33
+ factories (`createBluezBleManager` and its siblings) select the first adapter,
34
+ ordered deterministically by id, so the common single-adapter machine needs no
35
+ configuration and a multi-adapter host still picks the same controller every
36
+ run; a caller targets a specific controller by passing `adapterId`. This
37
+ supersedes the earlier stance that ambiguous selection must fail: forcing every
38
+ caller to name an adapter is poor ergonomics for the common case. The
39
+ `adapter.selection-required` / `adapter.ambiguous` codes remain in the taxonomy
40
+ for a provider that genuinely cannot pick, but the first-party host factories do
41
+ not push that choice onto the caller.
30
42
 
31
43
  `BleCentralBackend` owns these required components:
32
44