unified-ble-manager 4.0.25 → 4.0.27

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 (58) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/MIGRATION_4.0.md +1 -1
  3. package/README.md +1 -1
  4. package/RELEASE.md +19 -3
  5. package/SBOM.cdx.json +4 -4
  6. package/THIRD_PARTY_LICENSES.json +1 -1
  7. package/docs/ELECTRON.md +1 -1
  8. package/docs/EXPO_PLUGIN.md +1 -1
  9. package/docs/GAPS.4.0.md +1 -1
  10. package/docs/GETTING_STARTED.md +3 -3
  11. package/docs/NODE.md +1 -1
  12. package/docs/WEB.md +1 -1
  13. package/docs/generated/PLATFORM_SUPPORT.md +1 -1
  14. package/lib/commonjs/backend-contract/index.js +7 -0
  15. package/lib/commonjs/backend-contract/index.js.map +1 -1
  16. package/lib/commonjs/backend-contract/security.js +10 -0
  17. package/lib/commonjs/backend-contract/security.js.map +1 -1
  18. package/lib/commonjs/implementation-version.js +1 -1
  19. package/lib/commonjs/tck/runner-public-scenarios.js +17 -2
  20. package/lib/commonjs/tck/runner-public-scenarios.js.map +1 -1
  21. package/lib/module/backend-contract/index.js +1 -0
  22. package/lib/module/backend-contract/index.js.map +1 -1
  23. package/lib/module/backend-contract/security.js +11 -0
  24. package/lib/module/backend-contract/security.js.map +1 -1
  25. package/lib/module/implementation-version.js +1 -1
  26. package/lib/module/tck/runner-public-scenarios.js +17 -2
  27. package/lib/module/tck/runner-public-scenarios.js.map +1 -1
  28. package/lib/typescript/commonjs/src/backend-contract/index.d.ts +1 -0
  29. package/lib/typescript/commonjs/src/backend-contract/index.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/src/backend-contract/security.d.ts.map +1 -1
  31. package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
  32. package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
  33. package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
  34. package/lib/typescript/commonjs/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
  35. package/lib/typescript/commonjs/src/backends/winrt/winrt-provider.d.ts +1 -1
  36. package/lib/typescript/commonjs/src/implementation-version.d.ts +1 -1
  37. package/lib/typescript/commonjs/src/tck/runner-public-scenarios.d.ts.map +1 -1
  38. package/lib/typescript/module/src/backend-contract/index.d.ts +1 -0
  39. package/lib/typescript/module/src/backend-contract/index.d.ts.map +1 -1
  40. package/lib/typescript/module/src/backend-contract/security.d.ts.map +1 -1
  41. package/lib/typescript/module/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
  42. package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
  43. package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
  44. package/lib/typescript/module/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
  45. package/lib/typescript/module/src/backends/winrt/winrt-provider.d.ts +1 -1
  46. package/lib/typescript/module/src/implementation-version.d.ts +1 -1
  47. package/lib/typescript/module/src/tck/runner-public-scenarios.d.ts.map +1 -1
  48. package/native/PREBUILDS.json +5 -5
  49. package/native/electron/corebluetooth/prebuilds/darwin-arm64/unified_ble_corebluetooth.node +0 -0
  50. package/native/electron/corebluetooth/prebuilds/darwin-x64/unified_ble_corebluetooth.node +0 -0
  51. package/native/electron/winrt/prebuilds/win32-arm64/unified_ble_winrt.node +0 -0
  52. package/native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node +0 -0
  53. package/native/tauri/src/btleplug_dispatcher.rs +18 -3
  54. package/package.json +1 -1
  55. package/src/backend-contract/index.ts +1 -0
  56. package/src/backend-contract/security.ts +11 -0
  57. package/src/implementation-version.ts +1 -1
  58. package/src/tck/runner-public-scenarios.ts +21 -5
package/CHANGELOG.md CHANGED
@@ -6,6 +6,37 @@ All notable changes to `unified-ble-manager` are documented here.
6
6
 
7
7
  No changes yet.
8
8
 
