unified-ble-manager 4.0.16 → 4.0.18
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 +17 -0
- package/MIGRATION_4.0.md +1 -1
- package/README.md +1 -1
- package/RELEASE.md +44 -2
- package/SBOM.cdx.json +4 -4
- package/THIRD_PARTY_LICENSES.json +1 -1
- package/android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcher.kt +4 -6
- package/android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidGattRadio.kt +1 -1
- package/android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidLog.kt +4 -0
- package/android/src/test/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcherLifecycleTest.kt +37 -1
- 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 +3 -3
- package/docs/NODE.md +1 -1
- package/docs/WEB.md +1 -1
- package/docs/generated/PLATFORM_SUPPORT.md +1 -1
- package/ios/NativeProtocol/UnifiedBleProtocolAppleExecution.mm +5 -0
- package/lib/commonjs/backends/corebluetooth/corebluetooth-backend.js +1 -1
- package/lib/commonjs/backends/corebluetooth/corebluetooth-backend.js.map +1 -1
- package/lib/commonjs/implementation-version.js +1 -1
- package/lib/module/backends/corebluetooth/corebluetooth-backend.js +1 -1
- package/lib/module/backends/corebluetooth/corebluetooth-backend.js.map +1 -1
- package/lib/module/implementation-version.js +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts +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-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/implementation-version.d.ts +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts +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-provider.d.ts +1 -1
- package/lib/typescript/module/src/implementation-version.d.ts +1 -1
- package/native/PREBUILDS.json +5 -5
- 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/winrt/prebuilds/win32-arm64/unified_ble_winrt.node +0 -0
- package/native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node +0 -0
- package/package.json +1 -1
- package/src/backends/corebluetooth/corebluetooth-backend.ts +2 -2
- package/src/implementation-version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ All notable changes to `unified-ble-manager` are documented here.
|
|
|
6
6
|
|
|
7
7
|
No changes yet.
|
|
8
8
|
|
|
9
|
+
## [4.0.18] - 2026-09-03
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- Let exactly one lifecycle path complete a React Native subscription command
|
|
14
|
+
when peer disconnection races a late CCCD callback. Android atomically
|
|
15
|
+
claims the pending command before emitting a failure, while Apple ignores
|
|
16
|
+
subscription completions from a disconnected connection generation.
|
|
17
|
+
|
|
18
|
+
## [4.0.17] - 2026-09-03
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
|
|
22
|
+
- Downgrade expected late native connect-cleanup diagnostics after caller
|
|
23
|
+
cancellation from error severity to informational telemetry, while retaining
|
|
24
|
+
the physical connection quarantine until native teardown is confirmed.
|
|
25
|
+
|
|
9
26
|
## [4.0.16] - 2026-09-03
|
|
10
27
|
|
|
11
28
|
### Fixes
|
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.18`. 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.18`. 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.
|
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` through `4.0.
|
|
84
|
+
once tagged. Stable `4.0.0` through `4.0.17` are immutable. `4.0.18` is the current train head.
|
|
85
85
|
|
|
86
86
|
```sh
|
|
87
87
|
release_candidate=4.0.0-rc.N
|
|
@@ -133,6 +133,48 @@ 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.18
|
|
137
|
+
|
|
138
|
+
The `v4.0.18` tag must identify the exact current `main` commit after canonical
|
|
139
|
+
CI passes. Do not tag the release branch directly.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
git fetch origin --tags
|
|
143
|
+
git checkout main
|
|
144
|
+
git pull --ff-only origin main
|
|
145
|
+
|
|
146
|
+
test "$(git branch --show-current)" = "main"
|
|
147
|
+
test "$(node -p "require('./package.json').version")" = "4.0.18"
|
|
148
|
+
git diff --exit-code
|
|
149
|
+
git diff --cached --exit-code
|
|
150
|
+
|
|
151
|
+
git tag -a v4.0.18 -m "v4.0.18"
|
|
152
|
+
git push origin v4.0.18
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Before tagging, confirm release-note extraction finds `## [4.0.18]`.
|
|
156
|
+
|
|
157
|
+
## Releasing 4.0.17
|
|
158
|
+
|
|
159
|
+
The `v4.0.17` tag must identify the exact current `main` commit after canonical
|
|
160
|
+
CI passes. Do not tag the release branch directly.
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
git fetch origin --tags
|
|
164
|
+
git checkout main
|
|
165
|
+
git pull --ff-only origin main
|
|
166
|
+
|
|
167
|
+
test "$(git branch --show-current)" = "main"
|
|
168
|
+
test "$(node -p "require('./package.json').version")" = "4.0.17"
|
|
169
|
+
git diff --exit-code
|
|
170
|
+
git diff --cached --exit-code
|
|
171
|
+
|
|
172
|
+
git tag -a v4.0.17 -m "v4.0.17"
|
|
173
|
+
git push origin v4.0.17
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Before tagging, confirm release-note extraction finds `## [4.0.17]`.
|
|
177
|
+
|
|
136
178
|
## Releasing 4.0.16
|
|
137
179
|
|
|
138
180
|
The `v4.0.16` tag must identify the exact current `main` commit after canonical
|
|
@@ -361,7 +403,7 @@ a green publish job and a package a consumer can actually install are not the
|
|
|
361
403
|
same claim.
|
|
362
404
|
|
|
363
405
|
```sh
|
|
364
|
-
version=4.0.
|
|
406
|
+
version=4.0.18
|
|
365
407
|
|
|
366
408
|
npm view "unified-ble-manager@$version" version
|
|
367
409
|
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.18",
|
|
10
10
|
"name": "unified-ble-manager",
|
|
11
|
-
"version": "4.0.
|
|
11
|
+
"version": "4.0.18",
|
|
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.18"
|
|
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.18",
|
|
541
541
|
"dependsOn": [
|
|
542
542
|
"pkg:npm/%40babel/runtime@7.29.7",
|
|
543
543
|
"pkg:npm/node-addon-api@8.9.0",
|
|
@@ -879,11 +879,10 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
879
879
|
message: String,
|
|
880
880
|
androidGattStatus: Int? = null
|
|
881
881
|
) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
} else if (!isPending(command)) return
|
|
882
|
+
// Claim before constructing or emitting the terminal. Link loss can race a
|
|
883
|
+
// native CCCD callback; a check followed by a later claim lets both paths
|
|
884
|
+
// publish a result for the same operation.
|
|
885
|
+
if (!claimExactPendingCommand(pendingCommands, operationKey(command), command)) return
|
|
887
886
|
val errorFields = mutableMapOf<Int, ProtocolWireValue>(
|
|
888
887
|
1 to ProtocolWireValue.StringValue(code),
|
|
889
888
|
2 to ProtocolWireValue.StringValue("android"),
|
|
@@ -908,7 +907,6 @@ class UnifiedBleProtocolAndroidDispatcher(
|
|
|
908
907
|
)
|
|
909
908
|
)
|
|
910
909
|
UnifiedBleProtocolJsiBinding.emitRecord(nativeHandle, ProtocolWireEncoder.encode(result))
|
|
911
|
-
if (!bondedPeerCommand) claimExactPendingCommand(pendingCommands, operationKey(command), command)
|
|
912
910
|
radioOperationIds.remove(operationKey(command))
|
|
913
911
|
}
|
|
914
912
|
|
package/android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidGattRadio.kt
CHANGED
|
@@ -978,7 +978,7 @@ class OwnedAndroidGattRadio(private val context: Context) {
|
|
|
978
978
|
val r =
|
|
979
979
|
Runnable {
|
|
980
980
|
if (gatts[key] === gatt) {
|
|
981
|
-
OwnedAndroidLog.
|
|
981
|
+
OwnedAndroidLog.i("GATT close safety timeout; cleanup callback absent, forced close proceeding for $key")
|
|
982
982
|
dispatchConnectionState(key, false, BluetoothGatt.GATT_FAILURE)
|
|
983
983
|
failPendingForDevice(key, "disconnected timeout")
|
|
984
984
|
val teardownFailure = completeGattTeardown(key, gatt)
|
|
@@ -17,6 +17,10 @@ object OwnedAndroidLog {
|
|
|
17
17
|
if (level <= Log.DEBUG) Log.d(TAG, msg)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
@JvmStatic fun i(msg: String) {
|
|
21
|
+
if (level <= Log.INFO) Log.i(TAG, msg)
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
@JvmStatic fun e(msg: String, t: Throwable? = null) {
|
|
21
25
|
try {
|
|
22
26
|
if (t != null) Log.e(TAG, msg, t) else Log.e(TAG, msg)
|
|
@@ -269,7 +269,6 @@ class UnifiedBleProtocolAndroidDispatcherLifecycleTest {
|
|
|
269
269
|
dispatcher.indexOf("private fun emitFailure"),
|
|
270
270
|
dispatcher.indexOf("private fun emitCancelled")
|
|
271
271
|
)
|
|
272
|
-
assertTrue(failure.contains("bondedPeerCommand"))
|
|
273
272
|
assertTrue(
|
|
274
273
|
failure.indexOf("claimExactPendingCommand") <
|
|
275
274
|
failure.indexOf("UnifiedBleProtocolJsiBinding.emitRecord")
|
|
@@ -281,6 +280,28 @@ class UnifiedBleProtocolAndroidDispatcherLifecycleTest {
|
|
|
281
280
|
)
|
|
282
281
|
}
|
|
283
282
|
|
|
283
|
+
@Test
|
|
284
|
+
fun cccdFailureClaimsThePendingCommandBeforeEmittingItsTerminal() {
|
|
285
|
+
val dispatcher = readAndroidSource(
|
|
286
|
+
"android/src/main/java/com/sfourdrinier/unifiedblemanager/protocol/UnifiedBleProtocolAndroidDispatcher.kt"
|
|
287
|
+
)
|
|
288
|
+
val failure = dispatcher.substring(
|
|
289
|
+
dispatcher.indexOf("private fun emitFailure"),
|
|
290
|
+
dispatcher.indexOf("private fun emitCancelled")
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
// Link loss and the CCCD callback can run concurrently. Claiming before
|
|
294
|
+
// emission makes the first terminal the owner; a late subscriptionFailed
|
|
295
|
+
// callback must not pass a check-then-emit race and publish a duplicate.
|
|
296
|
+
val claimIndex = failure.indexOf(
|
|
297
|
+
"if (!claimExactPendingCommand(pendingCommands, operationKey(command), command)) return",
|
|
298
|
+
failure.indexOf("Claim before constructing")
|
|
299
|
+
)
|
|
300
|
+
val emitIndex = failure.indexOf("UnifiedBleProtocolJsiBinding.emitRecord")
|
|
301
|
+
assertTrue(claimIndex >= 0)
|
|
302
|
+
assertTrue(claimIndex < emitIndex)
|
|
303
|
+
}
|
|
304
|
+
|
|
284
305
|
@Test
|
|
285
306
|
fun bondedPeerSnapshotBridgeHasAnOwnedRadioAndDispatcherRoute() {
|
|
286
307
|
val radio = readAndroidSource(
|
|
@@ -839,6 +860,21 @@ class UnifiedBleProtocolAndroidDispatcherLifecycleTest {
|
|
|
839
860
|
assertTrue(connectionLossIndex < teardownIndex)
|
|
840
861
|
}
|
|
841
862
|
|
|
863
|
+
@Test
|
|
864
|
+
fun gattSafetyCloseTimeoutUsesInformationalDiagnostics() {
|
|
865
|
+
val radio = readAndroidSource(
|
|
866
|
+
"android/src/main/java/com/sfourdrinier/unifiedblemanager/radio/OwnedAndroidGattRadio.kt"
|
|
867
|
+
)
|
|
868
|
+
val timeout = radio.substring(
|
|
869
|
+
radio.indexOf("private fun scheduleSafeClose"),
|
|
870
|
+
radio.indexOf("private fun cancelSafeClose")
|
|
871
|
+
)
|
|
872
|
+
|
|
873
|
+
assertTrue(timeout.contains("OwnedAndroidLog.i(\"GATT close safety timeout"))
|
|
874
|
+
assertFalse(timeout.contains("OwnedAndroidLog.w(\"GATT close safety timeout"))
|
|
875
|
+
assertFalse(timeout.contains("OwnedAndroidLog.e(\"GATT close safety timeout"))
|
|
876
|
+
}
|
|
877
|
+
|
|
842
878
|
@Test
|
|
843
879
|
fun adapterLossClosesGattOwnersBeforeForwardingTheState() {
|
|
844
880
|
val radio = readAndroidSource(
|
package/docs/ELECTRON.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Main owns the radio. The renderer uses a versioned IPC client and never loads a native addon.
|
|
6
6
|
|
|
7
|
-
This source targets `4.0.
|
|
7
|
+
This source targets `4.0.18`. Tagged releases ship Node-API v8 prebuilds covering macOS and Windows `arm64`/`x64` for both Node and modern Electron.
|
|
8
8
|
|
|
9
9
|
`unified-ble-manager/electron/main` and
|
|
10
10
|
`unified-ble-manager/electron/renderer` are the only Electron entrypoints.
|
package/docs/EXPO_PLUGIN.md
CHANGED
|
@@ -7,7 +7,7 @@ start a radio, request runtime permissions during prebuild, or prove physical
|
|
|
7
7
|
radio/restoration reliability. Expo Go is not a supported BLE execution
|
|
8
8
|
environment because it cannot contain this native module.
|
|
9
9
|
|
|
10
|
-
Use the v2 plugin options in this `4.0.
|
|
10
|
+
Use the v2 plugin options in this `4.0.18` source. Those options match
|
|
11
11
|
the schema introduced at `4.0.0-rc.4`. Expo Go cannot load this native module.
|
|
12
12
|
|
|
13
13
|
## Installation and development build
|
package/docs/GAPS.4.0.md
CHANGED
|
@@ -14,7 +14,7 @@ This file tracks platform code, CI, package, lab, and live-radio evidence. It do
|
|
|
14
14
|
|
|
15
15
|
The clean-baseline contract, unified core, public manager, deterministic backend, TCK, native protocol, first-party backend implementations, host-isolated package exports, SDK/CLI, and legacy-absence gates exist in the 4.0 source. Passing deterministic, compile, ABI, or package tests are implementation proof; they do not become physical-radio support evidence unless a retained record proves the corresponding live scenario.
|
|
16
16
|
|
|
17
|
-
This source targets `unified-ble-manager@4.0.
|
|
17
|
+
This source targets `unified-ble-manager@4.0.18`; the npm registry and release
|
|
18
18
|
provenance, not a source version string, determine whether it is published.
|
|
19
19
|
Earlier stable releases remain immutable published history. Backend support labels remain
|
|
20
20
|
evidence-derived. This package does not rewrite the evidence inventory: a backend remains at the support level
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
This page gets you to a first scan, connect, read, notify, and teardown on React Native. Other hosts are linked at the bottom. The root import does not turn Bluetooth on.
|
|
6
6
|
|
|
7
|
-
This source targets `4.0.
|
|
7
|
+
This source targets `4.0.18`; verify the published version in the npm registry.
|
|
8
8
|
|
|
9
9
|
## Pick a host
|
|
10
10
|
|
|
@@ -38,11 +38,11 @@ request runtime permissions on Android 12+, add
|
|
|
38
38
|
#### Expo / CNG v2
|
|
39
39
|
|
|
40
40
|
The Expo v2 schema and `unified-ble-manager/expo` factory are in this source.
|
|
41
|
-
After the npm registry lists `4.0.
|
|
41
|
+
After the npm registry lists `4.0.18`, install that exact version and keep it in
|
|
42
42
|
your lockfile while validating the native build:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
-
pnpm add unified-ble-manager@4.0.
|
|
45
|
+
pnpm add unified-ble-manager@4.0.18
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
The package does not run in Expo Go.
|
package/docs/NODE.md
CHANGED
|
@@ -10,7 +10,7 @@ The root import does not open an adapter. Pick one backend:
|
|
|
10
10
|
| `unified-ble-manager/node/winrt` | Windows |
|
|
11
11
|
| `unified-ble-manager/node/bluez` | Linux (needs `dbus-next@^0.10.2` in the app) |
|
|
12
12
|
|
|
13
|
-
This source targets `4.0.
|
|
13
|
+
This source targets `4.0.18`. Tagged releases ship Node-API v8 prebuilds for macOS and Windows on `arm64` and `x64`. A normal install should not compile native code. BlueZ talks D-Bus and has no addon.
|
|
14
14
|
|
|
15
15
|
## One-call factories
|
|
16
16
|
|
package/docs/WEB.md
CHANGED
|
@@ -6,7 +6,7 @@ Use `unified-ble-manager/web` to run the public UBM manager directly in a browse
|
|
|
6
6
|
|
|
7
7
|
The complete runnable TypeScript/Vite application is in [`example-web/`](../example-web/).
|
|
8
8
|
|
|
9
|
-
This guide targets `4.0.
|
|
9
|
+
This guide targets `4.0.18`. Web Bluetooth support still depends on the browser, operating system, adapter, and peripheral. UBM reports those runtime boundaries; it does not fabricate a fallback backend.
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ This page is generated by `scripts/docs/generate-platform-support.js` from valid
|
|
|
6
6
|
|
|
7
7
|
## Current package
|
|
8
8
|
|
|
9
|
-
`unified-ble-manager@4.0.
|
|
9
|
+
`unified-ble-manager@4.0.18`
|
|
10
10
|
|
|
11
11
|
No evidence record is bound to this exact package version and artifact. Consequently, this generated page makes no Preview, Live Preview, Supported, or Reliability-qualified platform claim for the current package.
|
|
12
12
|
|
|
@@ -1400,6 +1400,11 @@ void dispatchCommand(
|
|
|
1400
1400
|
const auto subscription = requiredString(command, 7U);
|
|
1401
1401
|
const auto subscriptionIdentifier = [NSString stringWithUTF8String:subscription.c_str()];
|
|
1402
1402
|
void (^completion)(NSError*) = ^(NSError* error) {
|
|
1403
|
+
// CoreBluetooth can complete a CCCD write after didDisconnect. The
|
|
1404
|
+
// disconnect path removes this connection generation before publishing
|
|
1405
|
+
// its event, so suppress any completion that is now stale and let the
|
|
1406
|
+
// boundary's connectionLost terminal own the pending operation.
|
|
1407
|
+
if (!currentConnectionGenerationMatches(state, endpoint.peer, endpoint.connectionGeneration)) return;
|
|
1403
1408
|
if (error == nil) static_cast<void>(success(state, command));
|
|
1404
1409
|
else fail(state, command, "subscriptionFailed", error);
|
|
1405
1410
|
};
|
|
@@ -708,7 +708,7 @@ class CoreBluetoothBackend {
|
|
|
708
708
|
if (this.boundary.connectionState(nativePeerId) === 'disconnected') return;
|
|
709
709
|
const released = await (0, _corebluetoothLateConnectCleanup.releaseLateCoreBluetoothConnection)(this.boundary, this.connectionsByNativeId, record);
|
|
710
710
|
if (!released) {
|
|
711
|
-
console.
|
|
711
|
+
console.info(`${this.diagnosticTag('connect')} Cancelled native connection cleanup is not yet confirmed; quarantine retained:`, record.nativePeerId);
|
|
712
712
|
}
|
|
713
713
|
};
|
|
714
714
|
try {
|