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

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.js CHANGED
@@ -194,6 +194,38 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
194
194
  }, ms);
195
195
  });
196
196
 
197
+ const ATT_INSUFFICIENT_AUTHENTICATION = 5;
198
+ const ATT_INSUFFICIENT_ENCRYPTION = 15;
199
+ const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
200
+ const nativeErrorText = (error) => [error.reason, error.message]
201
+ .filter((value) => typeof value === 'string')
202
+ .join(' ');
203
+ const isNativeBleStaleBondError = (error) => {
204
+ if (!error || typeof error !== 'object') {
205
+ return typeof error === 'string' ? hdShared.isBleStaleBondErrorText(error) : false;
206
+ }
207
+ const nativeError = error;
208
+ if (nativeError.attErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
209
+ nativeError.attErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
210
+ nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION) {
211
+ return true;
212
+ }
213
+ return hdShared.isBleStaleBondErrorText(nativeErrorText(nativeError));
214
+ };
215
+ const toBleStaleBondHardwareError = (error) => {
216
+ if (hdShared.isBleStaleBondHardwareError(error)) {
217
+ return error;
218
+ }
219
+ const nativeError = (error !== null && error !== void 0 ? error : {});
220
+ const text = nativeErrorText(nativeError);
221
+ const normalizedText = text.toLowerCase();
222
+ const peerRemoved = nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION ||
223
+ normalizedText.includes('peer removed pairing information');
224
+ return hdShared.ERRORS.TypedError(peerRemoved
225
+ ? hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation
226
+ : hdShared.HardwareErrorCode.BleDeviceBondError, text || undefined);
227
+ };
228
+
197
229
  const isHeaderChunk = (chunk) => {
198
230
  if (chunk.length < 9)
199
231
  return false;
@@ -274,9 +306,10 @@ const getFirmwareUploadWriteRetryType = (error) => {
274
306
  return text.includes('GATT_CONGESTED') || hasGattCongestedStatus(text) ? 'congested' : null;
275
307
  };
276
308
  const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
277
- const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
309
+ const PROTOCOL_PROBE_TIMEOUT_MS = 3000;
278
310
  const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
279
311
  const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
312
+ const BLE_NATIVE_TEARDOWN_TIMEOUT_MS = 3000;
280
313
  const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
281
314
  const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
282
315
  typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
@@ -310,9 +343,6 @@ function resetProtocolV2BleTuning() {
310
343
  function getProtocolV2BleTuning() {
311
344
  return Object.assign({}, protocolV2BleTuning);
312
345
  }
313
- function inferProtocolHintFromDeviceName(name) {
314
- return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
315
- }
316
346
  function getDeviceDisplayName(device) {
317
347
  return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
318
348
  }
@@ -335,9 +365,14 @@ const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
335
365
  const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
336
366
  const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
337
367
  const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
368
+ const BLE_SETUP_WEDGED_MESSAGE = 'BLE setup wedged repeatedly';
338
369
  const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
339
370
  typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
340
371
  error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
372
+ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.PollingTimeout &&
373
+ typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
374
+ error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
375
+ const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
341
376
  const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
342
377
  const tryToGetConfiguration = (device) => {
343
378
  if (!device || !device.serviceUUIDs)
@@ -369,12 +404,11 @@ const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void
369
404
  }
370
405
  });
371
406
  const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
