@onekeyfe/hd-transport-react-native 1.2.0-alpha.62 → 1.2.0-alpha.64

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/dist/index.d.ts CHANGED
@@ -64,6 +64,14 @@ declare function getProtocolV2BleTuning(): {
64
64
  * inside the native budget, so this only fires when the native timeout did not.
65
65
  */
66
66
  declare const BLE_CONNECT_TIMEOUT_MS: number;
67
+ /**
68
+ * How many times a known device may fail its own protocol before we probe the others
69
+ * again. Reconnect polling during a device reboot repeats this every few seconds, and
70
+ * probing Protocol V2 costs a 10s Ping timeout, so paying it on every attempt for a
71
+ * device we just spoke V1 to dominates the wait. A firmware update can legitimately
72
+ * change a device's protocol, so the shortcut has to expire rather than stick.
73
+ */
74
+ declare const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
67
75
  /** Consecutive connect timeouts on one device before the BLE manager itself is recreated. */
68
76
  declare const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
69
77
  type IOneKeyDevice = OneKeyDeviceInfoBase & Device;
@@ -94,6 +102,10 @@ declare class ReactNativeBleTransport {
94
102
  /** Consecutive connect timeouts per device; reset by any connect that settles. */
95
103
  private connectTimeoutCounts;
96
104
  private deviceProtocolHints;
105
+ /** Protocol this device actually answered on, kept across reconnects of one session. */
106
+ private sessionProtocols;
107
+ /** Consecutive detections that failed while trusting sessionProtocols. */
108
+ private protocolReprobeFailures;
97
109
  private protocolV2Assemblers;
98
110
  private protocolV2FrameQueues;
99
111
  private protocolV2FramePromises;
@@ -178,4 +190,4 @@ declare class ReactNativeBleTransport {
178
190
  getProtocolType(path: string): ProtocolType | undefined;
179
191
  }
180
192
 
181
- export { BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD, BLE_CONNECT_TIMEOUT_MS, BLE_WRITE_PACKET_TIMEOUT_MS, BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD, IOneKeyDevice, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
193
+ export { BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD, BLE_CONNECT_TIMEOUT_MS, BLE_WRITE_PACKET_TIMEOUT_MS, BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD, IOneKeyDevice, PROTOCOL_REPROBE_FALLBACK_ATTEMPTS, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -295,6 +295,7 @@ const fallbackConnectOptions = {
295
295
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
296
296
  };
297
297
  const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
298
+ const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
298
299
  const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
299
300
  const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
300
301
  const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
@@ -361,6 +362,8 @@ class ReactNativeBleTransport {
361
362
  this.writeTimeoutCounts = new Map();
362
363
  this.connectTimeoutCounts = new Map();
363
364
  this.deviceProtocolHints = new Map();
365
+ this.sessionProtocols = new Map();
366
+ this.protocolReprobeFailures = new Map();
364
367
  this.protocolV2Assemblers = new Map();
365
368
  this.protocolV2FrameQueues = new Map();
366
369
  this.protocolV2FramePromises = new Map();
@@ -1304,6 +1307,8 @@ class ReactNativeBleTransport {
1304
1307
  this.deviceProtocol.delete(session);
1305
1308
  this.probingProtocols.delete(session);
1306
1309
  this.deviceProtocolHints.delete(session);
1310
+ this.sessionProtocols.delete(session);
1311
+ this.protocolReprobeFailures.delete(session);
1307
1312
  this.protocolV2Assemblers.delete(session);
1308
1313
  this.resetProtocolV2Frames(session);
1309
1314
  try {
@@ -1450,6 +1455,8 @@ class ReactNativeBleTransport {
1450
1455
  });
1451
1456
  this.deviceProtocol.clear();
1452
1457
  this.probingProtocols.clear();
1458
+ this.sessionProtocols.clear();
1459
+ this.protocolReprobeFailures.clear();
1453
1460
  this.monitorTokens.clear();
1454
1461
  this.protocolV2Assemblers.clear();
1455
1462
  try {
@@ -1478,10 +1485,12 @@ class ReactNativeBleTransport {
1478
1485
  return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
1479
1486
  }
1480
1487
  detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
1488
+ var _a;
1481
1489
  return __awaiter(this, void 0, void 0, function* () {
1482
1490
  if (expectedProtocol === 'V1') {
1483
1491
  if (yield this.probeProtocolV1(uuid)) {
1484
1492
  this.deviceProtocol.set(uuid, 'V1');
1493
+ this.sessionProtocols.set(uuid, 'V1');
1485
1494
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1486
1495
  deviceId: uuid,
1487
1496
  protocol: 'V1',
@@ -1494,6 +1503,7 @@ class ReactNativeBleTransport {
1494
1503
  if (expectedProtocol === 'V2') {
1495
1504
  if (yield this.probeProtocolV2(uuid)) {
1496
1505
  this.deviceProtocol.set(uuid, 'V2');
1506
+ this.sessionProtocols.set(uuid, 'V2');
1497
1507
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1498
1508
  deviceId: uuid,
1499
1509
  protocol: 'V2',
@@ -1503,7 +1513,13 @@ class ReactNativeBleTransport {
1503
1513
  }
1504
1514
  throw this.createProtocolMismatchError(expectedProtocol);
1505
1515
  }
1506
- const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1516
+ const sessionProtocol = this.sessionProtocols.get(uuid);
1517
+ const reprobeFailures = (_a = this.protocolReprobeFailures.get(uuid)) !== null && _a !== void 0 ? _a : 0;
1518
+ const fullProbeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1519
+ const trustSessionProtocol = sessionProtocol !== undefined &&
1520
+ !protocolHint &&
1521
+ reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
1522
+ const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
1507
1523
  for (let i = 0; i < probeOrder.length; i += 1) {
1508
1524
  const protocol = probeOrder[i];
1509
1525
  if (i > 0) {
@@ -1518,6 +1534,8 @@ class ReactNativeBleTransport {
1518
1534
  const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
1519
1535
  if (detected) {
1520
1536
  this.deviceProtocol.set(uuid, protocol);
1537
+ this.sessionProtocols.set(uuid, protocol);
1538
+ this.protocolReprobeFailures.delete(uuid);
1521
1539
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1522
1540
  deviceId: uuid,
1523
1541
  protocol,
@@ -1526,6 +1544,12 @@ class ReactNativeBleTransport {
1526
1544
  return protocol;
1527
1545
  }
1528
1546
  }
1547
+ if (trustSessionProtocol) {
1548
+ this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
1549
+ }
1550
+ else {
1551
+ this.protocolReprobeFailures.delete(uuid);
1552
+ }
1529
1553
  this.deviceProtocol.delete(uuid);
1530
1554
  this.probingProtocols.delete(uuid);
1531
1555
  throw this.createProtocolDetectionError();
@@ -1825,6 +1849,7 @@ exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGE
1825
1849
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
1826
1850
  exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
1827
1851
  exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
1852
+ exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
1828
1853
  exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
1829
1854
  exports["default"] = ReactNativeBleTransport;
1830
1855
  exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.0-alpha.62",
3
+ "version": "1.2.0-alpha.64",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,11 +20,11 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-core": "1.2.0-alpha.62",
24
- "@onekeyfe/hd-shared": "1.2.0-alpha.62",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.62",
23
+ "@onekeyfe/hd-core": "1.2.0-alpha.64",
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.64",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.64",
26
26
  "@onekeyfe/react-native-ble-utils": "^0.1.6",
27
27
  "react-native-ble-plx": "3.5.1"
28
28
  },
29
- "gitHead": "f38f4fc8bf05aea42a4da5b2bd633544597ad958"
29
+ "gitHead": "636cd3d9874820414cee6faa7e521f90a42ce6d5"
30
30
  }
@@ -0,0 +1,133 @@
1
+ import ReactNativeBleTransport, { PROTOCOL_REPROBE_FALLBACK_ATTEMPTS } from '../index';
2
+
3
+ import messages from '@onekeyfe/hd-transport/messages.json';
4
+
5
+ jest.mock(
6
+ 'react-native',
7
+ () => ({
8
+ Platform: { OS: 'ios', select: (spec: Record<string, unknown>) => spec.ios },
9
+ PermissionsAndroid: {
10
+ PERMISSIONS: {},
11
+ RESULTS: {},
12
+ request: jest.fn(),
13
+ requestMultiple: jest.fn(),
14
+ },
15
+ }),
16
+ { virtual: true }
17
+ );
18
+
19
+ jest.mock('react-native-ble-plx', () => ({
20
+ BleATTErrorCode: { InvalidHandle: 1, UnlikelyError: 14 },
21
+ BleError: Error,
22
+ BleErrorCode: { DeviceDisconnected: 201, OperationStartFailed: 601 },
23
+ BleManager: jest.fn(),
24
+ ScanMode: { LowLatency: 2 },
25
+ }));
26
+
27
+ jest.mock('@onekeyfe/react-native-ble-utils', () => ({
28
+ __esModule: true,
29
+ default: {
30
+ getConnectedPeripherals: jest.fn(() => Promise.resolve([])),
31
+ getBondedPeripherals: jest.fn(() => Promise.resolve([])),
32
+ pairDevice: jest.fn(() => Promise.resolve()),
33
+ },
34
+ }));
35
+
36
+ const UUID = 'reprobe-device';
37
+
38
+ /** Drive detectProtocol with stubbed probes so we can observe which are attempted. */
39
+ function createHarness({ v1, v2 }: { v1: boolean; v2: boolean }) {
40
+ const transport = new ReactNativeBleTransport({});
41
+ transport.configure(messages);
42
+ const probeV1 = jest.fn(() => {
43
+ if (v1) {
44
+ (transport as any).deviceProtocol.set(UUID, 'V1');
45
+ }
46
+ return Promise.resolve(v1);
47
+ });
48
+ const probeV2 = jest.fn(() => {
49
+ if (v2) {
50
+ (transport as any).deviceProtocol.set(UUID, 'V2');
51
+ }
52
+ return Promise.resolve(v2);
53
+ });
54
+ (transport as any).probeProtocolV1 = probeV1;
55
+ (transport as any).probeProtocolV2 = probeV2;
56
+ (transport as any).resetProbeStateAfterProtocolProbe = jest.fn(() => Promise.resolve());
57
+ return { transport, probeV1, probeV2 };
58
+ }
59
+
60
+ const detect = (transport: ReactNativeBleTransport) =>
61
+ (transport as any).detectProtocol(UUID, undefined, undefined, () =>
62
+ Promise.resolve()
63
+ ) as Promise<string>;
64
+
65
+ describe('protocol re-probe after a known device goes away', () => {
66
+ test('an unknown device still probes both protocols', async () => {
67
+ const { transport, probeV1, probeV2 } = createHarness({ v1: false, v2: false });
68
+
69
+ await expect(detect(transport)).rejects.toBeDefined();
70
+
71
+ expect(probeV1).toHaveBeenCalledTimes(1);
72
+ expect(probeV2).toHaveBeenCalledTimes(1);
73
+ });
74
+
75
+ test('a device already known to speak V1 does not pay the V2 probe while it is away', async () => {
76
+ const known = createHarness({ v1: true, v2: false });
77
+ // First detection confirms V1 (this is the session that just talked to the device).
78
+ await expect(detect(known.transport)).resolves.toBe('V1');
79
+
80
+ // The device now reboots after a firmware install: V1 stops answering.
81
+ (known.transport as any).deviceProtocol.delete(UUID);
82
+ const probeV1 = jest.fn(() => Promise.resolve(false));
83
+ const probeV2 = jest.fn(() => Promise.resolve(false));
84
+ (known.transport as any).probeProtocolV1 = probeV1;
85
+ (known.transport as any).probeProtocolV2 = probeV2;
86
+
87
+ await expect(detect(known.transport)).rejects.toBeDefined();
88
+
89
+ expect(probeV1).toHaveBeenCalledTimes(1);
90
+ // The 10s Protocol V2 ping is pure waste for a device we just spoke V1 to.
91
+ expect(probeV2).not.toHaveBeenCalled();
92
+ });
93
+
94
+ test('after repeated failures it re-probes every protocol again', async () => {
95
+ const known = createHarness({ v1: true, v2: false });
96
+ await expect(detect(known.transport)).resolves.toBe('V1');
97
+
98
+ (known.transport as any).deviceProtocol.delete(UUID);
99
+ const probeV1 = jest.fn(() => Promise.resolve(false));
100
+ const probeV2 = jest.fn(() => Promise.resolve(false));
101
+ (known.transport as any).probeProtocolV1 = probeV1;
102
+ (known.transport as any).probeProtocolV2 = probeV2;
103
+
104
+ for (let attempt = 0; attempt < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS; attempt += 1) {
105
+ // eslint-disable-next-line no-await-in-loop
106
+ await expect(detect(known.transport)).rejects.toBeDefined();
107
+ }
108
+ expect(probeV2).not.toHaveBeenCalled();
109
+
110
+ // The device may genuinely have changed protocol, so the shortcut must expire.
111
+ await expect(detect(known.transport)).rejects.toBeDefined();
112
+ expect(probeV2).toHaveBeenCalled();
113
+ });
114
+
115
+ test('a successful detection clears the failure streak', async () => {
116
+ const known = createHarness({ v1: true, v2: false });
117
+ await expect(detect(known.transport)).resolves.toBe('V1');
118
+ (known.transport as any).deviceProtocol.delete(UUID);
119
+
120
+ const failingV1 = jest.fn(() => Promise.resolve(false));
121
+ (known.transport as any).probeProtocolV1 = failingV1;
122
+ await expect(detect(known.transport)).rejects.toBeDefined();
123
+
124
+ // Device comes back.
125
+ (known.transport as any).probeProtocolV1 = jest.fn(() => {
126
+ (known.transport as any).deviceProtocol.set(UUID, 'V1');
127
+ return Promise.resolve(true);
128
+ });
129
+ await expect(detect(known.transport)).resolves.toBe('V1');
130
+
131
+ expect((known.transport as any).protocolReprobeFailures.get(UUID)).toBeUndefined();
132
+ });
133
+ });
package/src/index.ts CHANGED
@@ -199,6 +199,14 @@ const fallbackConnectOptions: Record<string, unknown> = {
199
199
  * inside the native budget, so this only fires when the native timeout did not.
200
200
  */
201
201
  export const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
202
+ /**
203
+ * How many times a known device may fail its own protocol before we probe the others
204
+ * again. Reconnect polling during a device reboot repeats this every few seconds, and
205
+ * probing Protocol V2 costs a 10s Ping timeout, so paying it on every attempt for a
206
+ * device we just spoke V1 to dominates the wait. A firmware update can legitimately
207
+ * change a device's protocol, so the shortcut has to expire rather than stick.
208
+ */
209
+ export const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
202
210
  /** Consecutive connect timeouts on one device before the BLE manager itself is recreated. */
203
211
  export const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
204
212
  const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
@@ -311,6 +319,12 @@ export default class ReactNativeBleTransport {
311
319
 
312
320
  private deviceProtocolHints: Map<string, ProtocolType> = new Map();
313
321
 
322
+ /** Protocol this device actually answered on, kept across reconnects of one session. */
323
+ private sessionProtocols: Map<string, ProtocolType> = new Map();
324
+
325
+ /** Consecutive detections that failed while trusting sessionProtocols. */
326
+ private protocolReprobeFailures: Map<string, number> = new Map();
327
+
314
328
  private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
315
329
 
316
330
  private protocolV2FrameQueues: Map<string, Uint8Array[]> = new Map();
@@ -1482,6 +1496,8 @@ export default class ReactNativeBleTransport {
1482
1496
  this.deviceProtocol.delete(session);
1483
1497
  this.probingProtocols.delete(session);
1484
1498
  this.deviceProtocolHints.delete(session);
1499
+ this.sessionProtocols.delete(session);
1500
+ this.protocolReprobeFailures.delete(session);
1485
1501
  this.protocolV2Assemblers.delete(session);
1486
1502
  this.resetProtocolV2Frames(session);
1487
1503
 
@@ -1674,6 +1690,8 @@ export default class ReactNativeBleTransport {
1674
1690
  });
1675
1691
  this.deviceProtocol.clear();
1676
1692
  this.probingProtocols.clear();
1693
+ this.sessionProtocols.clear();
1694
+ this.protocolReprobeFailures.clear();
1677
1695
  this.monitorTokens.clear();
1678
1696
  this.protocolV2Assemblers.clear();
1679
1697
  try {
@@ -1720,6 +1738,7 @@ export default class ReactNativeBleTransport {
1720
1738
  if (expectedProtocol === 'V1') {
1721
1739
  if (await this.probeProtocolV1(uuid)) {
1722
1740
  this.deviceProtocol.set(uuid, 'V1');
1741
+ this.sessionProtocols.set(uuid, 'V1');
1723
1742
  Log?.debug('[ReactNativeBleTransport] protocol detected', {
1724
1743
  deviceId: uuid,
1725
1744
  protocol: 'V1',
@@ -1733,6 +1752,7 @@ export default class ReactNativeBleTransport {
1733
1752
  if (expectedProtocol === 'V2') {
1734
1753
  if (await this.probeProtocolV2(uuid)) {
1735
1754
  this.deviceProtocol.set(uuid, 'V2');
1755
+ this.sessionProtocols.set(uuid, 'V2');
1736
1756
  Log?.debug('[ReactNativeBleTransport] protocol detected', {
1737
1757
  deviceId: uuid,
1738
1758
  protocol: 'V2',
@@ -1745,8 +1765,18 @@ export default class ReactNativeBleTransport {
1745
1765
 
1746
1766
  // Protocol must be actively probed after connection. Name, PID, and descriptors only
1747
1767
  // influence probe order; a V2 hint probes V2 first and falls back to V1.
1748
- const probeOrder: ProtocolType[] =
1768
+ const sessionProtocol = this.sessionProtocols.get(uuid);
1769
+ const reprobeFailures = this.protocolReprobeFailures.get(uuid) ?? 0;
1770
+ const fullProbeOrder: ProtocolType[] =
1749
1771
  protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1772
+ // A device that already answered on a protocol in this session keeps answering on
1773
+ // it; while it is rebooting nothing answers at all, so probing the other protocol
1774
+ // only adds its timeout to every poll.
1775
+ const trustSessionProtocol =
1776
+ sessionProtocol !== undefined &&
1777
+ !protocolHint &&
1778
+ reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
1779
+ const probeOrder: ProtocolType[] = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
1750
1780
 
1751
1781
  for (let i = 0; i < probeOrder.length; i += 1) {
1752
1782
  const protocol = probeOrder[i];
@@ -1764,6 +1794,8 @@ export default class ReactNativeBleTransport {
1764
1794
  protocol === 'V1' ? await this.probeProtocolV1(uuid) : await this.probeProtocolV2(uuid);
1765
1795
  if (detected) {
1766
1796
  this.deviceProtocol.set(uuid, protocol);
1797
+ this.sessionProtocols.set(uuid, protocol);
1798
+ this.protocolReprobeFailures.delete(uuid);
1767
1799
  Log?.debug('[ReactNativeBleTransport] protocol detected', {
1768
1800
  deviceId: uuid,
1769
1801
  protocol,
@@ -1773,6 +1805,14 @@ export default class ReactNativeBleTransport {
1773
1805
  }
1774
1806
  }
1775
1807
 
1808
+ if (trustSessionProtocol) {
1809
+ // Still silent on its own protocol: count it, and let the streak expire the
1810
+ // shortcut so a device that genuinely switched protocols is found again.
1811
+ this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
1812
+ } else {
1813
+ this.protocolReprobeFailures.delete(uuid);
1814
+ }
1815
+
1776
1816
  this.deviceProtocol.delete(uuid);
1777
1817
  this.probingProtocols.delete(uuid);
1778
1818
  throw this.createProtocolDetectionError();