9
+ ## [4.0.27] - 2026-09-06
10
+
11
+ ### Fixes
12
+
13
+ - Tauri continuous scans now pace synthetic peripheral-inventory snapshots at
14
+ two-second intervals instead of replaying the full inventory four times per
15
+ second. Real btleplug advertisement events remain event-driven. This keeps
16
+ discovery live when platform events are silent or closed while sharply reducing
17
+ bounded IPC pressure without suppressing real `duplicates: "all"` reports.
18
+ Slow inventory work delays the next poll instead of triggering catch-up bursts.
19
+
20
+ ## [4.0.26] - 2026-09-06
21
+
22
+ ### Fixes
23
+
24
+ - A third-party backend can now follow, and pass, the cancellation contract
25
+ 4.0.7 introduced. `cancelOutcomeForPairResult` was exported from
26
+ `backend-contract/security` but re-exported type-only from the barrel, so it
27
+ never reached `/backend-sdk`; first-party backends imported it by deep
28
+ relative path and nothing failed. The TCK still hard-required
29
+ `outcome === 'cancelled'` from both `pair()` and `cancelPairing()`, so a
30
+ backend that correctly reported `'paired'` when the bond won the race failed
31
+ `security-pairing-cancellation-cleans-up` while conforming. The scenario now
32
+ asserts that the two calls do not contradict each other about one pairing,
33
+ checked through the shared mapper rather than against a fixed word.
34
+ `cancelOutcomeForPairResult` also gains a `default` branch so an out-of-contract
35
+ outcome from a third-party backend is named as `protocol.violation` instead of
36
+ surfacing as `undefined` and a raw TypeError several frames away. The `default`
37
+ routes through a `never` parameter, so a new first-party `SecurityPairResult`
38
+ variant is still a compile error (#167).
39
+
9
40
  ## [4.0.25] - 2026-09-05
10
41
 
11
42
  ### 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.25`. 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
+ This source targets `4.0.27`. 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.25`. Install the exact version shown in the npm
21
+ This source tree is versioned `4.0.27`. 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
@@ -83,8 +83,8 @@ On release day, set `release_candidate` to the exact candidate required by the
83
83
  release plan. RC2, RC3, RC4, `4.0.0-rc.4.1`, and RC5 are already immutable
84
84
  once tagged. Stable `4.0.0` through `4.0.20` are immutable. The unpublished
85
85
  `v4.0.21` tag is also immutable after its cancelled workflow. `4.0.22`,
86
- `4.0.23`, and `4.0.24` are immutable tagged history. This branch prepares
87
- `4.0.25`.
86
+ `4.0.23`, `4.0.24`, `4.0.25`, and `4.0.26` are immutable tagged history. This
87
+ branch prepares `4.0.27`.
88
88
 
89
89
  ```sh
90
90
  release_candidate=4.0.0-rc.N
@@ -112,6 +112,22 @@ The first stable tag `v4.0.0` is immutable published history. Do not recreate or
112
112
  git tag -a v4.0.0 -m "v4.0.0"
113
113
  ```
114
114
 
115
+ ## Releasing 4.0.27
116
+
117
+ Release `v4.0.27` only from the exact current `main` commit after its canonical
118
+ CI succeeds. Verify `package.json` is `4.0.27`, the worktree is clean, and
119
+ release-note extraction finds `## [4.0.27]`. Push a new annotated `v4.0.27`
120
+ tag; never move the immutable `v4.0.26` tag. Follow the required local validation,
121
+ publish workflow, and registry verification below.
122
+
123
+ ## Releasing 4.0.26
124
+
125
+ Release `v4.0.26` only from the exact current `main` commit after its canonical
126
+ CI succeeds. Verify `package.json` is `4.0.26`, the worktree is clean, and
127
+ release-note extraction finds `## [4.0.26]`. Push a new annotated `v4.0.26`
128
+ tag; never move the immutable `v4.0.25` tag. Follow the required local validation,
129
+ publish workflow, and registry verification below.
130
+
115
131
  ## Releasing 4.0.25
116
132
 
117
133
  Release `v4.0.25` only from the exact current `main` commit after its canonical
@@ -500,7 +516,7 @@ a green publish job and a package a consumer can actually install are not the
500
516
  same claim.
501
517
 
502
518
  ```sh
503
- version=4.0.25
519
+ version=4.0.27
504
520
 
505
521
  npm view "unified-ble-manager@$version" version
506
522
  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.25",
9
+ "bom-ref": "pkg:npm/unified-ble-manager@4.0.27",
10
10
  "name": "unified-ble-manager",
11
- "version": "4.0.25",
11
+ "version": "4.0.27",
12
12
  "licenses": [
13
13
  {
14
14
  "expression": "Apache-2.0"
15
15
  }
16
16
  ],
17
- "purl": "pkg:npm/unified-ble-manager@4.0.25"
17
+ "purl": "pkg:npm/unified-ble-manager@4.0.27"
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.25",
540
+ "ref": "pkg:npm/unified-ble-manager@4.0.27",
541
541
  "dependsOn": [
542
542
  "pkg:npm/%40babel/runtime@7.29.7",
543
543
  "pkg:npm/node-addon-api@8.9.0",
@@ -4,7 +4,7 @@
4
4
  "schemaVersion": "1.0.0",
5
5
  "package": {
6
6
  "name": "unified-ble-manager",
7
- "version": "4.0.25"
7
+ "version": "4.0.27"
8
8
  },
9
9
  "source": {
10
10
  "method": "pnpm-lock production graph with installed-manifest license audit",
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.25`. Tagged releases ship Node-API v8 prebuilds covering macOS and Windows `arm64`/`x64` for both Node and modern Electron.
7
+ This source targets `4.0.27`. 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.
@@ -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.25` source. Those options match
10
+ Use the v2 plugin options in this `4.0.27` 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.25`; the npm registry and release
17
+ This source targets `unified-ble-manager@4.0.27`; 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
@@ -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.25`; verify the published version in the npm registry.
7
+ This source targets `4.0.27`; 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.25`, install that exact version and keep it in
41
+ After the npm registry lists `4.0.27`, 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.25
45
+ pnpm add unified-ble-manager@4.0.27
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.25`. 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.
13
+ This source targets `4.0.27`. 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.25`. 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.
9
+ This guide targets `4.0.27`. 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.25`
9
+ `unified-ble-manager@4.0.27`
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
 
@@ -99,6 +99,12 @@ Object.defineProperty(exports, "byteLimit", {
99
99
  return _primitives.byteLimit;
100
100
  }
101
101
  });
102
+ Object.defineProperty(exports, "cancelOutcomeForPairResult", {
103
+ enumerable: true,
104
+ get: function () {
105
+ return _security.cancelOutcomeForPairResult;
106
+ }
107
+ });
102
108
  Object.defineProperty(exports, "canonicalUuid", {
103
109
  enumerable: true,
104
110
  get: function () {
@@ -310,6 +316,7 @@ Object.defineProperty(exports, "versionRange", {
310
316
  }
311
317
  });
312
318
  var _backend = require("./backend.js");
319
+ var _security = require("./security.js");
313
320
  var _peerReference = require("./peer-reference.js");
314
321
  var _capabilities = require("./capabilities.js");
315
322
  var _errors = require("./errors.js");
@@ -1 +1 @@
1
- {"version":3,"names":["_backend","require","_peerReference","_capabilities","_errors","_gatt","_identity","_ipc","_operations","_primitives","_recovery","_scanPlanning"],"sourceRoot":"../../../src","sources":["backend-contract/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6EA,IAAAA,QAAA,GAAAC,OAAA;AAmBA,IAAAC,cAAA,GAAAD,OAAA;AAsBA,IAAAE,aAAA,GAAAF,OAAA;AAuBA,IAAAG,OAAA,GAAAH,OAAA;AAwBA,IAAAI,KAAA,GAAAJ,OAAA;AAyBA,IAAAK,SAAA,GAAAL,OAAA;AASA,IAAAM,IAAA,GAAAN,OAAA;AAyBA,IAAAO,WAAA,GAAAP,OAAA;AAwDA,IAAAQ,WAAA,GAAAR,OAAA;AAwCA,IAAAS,SAAA,GAAAT,OAAA;AAkBA,IAAAU,aAAA,GAAAV,OAAA","ignoreList":[]}
1
+ {"version":3,"names":["_backend","require","_security","_peerReference","_capabilities","_errors","_gatt","_identity","_ipc","_operations","_primitives","_recovery","_scanPlanning"],"sourceRoot":"../../../src","sources":["backend-contract/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6EA,IAAAA,QAAA,GAAAC,OAAA;AAmBA,IAAAC,SAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;AAsBA,IAAAG,aAAA,GAAAH,OAAA;AAuBA,IAAAI,OAAA,GAAAJ,OAAA;AAwBA,IAAAK,KAAA,GAAAL,OAAA;AAyBA,IAAAM,SAAA,GAAAN,OAAA;AASA,IAAAO,IAAA,GAAAP,OAAA;AAyBA,IAAAQ,WAAA,GAAAR,OAAA;AAwDA,IAAAS,WAAA,GAAAT,OAAA;AAwCA,IAAAU,SAAA,GAAAV,OAAA;AAkBA,IAAAW,aAAA,GAAAX,OAAA","ignoreList":[]}
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.cancelOutcomeForPairResult = cancelOutcomeForPairResult;
7
+ var _errors = require("./errors.js");
7
8
  /**
8
9
  * What a cancellation actually achieved, not what it requested.
9
10
  *
@@ -55,6 +56,15 @@ function cancelOutcomeForPairResult(result) {
55
56
  return {
56
57
  outcome: 'cancelled'
57
58
  };
59
+ default:
60
+ return unreachableCancelPairOutcome(result);
58
61
  }
59
62
  }
63
+ function unreachableCancelPairOutcome(_result) {
64
+ // Unreachable for a compliant backend. Typing `_result` as `never` keeps a
65
+ // new SecurityPairResult variant a compile error; types erase, so a
66
+ // third-party invented outcome still throws instead of returning `undefined`
67
+ // and a raw TypeError several frames away.
68
+ throw (0, _errors.contractError)('protocol.violation', 'core', 'security.cancel-pairing.outcome');
69
+ }
60
70
  //# sourceMappingURL=security.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["cancelOutcomeForPairResult","result","outcome","reason"],"sourceRoot":"../../../src","sources":["backend-contract/security.ts"],"mappings":";;;;;;AA6FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,0BAA0BA,CAACC,MAA0B,EAA+B;EAClG,QAAQA,MAAM,CAACC,OAAO;IACpB;IACA;IACA,KAAK,QAAQ;IACb,KAAK,gBAAgB;IACrB,KAAK,UAAU;MACb,OAAO;QAAEA,OAAO,EAAE;MAAS,CAAC;IAC9B;IACA;IACA,KAAK,UAAU;MACb,OAAO;QAAEA,OAAO,EAAE,UAAU;QAAEC,MAAM,EAAEF,MAAM,CAACE;MAAO,CAAC;IACvD,KAAK,WAAW;MACd,OAAO;QAAED,OAAO,EAAE;MAAY,CAAC;EACnC;AACF","ignoreList":[]}
1
+ {"version":3,"names":["_errors","require","cancelOutcomeForPairResult","result","outcome","reason","unreachableCancelPairOutcome","_result","contractError"],"sourceRoot":"../../../src","sources":["backend-contract/security.ts"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AA8FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,0BAA0BA,CAACC,MAA0B,EAA+B;EAClG,QAAQA,MAAM,CAACC,OAAO;IACpB;IACA;IACA,KAAK,QAAQ;IACb,KAAK,gBAAgB;IACrB,KAAK,UAAU;MACb,OAAO;QAAEA,OAAO,EAAE;MAAS,CAAC;IAC9B;IACA;IACA,KAAK,UAAU;MACb,OAAO;QAAEA,OAAO,EAAE,UAAU;QAAEC,MAAM,EAAEF,MAAM,CAACE;MAAO,CAAC;IACvD,KAAK,WAAW;MACd,OAAO;QAAED,OAAO,EAAE;MAAY,CAAC;IACjC;MACE,OAAOE,4BAA4B,CAACH,MAAM,CAAC;EAC/C;AACF;AAEA,SAASG,4BAA4BA,CAACC,OAAc,EAAS;EAC3D;EACA;EACA;EACA;EACA,MAAM,IAAAC,qBAAa,EAAC,oBAAoB,EAAE,MAAM,EAAE,iCAAiC,CAAC;AACtF","ignoreList":[]}
@@ -7,5 +7,5 @@ exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = void 0;
7
7
  // src/implementation-version.ts
8
8
 
9
9
  /** The one production version stamped into every first-party backend identity. */
10
- const UNIFIED_BLE_IMPLEMENTATION_VERSION = exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.25';
10
+ const UNIFIED_BLE_IMPLEMENTATION_VERSION = exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.27';
11
11
  //# sourceMappingURL=implementation-version.js.map
@@ -8,6 +8,7 @@ var _capabilities = require("../backend-contract/capabilities.js");
8
8
  var _connectionControls = require("../backend-contract/connection-controls.js");
9
9
  var _errors = require("../backend-contract/errors.js");
10
10
  var _primitives = require("../backend-contract/primitives.js");
11
+ var _security = require("../backend-contract/security.js");
11
12
  var _bleManager = require("../manager/ble-manager.js");
12
13
  var _contracts = require("./contracts.js");
13
14
  var _runnerPublicScenarioSupport = require("./runner-public-scenario-support.js");
@@ -24,6 +25,20 @@ const publicScenarioId = 'manager.scan-connect-discover-read-notify-destroy';
24
25
  const publicScenarioFact = 'scan-connect-discover-read-notify-destroy-completes';
25
26
  const publicScenarioDefinitionId = 'scenario.scan-connect-discover-read-notify-destroy';
26
27
 
28
+ /**
29
+ * A conformant backend agrees with itself about one pairing.
30
+ *
31
+ * This used to require `'cancelled'` from both calls, which made the suite
32
+ * penalise a backend for being correct: when the bond wins the race, the
33
+ * contract requires `pair()` to report `paired` and `cancelPairing()` to
34
+ * report `paired` - and the old assertion failed exactly that. What matters is
35
+ * not which word appears but that the two calls do not contradict each other,
36
+ * so the check is the shared mapper the contract is defined by.
37
+ */
38
+ function cancellationIsConsistent(cancelled, cancelledPair) {
39
+ return (0, _security.cancelOutcomeForPairResult)(cancelledPair).outcome === cancelled.outcome;
40
+ }
41
+
27
42
  /**
28
43
  * Executes the public manager vertical slice over the exact backend owned by
29
44
  * this runner fixture. Facts are emitted only after every public operation and
@@ -267,7 +282,7 @@ async function executeSecurityScenario(manager, fixture) {
267
282
  }), (0, _runnerPublicScenarioSupport.fact)('security-custom-challenge-is-bounded', !customCeremonySupported || custom.outcome === 'already-paired' || custom.outcome === 'paired', {
268
283
  outcome: custom.outcome,
269
284
  supported: customCeremonySupported
270
- }), (0, _runnerPublicScenarioSupport.fact)('security-pairing-cancellation-cleans-up', cancelled.outcome === 'cancelled' && cancelledPair.outcome === 'cancelled' && afterCancellation.outcome === 'not-pairing', {
285
+ }), (0, _runnerPublicScenarioSupport.fact)('security-pairing-cancellation-cleans-up', cancellationIsConsistent(cancelled, cancelledPair) && afterCancellation.outcome === 'not-pairing', {
271
286
  cancelled: cancelled.outcome,
272
287
  cancelledPair: cancelledPair.outcome,
273
288
  afterCancellation: afterCancellation.outcome,
@@ -336,7 +351,7 @@ async function executeSystemOnlySecurityScenario(manager, fixture, securityAdapt
336
351
  }), (0, _runnerPublicScenarioSupport.fact)('security-custom-challenge-is-bounded', true, {
337
352
  supported: false,
338
353
  reason: 'BlueZ Agent1 custom ceremony is intentionally unsupported in this slice'
339
- }), (0, _runnerPublicScenarioSupport.fact)('security-pairing-cancellation-cleans-up', !supportsCancellation || cancelled?.outcome === 'cancelled' && cancelledPair?.outcome === 'cancelled' && afterCancellation?.outcome === 'not-pairing', {
354
+ }), (0, _runnerPublicScenarioSupport.fact)('security-pairing-cancellation-cleans-up', !supportsCancellation || cancelled !== null && cancelled !== undefined && cancelledPair !== null && cancelledPair !== undefined && cancellationIsConsistent(cancelled, cancelledPair) && afterCancellation?.outcome === 'not-pairing', {
340
355
  cancelled: cancelled?.outcome ?? null,
341
356
  cancelledPair: cancelledPair?.outcome ?? null,
342
357
  afterCancellation: afterCancellation?.outcome ?? null,