372
- function remapError(error) {
407
+ function remapError(error, mapProtocolV2StaleBond) {
373
408
  var _a;
374
409
  if (error instanceof reactNativeBlePlx.BleError) {
375
- if (error.iosErrorCode === reactNativeBlePlx.BleATTErrorCode.UnlikelyError ||
376
- error.reason === 'Peer removed pairing information') {
377
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation);
410
+ if (mapProtocolV2StaleBond && isNativeBleStaleBondError(error)) {
411
+ throw toBleStaleBondHardwareError(error);
378
412
  }
379
413
  if ((error === null || error === void 0 ? void 0 : error.attErrorCode) === 22) {
380
414
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondError);
@@ -403,7 +437,10 @@ class ReactNativeBleTransport {
403
437
  this.connectionSetupTimeoutCounts = new Map();
404
438
  this.deviceProtocolHints = new Map();
405
439
  this.sessionProtocols = new Map();
440
+ this.confirmedProtocolV2 = new Set();
406
441
  this.protocolReprobeFailures = new Map();
442
+ this.staleBondErrors = new Map();
443
+ this.acquiringProtocolV2 = new Set();
407
444
  this.protocolV2Assemblers = new Map();
408
445
  this.protocolV2FrameQueues = new Map();
409
446
  this.protocolV2FramePromises = new Map();
@@ -434,6 +471,7 @@ class ReactNativeBleTransport {
434
471
  this.androidHighPriorityDevices = new Set();
435
472
  this.androidPriorityResetTimers = new Map();
436
473
  this.nextMonitorToken = 1;
474
+ this.lifecycleOperations = new Map();
437
475
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
438
476
  }
439
477
  init(logger, emitter) {
@@ -658,7 +696,7 @@ class ReactNativeBleTransport {
658
696
  allowDuplicates: true,
659
697
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
660
698
  }, (error, device) => {
661
- var _a;
699
+ var _a, _b;
662
700
  if (error) {
663
701
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
664
702
  if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
@@ -680,15 +718,12 @@ class ReactNativeBleTransport {
680
718
  }
681
719
  const displayName = getDeviceDisplayName(device);
682
720
  const isUnnamedIOSPeripheral = reactNative.Platform.OS === 'ios' && !(displayName === null || displayName === void 0 ? void 0 : displayName.trim());
683
- const isFindMyPeripheral = hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.name) ||
684
- hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.localName);
685
721
  const isOneKey = !isUnnamedIOSPeripheral &&
686
- !isFindMyPeripheral &&
687
722
  hdShared.isOnekeyBluetoothDevice({
688
723
  id: device === null || device === void 0 ? void 0 : device.id,
689
724
  name: device === null || device === void 0 ? void 0 : device.name,
690
725
  localName: device === null || device === void 0 ? void 0 : device.localName,
691
- serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
726
+ serviceUuids: (_b = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _b !== void 0 ? _b : getBluetoothServiceUuids(),
692
727
  });
693
728
  if (isOneKey) {
694
729
  addDevice(device);
@@ -707,15 +742,12 @@ class ReactNativeBleTransport {
707
742
  const localName = 'localName' in device && typeof device.localName === 'string'
708
743
  ? device.localName
709
744
  : null;
710
- const isFindMyPeripheral = hdShared.isPro2FindMyAdvertisementName(device.name) ||
711
- hdShared.isPro2FindMyAdvertisementName(localName);
712
- if (!isFindMyPeripheral &&
713
- hdShared.isOnekeyBluetoothDevice({
714
- id: device.id,
715
- name: device.name,
716
- localName,
717
- serviceUuids: device.serviceUUIDs,
718
- })) {
745
+ if (hdShared.isOnekeyBluetoothDevice({
746
+ id: device.id,
747
+ name: device.name,
748
+ localName,
749
+ serviceUuids: device.serviceUUIDs,
750
+ })) {
719
751
  Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
720
752
  addDevice(device);
721
753
  }
@@ -725,16 +757,11 @@ class ReactNativeBleTransport {
725
757
  var _a;
726
758
  if (deviceList.every(d => d.id !== device.id)) {
727
759
  const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
728
- const protocolHint = inferProtocolHintFromDeviceName(displayName);
729
- if (protocolHint) {
730
- this.deviceProtocolHints.set(device.id, protocolHint);
731
- }
732
760
  deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
733
761
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
734
762
  deviceId: device.id,
735
763
  name: displayName,
736
764
  serviceUUIDs: device.serviceUUIDs,
737
- protocolHint,
738
765
  });
739
766
  }
740
767
  };
@@ -797,24 +824,57 @@ class ReactNativeBleTransport {
797
824
  });
798
825
  }
799
826
  acquire(input) {
800
- var _a, _b;
801
827
  return __awaiter(this, void 0, void 0, function* () {
802
- const { uuid, forceCleanRunPromise, expectedProtocol } = input;
828
+ const { uuid } = input;
803
829
  if (!uuid) {
804
830
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
805
831
  }
832
+ return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
833
+ });
834
+ }
835
+ acquireUnlocked(input) {
836
+ var _a;
837
+ return __awaiter(this, void 0, void 0, function* () {
838
+ const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
839
+ const shouldMapProtocolV2StaleBond = expectedProtocol
840
+ ? expectedProtocol === 'V2'
841
+ : this.confirmedProtocolV2.has(uuid);
806
842
  const cachedTransport = transportCache[uuid];
843
+ if (skipProtocolProbe && !cachedTransport && this.blePlxManager) {
844
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh uncached BLE connection for firmware install:', uuid);
845
+ const manager = this.blePlxManager;
846
+ yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
847
+ yield this.runBestEffortNativeOperation('firmware install reconnect: cancel uncached device connection', () => manager.cancelDeviceConnection(uuid));
848
+ }));
849
+ }
807
850
  if (cachedTransport) {
808
- const cachedProtocol = this.deviceProtocol.get(uuid);
809
- const isCachedDeviceConnected = yield cachedTransport.device.isConnected().catch(() => false);
810
- if (isCachedDeviceConnected &&
811
- cachedProtocol &&
812
- (!expectedProtocol || cachedProtocol === expectedProtocol)) {
813
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
814
- return { uuid, protocolType: cachedProtocol };
851
+ if (skipProtocolProbe) {
852
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh cached BLE connection for firmware install:', uuid);
853
+ const manager = this.blePlxManager;
854
+ yield this.releaseUnlocked(uuid, true);
855
+ yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
856
+ const operations = [];
857
+ if (manager) {
858
+ operations.push(this.runBestEffortNativeOperation('firmware install reconnect: cancel device connection', () => manager.cancelDeviceConnection(uuid)));
859
+ }
860
+ operations.push(this.runBestEffortNativeOperation('firmware install reconnect: device cancel connection', () => cachedTransport.device.cancelConnection()));
861
+ yield Promise.all(operations);
862
+ }));
863
+ }
864
+ else {
865
+ const cachedProtocol = this.deviceProtocol.get(uuid);
866
+ const isCachedDeviceConnected = yield cachedTransport.device
867
+ .isConnected()
868
+ .catch(() => false);
869
+ if (isCachedDeviceConnected &&
870
+ cachedProtocol &&
871
+ (!expectedProtocol || cachedProtocol === expectedProtocol)) {
872
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
873
+ return { uuid, protocolType: cachedProtocol };
874
+ }
875
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
876
+ yield this.releaseUnlocked(uuid, true);
815
877
  }
816
- Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
817
- yield this.release(uuid, true);
818
878
  }
819
879
  let device = null;
820
880
  if (forceCleanRunPromise && this.runPromise) {
@@ -858,7 +918,7 @@ class ReactNativeBleTransport {
858
918
  }
859
919
  catch (e) {
860
920
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
861
- if (isConnectTimeoutError(e)) {
921
+ if (shouldRethrowBleSetupError(e)) {
862
922
  throw e;
863
923
  }
864
924
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
@@ -871,7 +931,7 @@ class ReactNativeBleTransport {
871
931
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleAlreadyConnected);
872
932
  }
873
933
  else {
874
- remapError(e);
934
+ remapError(e, shouldMapProtocolV2StaleBond);
875
935
  }
876
936
  }
877
937
  }
@@ -886,7 +946,7 @@ class ReactNativeBleTransport {
886
946
  }
887
947
  catch (e) {
888
948
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
889
- if (isConnectTimeoutError(e)) {
949
+ if (shouldRethrowBleSetupError(e)) {
890
950
  throw e;
891
951
  }
892
952
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
@@ -905,7 +965,7 @@ class ReactNativeBleTransport {
905
965
  }
906
966
  }
907
967
  else {
908
- remapError(e);
968
+ remapError(e, shouldMapProtocolV2StaleBond);
909
969
  }
910
970
  }
911
971
  }
@@ -914,16 +974,43 @@ class ReactNativeBleTransport {
914
974
  const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
915
975
  const protocolHint = expectedProtocol
916
976
  ? undefined
917
- : (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
918
- yield this.release(uuid, true);
977
+ : (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
978
+ yield this.releaseUnlocked(uuid, true);
919
979
  if (protocolHint) {
920
980
  this.deviceProtocolHints.set(uuid, protocolHint);
921
981
  }
922
- yield this.installTransportForAcquire(uuid, acquiredDevice, {
923
- writeCharacteristic,
924
- notifyCharacteristic,
925
- });
982
+ if (shouldMapProtocolV2StaleBond) {
983
+ this.acquiringProtocolV2.add(uuid);
984
+ }
926
985
  try {
986
+ yield this.installTransportForAcquire(uuid, acquiredDevice, {
987
+ writeCharacteristic,
988
+ notifyCharacteristic,
989
+ });
990
+ if (skipProtocolProbe) {
991
+ if (!expectedProtocol) {
992
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires an expected BLE protocol');
993
+ }
994
+ const hasConfirmedProtocol = this.sessionProtocols.get(uuid) === expectedProtocol ||
995
+ (expectedProtocol === 'V2' && this.confirmedProtocolV2.has(uuid));
996
+ if (!hasConfirmedProtocol) {
997
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires a previously confirmed protocol for this BLE endpoint');
998
+ }
999
+ this.deviceProtocol.set(uuid, expectedProtocol);
1000
+ this.sessionProtocols.set(uuid, expectedProtocol);
1001
+ this.protocolReprobeFailures.delete(uuid);
1002
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected without probe', {
1003
+ deviceId: uuid,
1004
+ protocol: expectedProtocol,
1005
+ source: 'firmware-install-reconnect',
1006
+ });
1007
+ const currentTransport = transportCache[uuid];
1008
+ if (!currentTransport) {
1009
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
1010
+ }
1011
+ this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
1012
+ return { uuid, protocolType: expectedProtocol };
1013
+ }
927
1014
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
928
1015
  yield this.installTransportForAcquire(uuid, acquiredDevice);
929
1016
  }));
@@ -935,16 +1022,24 @@ class ReactNativeBleTransport {
935
1022
  return { uuid, protocolType };
936
1023
  }
937
1024
  catch (error) {
938
- yield this.release(uuid, true);
1025
+ if (hdShared.isBleStaleBondHardwareError(error)) {
1026
+ yield this.disconnectUnlocked(uuid);
1027
+ }
1028
+ else {
1029
+ yield this.releaseUnlocked(uuid, true);
1030
+ }
939
1031
  throw error;
940
1032
  }
1033
+ finally {
1034
+ this.acquiringProtocolV2.delete(uuid);
1035
+ }
941
1036
  });
942
1037
  }
943
1038
  _monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
944
1039
  let bufferLength = 0;
945
1040
  let buffer$1 = [];
946
1041
  const subscription = characteristic.monitor((error, c) => {
947
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
1042
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
948
1043
  const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
949
1044
  if (error) {
950
1045
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
@@ -956,19 +1051,21 @@ class ReactNativeBleTransport {
956
1051
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
957
1052
  return;
958
1053
  }
1054
+ if ((this.getActiveProtocol(uuid) === 'V2' || this.acquiringProtocolV2.has(uuid)) &&
1055
+ isNativeBleStaleBondError(error)) {
1056
+ this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
1057
+ return;
1058
+ }
959
1059
  if (this.getActiveProtocol(uuid) === 'V2') {
960
1060
  let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
961
1061
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
962
1062
  errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
963
1063
  }
964
- else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
965
- errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
966
- }
967
- else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
968
- ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
969
- ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
970
- ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
971
- ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
1064
+ else if (((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Cannot write client characteristic config descriptor')) ||
1065
+ ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot find client characteristic config descriptor')) ||
1066
+ ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('The handle is invalid')) ||
1067
+ ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('Writing is not permitted')) ||
1068
+ ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('notify change failed for device'))) {
972
1069
  errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
973
1070
  }
974
1071
  this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
@@ -976,17 +1073,14 @@ class ReactNativeBleTransport {
976
1073
  }
977
1074
  if (this.runPromise && this.runPromiseDeviceId === uuid) {
978
1075
  let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
979
- if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
1076
+ if ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('The connection has timed out unexpectedly')) {
980
1077
  ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
981
1078
  }
982
- if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
983
- ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
984
- }
985
- if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
986
- ((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
987
- ((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
988
- ((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
989
- ((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
1079
+ if (((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('Cannot write client characteristic config descriptor')) ||
1080
+ ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Cannot find client characteristic config descriptor')) ||
1081
+ ((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('The handle is invalid')) ||
1082
+ ((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Writing is not permitted')) ||
1083
+ ((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('notify change failed for device'))) {
990
1084
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
991
1085
  this.runPromise.reject(notifyError);
992
1086
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
@@ -1028,7 +1122,7 @@ class ReactNativeBleTransport {
1028
1122
  bufferLength = 0;
1029
1123
  buffer$1 = [];
1030
1124
  if (this.runPromiseDeviceId === uuid) {
1031
- (_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
1125
+ (_o = this.runPromise) === null || _o === void 0 ? void 0 : _o.resolve(value.toString('hex'));
1032
1126
  }
1033
1127
  }
1034
1128
  }
@@ -1039,22 +1133,28 @@ class ReactNativeBleTransport {
1039
1133
  this.rejectProtocolV2Frames(uuid, notifyError);
1040
1134
  }
1041
1135
  else if (this.runPromiseDeviceId === uuid) {
1042
- (_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
1136
+ (_p = this.runPromise) === null || _p === void 0 ? void 0 : _p.reject(notifyError);
1043
1137
  }
1044
1138
  }
1045
1139
  }, notifyTransactionId);
1046
1140
  return subscription;
1047
1141
  }
1048
1142
  release(uuid, onclose = false) {
1143
+ return __awaiter(this, void 0, void 0, function* () {
1144
+ return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
1145
+ });
1146
+ }
1147
+ releaseUnlocked(uuid, onclose = false) {
1049
1148
  return __awaiter(this, void 0, void 0, function* () {
1050
1149
  yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
1051
1150
  return this.releaseNative(uuid, onclose);
1052
1151
  });
1053
1152
  }
1054
1153
  releaseNative(uuid, onclose = false) {
1055
- var _a, _b, _c, _d, _e, _f, _g;
1154
+ var _a, _b, _c, _d, _e;
1056
1155
  return __awaiter(this, void 0, void 0, function* () {
1057
1156
  const transport = transportCache[uuid];
1157
+ const manager = this.blePlxManager;
1058
1158
  if (this.runPromise && this.runPromiseDeviceId === uuid) {
1059
1159
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1060
1160
  this.runPromise.reject(error);
@@ -1070,7 +1170,6 @@ class ReactNativeBleTransport {
1070
1170
  this.resetProtocolV2Frames(uuid);
1071
1171
  return Promise.resolve(true);
1072
1172
  }
1073
- yield this.restoreAndroidConnectionPriority(uuid, transport);
1074
1173
  if (transport) {
1075
1174
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1076
1175
  this.monitorTokens.delete(uuid);
@@ -1081,33 +1180,39 @@ class ReactNativeBleTransport {
1081
1180
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_c = transport.notifyCharacteristic) === null || _c === void 0 ? void 0 : _c.uuid);
1082
1181
  (_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
1083
1182
  transport.notifySubscription = undefined;
1084
- if (transport.notifyTransactionId) {
1085
- try {
1086
- yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
1087
- }
1088
- catch (e) {
1089
- Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel notify transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
1090
- }
1183
+ if (transportCache[uuid] === transport) {
1184
+ delete transportCache[uuid];
1091
1185
  }
1092
- delete transportCache[uuid];
1093
1186
  }
1094
1187
  this.protocolV2HighVolumeLogSignatures.delete(uuid);
1095
1188
  this.deviceProtocol.delete(uuid);
1096
1189
  this.probingProtocols.delete(uuid);
1097
- (_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
1190
+ this.staleBondErrors.delete(uuid);
1191
+ this.acquiringProtocolV2.delete(uuid);
1192
+ (_e = this.protocolV2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
1098
1193
  this.protocolV2Assemblers.delete(uuid);
1099
1194
  this.resetProtocolV2Frames(uuid);
1100
- try {
1101
- yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
1102
- }
1103
- catch (e) {
1104
- Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
1105
- }
1195
+ yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
1196
+ const operations = [
1197
+ this.runBestEffortNativeOperation('release: restore connection priority', () => this.restoreAndroidConnectionPriority(uuid, transport)),
1198
+ ];
1199
+ if ((transport === null || transport === void 0 ? void 0 : transport.notifyTransactionId) && manager) {
1200
+ operations.push(this.runBestEffortNativeOperation('release: cancel notify transaction', () => manager.cancelTransaction(transport.notifyTransactionId)));
1201
+ }
1202
+ if (manager) {
1203
+ operations.push(this.runBestEffortNativeOperation('release: cancel transaction', () => manager.cancelTransaction(uuid)));
1204
+ }
1205
+ yield Promise.all(operations);
1206
+ }));
1106
1207
  return Promise.resolve(true);
1107
1208
  });
1108
1209
  }
1109
1210
  post(session, name, data) {
1110
1211
  return __awaiter(this, void 0, void 0, function* () {
1212
+ if (this.getProtocolType(session) === 'V2') {
1213
+ yield this.protocolV2Links.sendFlowControl(session, () => this.createProtocolV2Adapter(session), name, data);
1214
+ return;
1215
+ }
1111
1216
  yield this.call(session, name, data);
1112
1217
  });
1113
1218
  }
@@ -1123,7 +1228,6 @@ class ReactNativeBleTransport {
1123
1228
  if (!protocol) {
1124
1229
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
1125
1230
  }
1126
- Log === null || Log === void 0 ? void 0 : Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
1127
1231
  if (protocol === 'V2') {
1128
1232
  return this.callProtocolV2(uuid, name, data, options);
1129
1233
  }
@@ -1334,10 +1438,16 @@ class ReactNativeBleTransport {
1334
1438
  this.stopped = true;
1335
1439
  }
1336
1440
  disconnect(session) {
1337
- var _a, _b, _c, _d, _e;
1441
+ return __awaiter(this, void 0, void 0, function* () {
1442
+ return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
1443
+ });
1444
+ }
1445
+ disconnectUnlocked(session) {
1446
+ var _a, _b, _c;
1338
1447
  return __awaiter(this, void 0, void 0, function* () {
1339
1448
  yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
1340
1449
  const transport = transportCache[session];
1450
+ const manager = this.blePlxManager;
1341
1451
  const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
1342
1452
  if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
1343
1453
  try {
@@ -1359,40 +1469,19 @@ class ReactNativeBleTransport {
1359
1469
  Log === null || Log === void 0 ? void 0 : Log.error('disconnect: remove notify subscription error: ', e);
1360
1470
  }
1361
1471
  }
1362
- if (session) {
1363
- try {
1364
- yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
1365
- }
1366
- catch (e) {
1367
- Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
1368
- }
1369
- }
1370
- if (transport === null || transport === void 0 ? void 0 : transport.device) {
1371
- try {
1372
- yield transport.device.cancelConnection();
1373
- }
1374
- catch (e) {
1375
- Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: device.cancelConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
1376
- }
1377
- }
1378
- try {
1379
- yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
1380
- }
1381
- catch (e) {
1382
- Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
1383
- }
1384
- if (transportCache[session]) {
1472
+ if (!transport || transportCache[session] === transport) {
1385
1473
  delete transportCache[session];
1386
1474
  }
1387
1475
  this.deviceProtocol.delete(session);
1388
1476
  this.probingProtocols.delete(session);
1477
+ this.staleBondErrors.delete(session);
1389
1478
  this.deviceProtocolHints.delete(session);
1390
1479
  this.sessionProtocols.delete(session);
1391
1480
  this.protocolReprobeFailures.delete(session);
1392
1481
  this.protocolV2Assemblers.delete(session);
1393
1482
  this.resetProtocolV2Frames(session);
1394
1483
  try {
1395
- this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
1484
+ this.emitDeviceDisconnect(session, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, monitorToken);
1396
1485
  }
1397
1486
  catch (e) {
1398
1487
  Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
@@ -1400,9 +1489,81 @@ class ReactNativeBleTransport {
1400
1489
  if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
1401
1490
  this.monitorTokens.delete(session);
1402
1491
  }
1492
+ yield this.runNativeTeardown(session, manager, () => __awaiter(this, void 0, void 0, function* () {
1493
+ const operations = [];
1494
+ if (manager) {
1495
+ operations.push(this.runBestEffortNativeOperation('disconnect: cancel transaction', () => manager.cancelTransaction(session)));
1496
+ operations.push(this.runBestEffortNativeOperation('disconnect: cancel device connection', () => manager.cancelDeviceConnection(session)));
1497
+ }
1498
+ if (transport === null || transport === void 0 ? void 0 : transport.device) {
1499
+ operations.push(this.runBestEffortNativeOperation('disconnect: device cancel connection', () => transport.device.cancelConnection()));
1500
+ }
1501
+ yield Promise.all(operations);
1502
+ }));
1403
1503
  yield new Promise(resolve => setTimeout(() => resolve(), 100));
1404
1504
  });
1405
1505
  }
1506
+ runNativeTeardown(uuid, manager, teardown) {
1507
+ return __awaiter(this, void 0, void 0, function* () {
1508
+ let timer;
1509
+ let timedOut = false;
1510
+ const pending = Promise.resolve()
1511
+ .then(teardown)
1512
+ .catch(error => {
1513
+ Log === null || Log === void 0 ? void 0 : Log.debug('BLE native teardown error (ignored): ', (error === null || error === void 0 ? void 0 : error.message) || error);
1514
+ });
1515
+ try {
1516
+ yield Promise.race([
1517
+ pending,
1518
+ new Promise(resolve => {
1519
+ timer = setTimeout(() => {
1520
+ timedOut = true;
1521
+ resolve();
1522
+ }, BLE_NATIVE_TEARDOWN_TIMEOUT_MS);
1523
+ }),
1524
+ ]);
1525
+ }
1526
+ finally {
1527
+ if (timer)
1528
+ clearTimeout(timer);
1529
+ }
1530
+ if (timedOut) {
1531
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE native teardown timed out:', uuid);
1532
+ if (this.blePlxManager === manager) {
1533
+ this.resetPlxManager();
1534
+ }
1535
+ }
1536
+ });
1537
+ }
1538
+ runBestEffortNativeOperation(label, operation) {
1539
+ return Promise.resolve()
1540
+ .then(operation)
1541
+ .catch(error => {
1542
+ Log === null || Log === void 0 ? void 0 : Log.debug(`${label} error (ignored): `, (error === null || error === void 0 ? void 0 : error.message) || error);
1543
+ });
1544
+ }
1545
+ runLifecycleOperation(uuid, operation) {
1546
+ var _a;
1547
+ return __awaiter(this, void 0, void 0, function* () {
1548
+ const previousOperation = (_a = this.lifecycleOperations.get(uuid)) !== null && _a !== void 0 ? _a : Promise.resolve();
1549
+ let completeOperation;
1550
+ const operationGate = new Promise(resolve => {
1551
+ completeOperation = resolve;
1552
+ });
1553
+ const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
1554
+ this.lifecycleOperations.set(uuid, operationTail);
1555
+ yield previousOperation.catch(() => undefined);
1556
+ try {
1557
+ return yield operation();
1558
+ }
1559
+ finally {
1560
+ completeOperation();
1561
+ if (this.lifecycleOperations.get(uuid) === operationTail) {
1562
+ this.lifecycleOperations.delete(uuid);
1563
+ }
1564
+ }
1565
+ });
1566
+ }
1406
1567
  cancel() {
1407
1568
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1408
1569
  if (this.runPromise) ;
@@ -1429,7 +1590,10 @@ class ReactNativeBleTransport {
1429
1590
  }
1430
1591
  catch (error) {
1431
1592
  if (timedOut || isNativeOperationTimeoutError(error)) {
1432
- this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
1593
+ const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
1594
+ if (resetManager) {
1595
+ throw this.createWedgedBleSetupError();
1596
+ }
1433
1597
  }
1434
1598
  throw error;
1435
1599
  }
@@ -1460,7 +1624,10 @@ class ReactNativeBleTransport {
1460
1624
  }
1461
1625
  catch (error) {
1462
1626
  if (timedOut || isNativeOperationTimeoutError(error)) {
1463
- this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
1627
+ const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
1628
+ if (resetManager) {
1629
+ throw this.createWedgedBleSetupError();
1630
+ }
1464
1631
  }
1465
1632
  throw error;
1466
1633
  }
@@ -1486,13 +1653,20 @@ class ReactNativeBleTransport {
1486
1653
  }
1487
1654
  this.deviceProtocol.delete(uuid);
1488
1655
  this.probingProtocols.delete(uuid);
1656
+ this.staleBondErrors.delete(uuid);
1657
+ this.acquiringProtocolV2.delete(uuid);
1489
1658
  this.protocolV2Assemblers.delete(uuid);
1490
1659
  this.resetProtocolV2Frames(uuid);
1491
1660
  if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
1492
1661
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
1493
1662
  this.resetPlxManager();
1494
1663
  this.connectionSetupTimeoutCounts.delete(uuid);
1664
+ return true;
1495
1665
  }
1666
+ return false;
1667
+ }
1668
+ createWedgedBleSetupError() {
1669
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.PollingTimeout, BLE_SETUP_WEDGED_MESSAGE);
1496
1670
  }
1497
1671
  getCachedTransport(uuid) {
1498
1672
  const transport = transportCache[uuid];
@@ -1550,6 +1724,8 @@ class ReactNativeBleTransport {
1550
1724
  }
1551
1725
  this.deviceProtocol.delete(uuid);
1552
1726
  this.probingProtocols.delete(uuid);
1727
+ this.staleBondErrors.delete(uuid);
1728
+ this.acquiringProtocolV2.delete(uuid);
1553
1729
  this.protocolV2Assemblers.delete(uuid);
1554
1730
  this.resetProtocolV2Frames(uuid);
1555
1731
  if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
@@ -1561,11 +1737,39 @@ class ReactNativeBleTransport {
1561
1737
  resetPlxManager() {
1562
1738
  const manager = this.blePlxManager;
1563
1739
  this.blePlxManager = undefined;
1564
- Object.keys(transportCache).forEach(key => {
1565
- delete transportCache[key];
1740
+ const reason = 'React Native BLE manager reset';
1741
+ Object.entries(transportCache).forEach(([uuid, cachedTransport]) => {
1742
+ var _a, _b, _c, _d;
1743
+ try {
1744
+ (_a = cachedTransport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
1745
+ }
1746
+ catch (error) {
1747
+ Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect subscription removal failed:', error);
1748
+ }
1749
+ cachedTransport.disconnectSubscription = undefined;
1750
+ try {
1751
+ (_b = cachedTransport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
1752
+ }
1753
+ catch (error) {
1754
+ Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset notify subscription removal failed:', error);
1755
+ }
1756
+ cachedTransport.notifySubscription = undefined;
1757
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
1758
+ try {
1759
+ this.emitDeviceDisconnect(uuid, (_c = cachedTransport.device) === null || _c === void 0 ? void 0 : _c.name, (_d = cachedTransport.monitorToken) !== null && _d !== void 0 ? _d : this.monitorTokens.get(uuid));
1760
+ }
1761
+ catch (error) {
1762
+ Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect event failed:', error);
1763
+ }
1764
+ delete transportCache[uuid];
1765
+ });
1766
+ this.protocolV2Links.invalidateAllLinks(reason).catch(error => {
1767
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager link invalidation failed:', error);
1566
1768
  });
1567
1769
  this.deviceProtocol.clear();
1568
1770
  this.probingProtocols.clear();
1771
+ this.staleBondErrors.clear();
1772
+ this.acquiringProtocolV2.clear();
1569
1773
  this.sessionProtocols.clear();
1570
1774
  this.protocolReprobeFailures.clear();
1571
1775
  this.writeTimeoutCounts.clear();
@@ -1600,32 +1804,23 @@ class ReactNativeBleTransport {
1600
1804
  detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
1601
1805
  var _a;
1602
1806
  return __awaiter(this, void 0, void 0, function* () {
1603
- if (reactNative.Platform.OS === 'ios' && expectedProtocol) {
1604
- this.deviceProtocol.set(uuid, expectedProtocol);
1807
+ if (expectedProtocol === 'V1') {
1808
+ this.deviceProtocol.set(uuid, 'V1');
1605
1809
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
1606
1810
  deviceId: uuid,
1607
- protocol: expectedProtocol,
1811
+ protocol: 'V1',
1608
1812
  source: 'expected',
1609
1813
  });
1610
- return expectedProtocol;
1814
+ return 'V1';
1611
1815
  }
1612
- if (expectedProtocol === 'V1') {
1613
- if (yield this.probeProtocolV1(uuid)) {
1614
- this.deviceProtocol.set(uuid, 'V1');
1615
- this.sessionProtocols.set(uuid, 'V1');
1616
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1617
- deviceId: uuid,
1618
- protocol: 'V1',
1619
- source: 'expected',
1620
- });
1621
- return 'V1';
1622
- }
1623
- throw this.createProtocolMismatchError(expectedProtocol);
1816
+ if (expectedProtocol === 'V2' || this.acquiringProtocolV2.has(uuid)) {
1817
+ this.throwIfStaleBondError(uuid);
1624
1818
  }
1625
1819
  if (expectedProtocol === 'V2') {
1626
1820
  if (yield this.probeProtocolV2(uuid)) {
1627
1821
  this.deviceProtocol.set(uuid, 'V2');
1628
1822
  this.sessionProtocols.set(uuid, 'V2');
1823
+ this.confirmedProtocolV2.add(uuid);
1629
1824
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1630
1825
  deviceId: uuid,
1631
1826
  protocol: 'V2',
@@ -1657,6 +1852,9 @@ class ReactNativeBleTransport {
1657
1852
  if (detected) {
1658
1853
  this.deviceProtocol.set(uuid, protocol);
1659
1854
  this.sessionProtocols.set(uuid, protocol);
1855
+ if (protocol === 'V2') {
1856
+ this.confirmedProtocolV2.add(uuid);
1857
+ }
1660
1858
  this.protocolReprobeFailures.delete(uuid);
1661
1859
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1662
1860
  deviceId: uuid,
@@ -1748,6 +1946,7 @@ class ReactNativeBleTransport {
1748
1946
  }
1749
1947
  this.probingProtocols.set(uuid, 'V2');
1750
1948
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1949
+ this.throwIfStaleBondError(uuid);
1751
1950
  const detected = yield transport.probeProtocolV2({
1752
1951
  call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
1753
1952
  timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
@@ -1758,6 +1957,7 @@ class ReactNativeBleTransport {
1758
1957
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1759
1958
  this.resetProtocolV2Frames(uuid);
1760
1959
  },
1960
+ shouldRethrow: hdShared.isBleStaleBondHardwareError,
1761
1961
  });
1762
1962
  if (!detected) {
1763
1963
  this.clearProbeProtocol(uuid, 'V2');
@@ -1818,6 +2018,19 @@ class ReactNativeBleTransport {
1818
2018
  framePromise.reject(error);
1819
2019
  }
1820
2020
  }
2021
+ rememberStaleBondError(uuid, error) {
2022
+ this.staleBondErrors.set(uuid, error);
2023
+ this.rejectProtocolV2Frames(uuid, error);
2024
+ if (this.runPromise && this.runPromiseDeviceId === uuid) {
2025
+ this.runPromise.reject(error);
2026
+ }
2027
+ }
2028
+ throwIfStaleBondError(uuid) {
2029
+ const error = this.staleBondErrors.get(uuid);
2030
+ if (error) {
2031
+ throw error;
2032
+ }
2033
+ }
1821
2034
  readProtocolV2Frame(uuid) {
1822
2035
  return __awaiter(this, void 0, void 0, function* () {
1823
2036
  const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
@@ -1866,6 +2079,11 @@ class ReactNativeBleTransport {
1866
2079
  return;
1867
2080
  }
1868
2081
  catch (error) {
2082
+ if (isNativeBleStaleBondError(error) || hdShared.isBleStaleBondHardwareError(error)) {
2083
+ const bondError = toBleStaleBondHardwareError(error);
2084
+ this.rememberStaleBondError(uuid, bondError);
2085
+ throw bondError;
2086
+ }
1869
2087
  if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
1870
2088
  attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
1871
2089
  throw error;
@@ -2064,6 +2282,8 @@ class ReactNativeBleTransport {
2064
2282
  }),
2065
2283
  reset: (reason) => {
2066
2284
  var _a;
2285
+ if (this.monitorTokens.get(uuid) !== generation)
2286
+ return;
2067
2287
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
2068
2288
  this.rejectProtocolV2Frames(uuid, new Error(reason));
2069
2289
  },
@@ -2080,6 +2300,8 @@ class ReactNativeBleTransport {
2080
2300
  exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
2081
2301
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
2082
2302
  exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
2303
+ exports.BLE_NATIVE_TEARDOWN_TIMEOUT_MS = BLE_NATIVE_TEARDOWN_TIMEOUT_MS;
2304
+ exports.BLE_SETUP_WEDGED_MESSAGE = BLE_SETUP_WEDGED_MESSAGE;
2083
2305
  exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
2084
2306
  exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
2085
2307
  exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;