@onekeyfe/hd-transport-react-native 1.2.2-alpha.12 → 1.2.2-alpha.122

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
@@ -57,36 +57,73 @@ const bleLogger = {
57
57
  };
58
58
 
59
59
  const Logger = bleLogger;
60
+ const bondFailureReasons = {
61
+ 1: 'authentication_failed',
62
+ 2: 'rejected',
63
+ 3: 'canceled',
64
+ 4: 'device_unreachable',
65
+ 5: 'discovery_in_progress',
66
+ 6: 'timeout',
67
+ 7: 'repeated_attempts',
68
+ 8: 'remote_canceled',
69
+ 9: 'removed',
70
+ };
60
71
  const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
61
72
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
62
- const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
73
+ const onDeviceBondState = (bleMacAddress, signal) => new Promise((resolve, reject) => {
74
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
75
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
76
+ return;
77
+ }
63
78
  const cleanup = () => {
64
79
  if (timeout) {
65
80
  clearTimeout(timeout);
66
81
  }
67
82
  if (cleanupListener)
68
83
  cleanupListener();
84
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
85
+ };
86
+ const onAbort = () => {
87
+ cleanup();
88
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
69
89
  };
90
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
70
91
  const timeout = setTimeout(() => {
71
92
  cleanup();
72
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
93
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', {
94
+ phase: 'bond',
95
+ reason: 'timeout',
96
+ }));
73
97
  }, 60 * 1000);
74
98
  const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
75
- var _a;
99
+ var _a, _b;
76
100
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
77
101
  return;
78
102
  }
79
103
  const { bondState } = peripheral;
80
104
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
81
- const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
105
+ const hasFailed = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
82
106
  Logger.debug('onDeviceBondState bondState:', bondState);
83
107
  if (hasBonded) {
84
108
  cleanup();
85
109
  resolve(peripheral);
86
110
  }
87
- else if (hasCanceled) {
111
+ else if (hasFailed) {
88
112
  cleanup();
89
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
113
+ const nativeReason = 'reason' in bondState && typeof bondState.reason === 'number'
114
+ ? bondState.reason
115
+ : undefined;
116
+ const reason = nativeReason === undefined ? 'unknown' : (_b = bondFailureReasons[nativeReason]) !== null && _b !== void 0 ? _b : 'unknown';
117
+ const params = Object.assign({ phase: 'bond', reason }, (nativeReason === undefined ? {} : { nativeReason }));
118
+ if (reason === 'timeout') {
119
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', params));
120
+ }
121
+ else if (reason === 'canceled') {
122
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'Bluetooth pairing canceled', params));
123
+ }
124
+ else {
125
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing failed', params));
126
+ }
90
127
  }
91
128
  });
92
129
  });
@@ -194,6 +231,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
194
231
  }, ms);
195
232
  });
196
233
 
234
+ const BLE_PLX_DEVICE_DISCONNECTED = 201;
235
+ const IOS_PERIPHERAL_DISCONNECTED = 7;
236
+ const nativeErrorText$1 = (error) => [error.reason, error.message]
237
+ .filter((value) => typeof value === 'string')
238
+ .join(' ');
239
+ const isNativeBleDisconnectError = (error) => {
240
+ if (!error || typeof error !== 'object') {
241
+ return false;
242
+ }
243
+ const nativeError = error;
244
+ return (nativeError.errorCode === BLE_PLX_DEVICE_DISCONNECTED ||
245
+ nativeError.iosErrorCode === IOS_PERIPHERAL_DISCONNECTED);
246
+ };
247
+ const toBleDisconnectHardwareError = (error) => {
248
+ if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
249
+ return error;
250
+ }
251
+ const nativeError = (error !== null && error !== void 0 ? error : {});
252
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, nativeErrorText$1(nativeError) || undefined);
253
+ };
254
+
197
255
  const ATT_INSUFFICIENT_AUTHENTICATION = 5;
198
256
  const ATT_INSUFFICIENT_ENCRYPTION = 15;
199
257
  const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
@@ -207,6 +265,8 @@ const isNativeBleStaleBondError = (error) => {
207
265
  const nativeError = error;
208
266
  if (nativeError.attErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
209
267
  nativeError.attErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
268
+ nativeError.androidErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
269
+ nativeError.androidErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
210
270
  nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION) {
211
271
  return true;
212
272
  }
@@ -256,6 +316,7 @@ class BleTransport {
256
316
  const { check, ProtocolV1, parseConfigure } = transport__default["default"];
257
317
  const Log = bleLogger;
258
318
  const transportCache = {};
319
+ let bleManagerResetPromise;
259
320
  const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
260
321
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
261
322
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
@@ -314,6 +375,17 @@ const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
314
375
  const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
315
376
  typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
316
377
  error.message.startsWith(WEDGED_WRITE_MESSAGE);
378
+ const shouldRethrowProtocolProbeError = (error) => {
379
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
380
+ return (hdShared.isBleStaleBondHardwareError(error) ||
381
+ isNativeBleDisconnectError(error) ||
382
+ code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
383
+ code === hdShared.HardwareErrorCode.BleDeviceBondedCanceled ||
384
+ code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
385
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
386
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
387
+ code === hdShared.HardwareErrorCode.BleWriteCharacteristicError);
388
+ };
317
389
  const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
318
390
  const DEVICE_SCAN_TIMEOUT_MS = 3000;
319
391
  const IOS_NOTIFY_READY_DELAY_MS = 150;
@@ -348,10 +420,10 @@ function getDeviceDisplayName(device) {
348
420
  }
349
421
  const IOS_REQUEST_MTU = 247;
350
422
  const ANDROID_REQUEST_MTU = 517;
351
- const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
352
423
  const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
353
424
  const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
354
425
  const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
426
+ const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
355
427
  const connectOptions = {
356
428
  requestMTU: getRequestedBleMtu(),
357
429
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
@@ -360,6 +432,29 @@ const connectOptions = {
360
432
  const fallbackConnectOptions = {
361
433
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
362
434
  };
435
+ const androidRefreshGattConnectOptions = {
436
+ timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
437
+ refreshGatt: 'OnConnected',
438
+ };
439
+ const ANDROID_MTU_EXCHANGE_TIMEOUT_MS = 12000;
440
+ const ANDROID_LINK_DROP_QUIET_MS = 5000;
441
+ const ANDROID_LINK_DROP_POLL_MS = 250;
442
+ const isKnownDefaultMtu = (mtu) => typeof mtu === 'number' && Number.isFinite(mtu) && mtu <= 23;
443
+ const isMissingGattShapeError = (error) => {
444
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
445
+ const message = error === null || error === void 0 ? void 0 : error.message;
446
+ return (code === hdShared.HardwareErrorCode.BleServiceNotFound ||
447
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotFound ||
448
+ (typeof message === 'string' &&
449
+ (message.includes('BLECharacteristicNotFound') ||
450
+ message.includes('BLECharacteristicNotWritable') ||
451
+ message.includes('BLECharacteristicNotNotifiable'))));
452
+ };
453
+ const isStaleGattTableNotifyReason = (reason) => !!reason &&
454
+ (reason.includes('Cannot write client characteristic config descriptor') ||
455
+ reason.includes('Cannot find client characteristic config descriptor') ||
456
+ reason.includes('The handle is invalid') ||
457
+ reason.includes('Writing is not permitted'));
363
458
  const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
364
459
  const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
365
460
  const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
@@ -374,6 +469,11 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
374
469
  error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
375
470
  const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
376
471
  const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
472
+ const isMtuOrCancelledConnectError = (error) => {
473
+ const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
474
+ return (errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
475
+ errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
476
+ };
377
477
  const tryToGetConfiguration = (device) => {
378
478
  if (!device || !device.serviceUUIDs)
379
479
  return null;
@@ -385,29 +485,69 @@ const tryToGetConfiguration = (device) => {
385
485
  return null;
386
486
  return infos;
387
487
  };
388
- const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
488
+ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
389
489
  if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
390
- return device;
490
+ return { device, timedOut: false };
491
+ const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
492
+ let timeoutId;
493
+ let timedOut = false;
391
494
  try {
392
- const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
393
- return mtuDevice;
495
+ const request = device.requestMTU(getRequestedBleMtu(), transactionId);
496
+ request.catch(() => undefined);
497
+ const mtuDevice = yield Promise.race([
498
+ request,
499
+ new Promise((_, reject) => {
500
+ timeoutId = setTimeout(() => {
501
+ timedOut = true;
502
+ reject(new Error(`BLE MTU request timeout after ${BLE_MTU_REQUEST_TIMEOUT_MS}ms`));
503
+ }, BLE_MTU_REQUEST_TIMEOUT_MS);
504
+ }),
505
+ ]);
506
+ return { device: mtuDevice, timedOut: false };
394
507
  }
395
508
  catch (error) {
509
+ if (timedOut && cancelTransaction) {
510
+ try {
511
+ Promise.resolve(cancelTransaction(transactionId)).catch(cancelError => {
512
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
513
+ platform: reactNative.Platform.OS,
514
+ stage,
515
+ attempt,
516
+ error: cancelError instanceof Error ? cancelError.message : String(cancelError),
517
+ });
518
+ });
519
+ }
520
+ catch (cancelError) {
521
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
522
+ platform: reactNative.Platform.OS,
523
+ stage,
524
+ attempt,
525
+ error: cancelError instanceof Error ? cancelError.message : String(cancelError),
526
+ });
527
+ }
528
+ }
396
529
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
397
530
  platform: reactNative.Platform.OS,
398
531
  stage,
399
532
  attempt,
400
533
  actual: device.mtu,
534
+ timedOut,
401
535
  error: error instanceof Error ? error.message : String(error),
402
536
  });
403
- return device;
537
+ return { device, timedOut };
538
+ }
539
+ finally {
540
+ if (timeoutId)
541
+ clearTimeout(timeoutId);
404
542
  }
405
543
  });
406
- const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
407
- function remapError(error, mapProtocolV2StaleBond) {
544
+ const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
545
+ ? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
546
+ : Promise.resolve({ device, timedOut: false });
547
+ function remapError(error) {
408
548
  var _a;
409
549
  if (error instanceof reactNativeBlePlx.BleError) {
410
- if (mapProtocolV2StaleBond && isNativeBleStaleBondError(error)) {
550
+ if (isNativeBleStaleBondError(error)) {
411
551
  throw toBleStaleBondHardwareError(error);
412
552
  }
413
553
  if ((error === null || error === void 0 ? void 0 : error.attErrorCode) === 22) {
@@ -427,6 +567,7 @@ class ReactNativeBleTransport {
427
567
  this.name = 'ReactNativeBleTransport';
428
568
  this.configured = false;
429
569
  this.stopped = false;
570
+ this.bondAbortController = new AbortController();
430
571
  this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
431
572
  this.runPromise = null;
432
573
  this.runPromiseDeviceId = null;
@@ -439,6 +580,8 @@ class ReactNativeBleTransport {
439
580
  this.sessionProtocols = new Map();
440
581
  this.confirmedProtocolV2 = new Set();
441
582
  this.protocolReprobeFailures = new Map();
583
+ this.silentDetections = new Map();
584
+ this.androidGattCacheRefreshes = new Set();
442
585
  this.staleBondErrors = new Map();
443
586
  this.acquiringProtocolV2 = new Set();
444
587
  this.protocolV2Assemblers = new Map();
@@ -456,11 +599,20 @@ class ReactNativeBleTransport {
456
599
  },
457
600
  classifyError: () => 'link-fatal',
458
601
  onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
459
- var _b;
602
+ var _b, _c;
460
603
  (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
461
604
  this.rejectProtocolV2Frames(uuid, new Error(reason));
462
605
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
463
606
  if (reason.startsWith('Protocol V2 link-fatal error:')) {
607
+ if (this.probingProtocols.get(uuid) !== 'V2') {
608
+ const transport = transportCache[uuid];
609
+ try {
610
+ this.emitDeviceDisconnect(uuid, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, transport === null || transport === void 0 ? void 0 : transport.monitorToken);
611
+ }
612
+ catch (_d) {
613
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 disconnect listener failed');
614
+ }
615
+ }
464
616
  yield this.releaseNative(uuid, true);
465
617
  }
466
618
  }),
@@ -472,6 +624,7 @@ class ReactNativeBleTransport {
472
624
  this.androidPriorityResetTimers = new Map();
473
625
  this.nextMonitorToken = 1;
474
626
  this.lifecycleOperations = new Map();
627
+ this.scanCleanups = new Set();
475
628
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
476
629
  }
477
630
  init(logger, emitter) {
@@ -500,10 +653,38 @@ class ReactNativeBleTransport {
500
653
  listen() {
501
654
  }
502
655
  getPlxManager() {
503
- if (this.blePlxManager)
504
- return Promise.resolve(this.blePlxManager);
505
- this.blePlxManager = new reactNativeBlePlx.BleManager();
506
- return Promise.resolve(this.blePlxManager);
656
+ return __awaiter(this, void 0, void 0, function* () {
657
+ while (bleManagerResetPromise) {
658
+ yield this.waitForManagerReset();
659
+ }
660
+ if (this.stopped)
661
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
662
+ if (!this.blePlxManager)
663
+ this.blePlxManager = new reactNativeBlePlx.BleManager();
664
+ return this.blePlxManager;
665
+ });
666
+ }
667
+ waitForManagerReset() {
668
+ return __awaiter(this, void 0, void 0, function* () {
669
+ if (!bleManagerResetPromise)
670
+ return;
671
+ let timeout;
672
+ try {
673
+ yield Promise.race([
674
+ bleManagerResetPromise,
675
+ new Promise((_, reject) => {
676
+ timeout = setTimeout(() => reject(this.createWedgedBleSetupError()), BLE_CONNECT_TIMEOUT_MS);
677
+ }),
678
+ ]);
679
+ }
680
+ catch (_a) {
681
+ throw this.createWedgedBleSetupError();
682
+ }
683
+ finally {
684
+ if (timeout)
685
+ clearTimeout(timeout);
686
+ }
687
+ });
507
688
  }
508
689
  resolveCharacteristics(device) {
509
690
  return __awaiter(this, void 0, void 0, function* () {
@@ -668,30 +849,55 @@ class ReactNativeBleTransport {
668
849
  }
669
850
  enumerate() {
670
851
  return __awaiter(this, void 0, void 0, function* () {
671
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
672
- const deviceList = [];
673
- const blePlxManager = yield this.getPlxManager();
674
- try {
675
- yield subscribeBleOn(blePlxManager);
676
- }
677
- catch (error) {
678
- Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
679
- reject(error);
680
- return;
681
- }
682
- if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
683
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
684
- const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
685
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
686
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
687
- ]);
688
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
689
- if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
690
- resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
691
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
692
- return;
693
- }
852
+ const scanStartedAt = Date.now();
853
+ let firstDeviceMs;
854
+ const blePlxManager = yield this.getPlxManager();
855
+ yield subscribeBleOn(blePlxManager);
856
+ if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
857
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
858
+ const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
859
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
860
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
861
+ ]);
862
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
863
+ if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
864
+ resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
865
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
694
866
  }
867
+ }
868
+ if (this.stopped)
869
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
870
+ return new Promise((resolve, reject) => {
871
+ const deviceList = [];
872
+ let finished = false;
873
+ let scanCleanup;
874
+ const finishScan = (error) => {
875
+ if (scanCleanup)
876
+ return scanCleanup;
877
+ finished = true;
878
+ clearScanTimer();
879
+ scanCleanup = this.runNativeTeardown('scan', blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
880
+ yield blePlxManager.stopDeviceScan();
881
+ })).then(() => {
882
+ this.scanCleanups.delete(cancelScan);
883
+ if (error)
884
+ reject(error);
885
+ else
886
+ resolve(deviceList);
887
+ });
888
+ return scanCleanup;
889
+ };
890
+ const cancelScan = () => finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
891
+ this.scanCleanups.add(cancelScan);
892
+ const clearScanTimer = timer.timeout(() => {
893
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan completed', {
894
+ elapsedMs: Date.now() - scanStartedAt,
895
+ firstDeviceMs,
896
+ deviceCount: deviceList.length,
897
+ scanWindowMs: this.scanTimeout,
898
+ });
899
+ finishScan();
900
+ }, this.scanTimeout);
695
901
  blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
696
902
  allowDuplicates: true,
697
903
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
@@ -700,19 +906,17 @@ class ReactNativeBleTransport {
700
906
  if (error) {
701
907
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
702
908
  if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
703
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
909
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
704
910
  }
705
911
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
706
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
912
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
707
913
  }
708
914
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
709
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
710
- }
711
- else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
712
- timer.timeout(() => { }, this.scanTimeout);
915
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
713
916
  }
917
+ else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
714
918
  else {
715
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
919
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
716
920
  }
717
921
  return;
718
922
  }
@@ -737,6 +941,8 @@ class ReactNativeBleTransport {
737
941
  });
738
942
  }
739
943
  });
944
+ if (finished)
945
+ return;
740
946
  getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
741
947
  for (const device of devices) {
742
948
  const localName = 'localName' in device && typeof device.localName === 'string'
@@ -752,10 +958,11 @@ class ReactNativeBleTransport {
752
958
  addDevice(device);
753
959
  }
754
960
  }
755
- });
961
+ }, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
756
962
  const addDevice = (device) => {
757
963
  var _a;
758
- if (deviceList.every(d => d.id !== device.id)) {
964
+ if (!finished && deviceList.every(d => d.id !== device.id)) {
965
+ firstDeviceMs !== null && firstDeviceMs !== void 0 ? firstDeviceMs : (firstDeviceMs = Date.now() - scanStartedAt);
759
966
  const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
760
967
  deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
761
968
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
@@ -765,16 +972,14 @@ class ReactNativeBleTransport {
765
972
  });
766
973
  }
767
974
  };
768
- timer.timeout(() => {
769
- blePlxManager.stopDeviceScan();
770
- resolve(deviceList);
771
- }, this.scanTimeout);
772
- }));
975
+ });
773
976
  });
774
977
  }
775
978
  installTransportForAcquire(uuid, device, characteristics) {
776
979
  return __awaiter(this, void 0, void 0, function* () {
777
980
  const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
981
+ if (this.stopped)
982
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
778
983
  const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
779
984
  transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
780
985
  const monitorToken = this.nextMonitorToken;
@@ -795,30 +1000,12 @@ class ReactNativeBleTransport {
795
1000
  else if (reactNative.Platform.OS === 'android') {
796
1001
  yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
797
1002
  }
798
- const initialMtu = transport$1.mtuSize;
799
- let refreshAttempts = 0;
800
- if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
801
- shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
802
- refreshAttempts += 1;
803
- let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
804
- transport$1.device = refreshedDevice;
805
- transport$1.mtuSize =
806
- typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
807
- if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
808
- yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
809
- refreshAttempts += 1;
810
- refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
811
- transport$1.device = refreshedDevice;
812
- transport$1.mtuSize =
813
- typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
814
- }
815
- }
1003
+ if (this.stopped)
1004
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
816
1005
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
817
1006
  platform: reactNative.Platform.OS,
818
1007
  requested: getRequestedBleMtu(),
819
- initial: initialMtu,
820
1008
  actual: transport$1.mtuSize,
821
- refreshAttempts,
822
1009
  });
823
1010
  return transport$1;
824
1011
  });
@@ -835,6 +1022,8 @@ class ReactNativeBleTransport {
835
1022
  acquireUnlocked(input) {
836
1023
  var _a;
837
1024
  return __awaiter(this, void 0, void 0, function* () {
1025
+ if (this.stopped)
1026
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
838
1027
  const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
839
1028
  const shouldMapProtocolV2StaleBond = expectedProtocol
840
1029
  ? expectedProtocol === 'V2'
@@ -866,9 +1055,13 @@ class ReactNativeBleTransport {
866
1055
  const isCachedDeviceConnected = yield cachedTransport.device
867
1056
  .isConnected()
868
1057
  .catch(() => false);
1058
+ const isCachedAndroidLinkUsable = reactNative.Platform.OS !== 'android' || !this.androidGattCacheRefreshes.has(uuid);
869
1059
  if (isCachedDeviceConnected &&
1060
+ isCachedAndroidLinkUsable &&
870
1061
  cachedProtocol &&
871
1062
  (!expectedProtocol || cachedProtocol === expectedProtocol)) {
1063
+ if (this.stopped)
1064
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
872
1065
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
873
1066
  return { uuid, protocolType: cachedProtocol };
874
1067
  }
@@ -877,6 +1070,15 @@ class ReactNativeBleTransport {
877
1070
  }
878
1071
  }
879
1072
  let device = null;
1073
+ const isAndroid = reactNative.Platform.OS === 'android';
1074
+ const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
1075
+ let nativeConnectOptions = connectOptions;
1076
+ if (isAndroid) {
1077
+ nativeConnectOptions = refreshAndroidGattCache
1078
+ ? androidRefreshGattConnectOptions
1079
+ : fallbackConnectOptions;
1080
+ }
1081
+ let androidRefreshConnectRan = false;
880
1082
  if (forceCleanRunPromise && this.runPromise) {
881
1083
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
882
1084
  this.runPromise.reject(error);
@@ -885,6 +1087,7 @@ class ReactNativeBleTransport {
885
1087
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
886
1088
  }
887
1089
  const blePlxManager = yield this.getPlxManager();
1090
+ let skipPostConnectMtu = false;
888
1091
  try {
889
1092
  yield subscribeBleOn(blePlxManager);
890
1093
  }
@@ -892,15 +1095,27 @@ class ReactNativeBleTransport {
892
1095
  Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
893
1096
  throw error;
894
1097
  }
1098
+ if (this.stopped)
1099
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
895
1100
  if (reactNative.Platform.OS === 'android') {
896
- const bondState = yield pairDevice(uuid);
897
- if (bondState.bonding) {
898
- yield onDeviceBondState(uuid);
1101
+ try {
1102
+ const bondState = yield pairDevice(uuid);
1103
+ if (bondState.bonding) {
1104
+ yield onDeviceBondState(uuid, this.bondAbortController.signal);
1105
+ }
1106
+ else if (!bondState.bonded) {
1107
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
1108
+ }
899
1109
  }
900
- else if (!bondState.bonded) {
901
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
1110
+ catch (error) {
1111
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1112
+ yield this.runBestEffortNativeOperation('bond failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
1113
+ }));
1114
+ throw error;
902
1115
  }
903
1116
  }
1117
+ if (this.stopped)
1118
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
904
1119
  if (!device) {
905
1120
  const devices = yield blePlxManager.devices([uuid]);
906
1121
  [device] = devices;
@@ -914,15 +1129,16 @@ class ReactNativeBleTransport {
914
1129
  if (!device) {
915
1130
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
916
1131
  try {
917
- device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
1132
+ device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, nativeConnectOptions));
1133
+ androidRefreshConnectRan = refreshAndroidGattCache;
918
1134
  }
919
1135
  catch (e) {
920
1136
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
921
1137
  if (shouldRethrowBleSetupError(e)) {
922
1138
  throw e;
923
1139
  }
924
- if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
925
- e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
1140
+ if (isMtuOrCancelledConnectError(e)) {
1141
+ skipPostConnectMtu = true;
926
1142
  Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
927
1143
  device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
928
1144
  }
@@ -931,47 +1147,119 @@ class ReactNativeBleTransport {
931
1147
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleAlreadyConnected);
932
1148
  }
933
1149
  else {
934
- remapError(e, shouldMapProtocolV2StaleBond);
1150
+ remapError(e);
935
1151
  }
936
1152
  }
937
1153
  }
938
1154
  if (!device) {
939
1155
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'unable to connect to device');
940
1156
  }
1157
+ if (refreshAndroidGattCache &&
1158
+ !androidRefreshConnectRan &&
1159
+ (yield device.isConnected().catch(() => false))) {
1160
+ yield this.dropAndroidLink(uuid, blePlxManager, device, 'gatt cache refresh');
1161
+ if (this.stopped)
1162
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1163
+ }
941
1164
  if (!(yield device.isConnected())) {
942
1165
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
943
1166
  const disconnectedDevice = device;
944
1167
  try {
945
- device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
1168
+ device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(nativeConnectOptions));
1169
+ androidRefreshConnectRan = refreshAndroidGattCache;
946
1170
  }
947
1171
  catch (e) {
948
1172
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
949
1173
  if (shouldRethrowBleSetupError(e)) {
950
1174
  throw e;
951
1175
  }
952
- if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
953
- e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
1176
+ if (isMtuOrCancelledConnectError(e)) {
1177
+ skipPostConnectMtu = true;
954
1178
  Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
955
1179
  try {
956
1180
  device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
957
1181
  }
958
- catch (e) {
959
- Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
960
- if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
1182
+ catch (fallbackError) {
1183
+ Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', fallbackError);
1184
+ if (fallbackError.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
961
1185
  Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
962
1186
  yield disconnectedDevice.cancelConnection();
963
1187
  device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
964
1188
  }
1189
+ else {
1190
+ remapError(fallbackError);
1191
+ }
965
1192
  }
966
1193
  }
967
1194
  else {
968
- remapError(e, shouldMapProtocolV2StaleBond);
1195
+ remapError(e);
1196
+ }
1197
+ }
1198
+ }
1199
+ if (this.stopped)
1200
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1201
+ if (reactNative.Platform.OS === 'android' && !(yield device.isConnected().catch(() => false))) {
1202
+ const disconnectedDevice = device;
1203
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1204
+ yield Promise.all([
1205
+ this.runBestEffortNativeOperation('connect failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid)),
1206
+ this.runBestEffortNativeOperation('connect failure: cancel device connection', () => disconnectedDevice.cancelConnection()),
1207
+ ]);
1208
+ }));
1209
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'device is not connected');
1210
+ }
1211
+ if (this.stopped)
1212
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1213
+ let characteristics;
1214
+ if (isAndroid) {
1215
+ if (refreshAndroidGattCache) {
1216
+ characteristics = yield this.resolveCharacteristicsWithTimeout(uuid, device);
1217
+ if (androidRefreshConnectRan)
1218
+ this.androidGattCacheRefreshes.delete(uuid);
1219
+ if (this.stopped)
1220
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1221
+ }
1222
+ device = yield this.negotiateAndroidMtu(uuid, blePlxManager, device);
1223
+ }
1224
+ else if (!skipPostConnectMtu) {
1225
+ const mtuResult = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
1226
+ device = mtuResult.device;
1227
+ if (mtuResult.timedOut) {
1228
+ if (this.stopped)
1229
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1230
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] post-connect MTU timed out, reconnecting without requesting MTU');
1231
+ const timedOutDevice = device;
1232
+ let mtuTeardownSettled = false;
1233
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1234
+ yield this.runBestEffortNativeOperation('mtu timeout: cancel device connection', () => timedOutDevice.cancelConnection());
1235
+ mtuTeardownSettled = true;
1236
+ }));
1237
+ if (this.stopped)
1238
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1239
+ if (!mtuTeardownSettled || this.blePlxManager !== blePlxManager) {
1240
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'BLE MTU cleanup timed out');
1241
+ }
1242
+ try {
1243
+ device = yield this.connectWithTimeout(uuid, () => timedOutDevice.connect(fallbackConnectOptions));
1244
+ }
1245
+ catch (error) {
1246
+ if (shouldRethrowBleSetupError(error))
1247
+ throw error;
1248
+ if ((error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
1249
+ device = timedOutDevice;
1250
+ }
1251
+ else {
1252
+ remapError(error);
1253
+ }
969
1254
  }
970
1255
  }
971
1256
  }
972
- device = yield resolveNegotiatedMtu(device);
1257
+ if (this.stopped)
1258
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
973
1259
  const acquiredDevice = device;
974
- const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
1260
+ const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice));
1261
+ if (this.stopped)
1262
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
975
1263
  const protocolHint = expectedProtocol
976
1264
  ? undefined
977
1265
  : (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
@@ -1014,6 +1302,8 @@ class ReactNativeBleTransport {
1014
1302
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
1015
1303
  yield this.installTransportForAcquire(uuid, acquiredDevice);
1016
1304
  }));
1305
+ if (this.stopped)
1306
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1017
1307
  const currentTransport = transportCache[uuid];
1018
1308
  if (!currentTransport) {
1019
1309
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
@@ -1022,12 +1312,7 @@ class ReactNativeBleTransport {
1022
1312
  return { uuid, protocolType };
1023
1313
  }
1024
1314
  catch (error) {
1025
- if (hdShared.isBleStaleBondHardwareError(error)) {
1026
- yield this.disconnectUnlocked(uuid);
1027
- }
1028
- else {
1029
- yield this.releaseUnlocked(uuid, true);
1030
- }
1315
+ yield this.disconnectUnlocked(uuid);
1031
1316
  throw error;
1032
1317
  }
1033
1318
  finally {
@@ -1039,7 +1324,7 @@ class ReactNativeBleTransport {
1039
1324
  let bufferLength = 0;
1040
1325
  let buffer$1 = [];
1041
1326
  const subscription = characteristic.monitor((error, c) => {
1042
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1327
+ var _a, _b, _c, _d, _e, _f;
1043
1328
  const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
1044
1329
  if (error) {
1045
1330
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
@@ -1056,16 +1341,16 @@ class ReactNativeBleTransport {
1056
1341
  this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
1057
1342
  return;
1058
1343
  }
1344
+ if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
1345
+ this.androidGattCacheRefreshes.add(uuid);
1346
+ }
1059
1347
  if (this.getActiveProtocol(uuid) === 'V2') {
1060
1348
  let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
1061
1349
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
1062
1350
  errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
1063
1351
  }
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'))) {
1352
+ else if (isStaleGattTableNotifyReason(error.reason) ||
1353
+ ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('notify change failed for device'))) {
1069
1354
  errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
1070
1355
  }
1071
1356
  this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
@@ -1073,14 +1358,11 @@ class ReactNativeBleTransport {
1073
1358
  }
1074
1359
  if (this.runPromise && this.runPromiseDeviceId === uuid) {
1075
1360
  let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
1076
- if ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('The connection has timed out unexpectedly')) {
1361
+ if ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('The connection has timed out unexpectedly')) {
1077
1362
  ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
1078
1363
  }
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'))) {
1364
+ if (isStaleGattTableNotifyReason(error.reason) ||
1365
+ ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('notify change failed for device'))) {
1084
1366
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
1085
1367
  this.runPromise.reject(notifyError);
1086
1368
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
@@ -1122,7 +1404,7 @@ class ReactNativeBleTransport {
1122
1404
  bufferLength = 0;
1123
1405
  buffer$1 = [];
1124
1406
  if (this.runPromiseDeviceId === uuid) {
1125
- (_o = this.runPromise) === null || _o === void 0 ? void 0 : _o.resolve(value.toString('hex'));
1407
+ (_e = this.runPromise) === null || _e === void 0 ? void 0 : _e.resolve(value.toString('hex'));
1126
1408
  }
1127
1409
  }
1128
1410
  }
@@ -1133,7 +1415,7 @@ class ReactNativeBleTransport {
1133
1415
  this.rejectProtocolV2Frames(uuid, notifyError);
1134
1416
  }
1135
1417
  else if (this.runPromiseDeviceId === uuid) {
1136
- (_p = this.runPromise) === null || _p === void 0 ? void 0 : _p.reject(notifyError);
1418
+ (_f = this.runPromise) === null || _f === void 0 ? void 0 : _f.reject(notifyError);
1137
1419
  }
1138
1420
  }
1139
1421
  }, notifyTransactionId);
@@ -1409,13 +1691,14 @@ class ReactNativeBleTransport {
1409
1691
  return check.call(jsonData);
1410
1692
  }
1411
1693
  catch (e) {
1412
- if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
1413
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
1694
+ const isProbeTimeout = (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS &&
1695
+ (name === 'GetFeatures' || name === 'Initialize');
1696
+ if (isProbeTimeout) {
1697
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] Protocol V1 ${name} probe call failed:`, e);
1414
1698
  }
1415
1699
  else {
1416
1700
  Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1417
1701
  }
1418
- const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
1419
1702
  const isStaleCall = this.runPromise !== runPromise;
1420
1703
  if (!isProbeTimeout &&
1421
1704
  !isStaleCall &&
@@ -1435,7 +1718,43 @@ class ReactNativeBleTransport {
1435
1718
  });
1436
1719
  }
1437
1720
  stop() {
1721
+ var _a;
1722
+ if (this.stopPromise)
1723
+ return this.stopPromise;
1438
1724
  this.stopped = true;
1725
+ this.bondAbortController.abort();
1726
+ const deviceIds = new Set([
1727
+ ...this.monitorTokens.keys(),
1728
+ ...this.sessionProtocols.keys(),
1729
+ ...this.lifecycleOperations.keys(),
1730
+ ...(this.runPromiseDeviceId ? [this.runPromiseDeviceId] : []),
1731
+ ]);
1732
+ const scans = Array.from(this.scanCleanups, cleanup => cleanup());
1733
+ this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
1734
+ this.androidPriorityResetTimers.clear();
1735
+ this.androidHighPriorityDevices.clear();
1736
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1737
+ (_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
1738
+ this.runPromise = null;
1739
+ this.runPromiseDeviceId = null;
1740
+ deviceIds.forEach(uuid => this.rejectProtocolV2Frames(uuid, error));
1741
+ const manager = this.blePlxManager;
1742
+ const pendingConnections = manager
1743
+ ? Array.from(this.lifecycleOperations.keys(), uuid => this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
1744
+ yield this.runBestEffortNativeOperation('stop: cancel pending device connection', () => manager.cancelDeviceConnection(uuid));
1745
+ })))
1746
+ : [];
1747
+ this.stopPromise = Promise.all([
1748
+ ...scans,
1749
+ ...pendingConnections,
1750
+ ...Array.from(deviceIds, uuid => this.disconnect(uuid)),
1751
+ ]).then(() => __awaiter(this, void 0, void 0, function* () {
1752
+ yield this.protocolV2Links.invalidateAllLinks('React Native BLE transport stopped');
1753
+ yield this.waitForManagerReset();
1754
+ this.blePlxManager = undefined;
1755
+ this.emitter = undefined;
1756
+ }));
1757
+ return this.stopPromise;
1439
1758
  }
1440
1759
  disconnect(session) {
1441
1760
  return __awaiter(this, void 0, void 0, function* () {
@@ -1565,13 +1884,93 @@ class ReactNativeBleTransport {
1565
1884
  });
1566
1885
  }
1567
1886
  cancel() {
1568
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1569
- if (this.runPromise) ;
1570
- this.runPromise = null;
1571
- this.runPromiseDeviceId = null;
1887
+ return __awaiter(this, void 0, void 0, function* () {
1888
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1889
+ const pending = this.runPromise;
1890
+ const deviceId = this.runPromiseDeviceId;
1891
+ if (pending) {
1892
+ pending.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
1893
+ if (this.runPromise === pending) {
1894
+ this.runPromise = null;
1895
+ this.runPromiseDeviceId = null;
1896
+ }
1897
+ if (deviceId)
1898
+ yield this.disconnect(deviceId);
1899
+ }
1900
+ });
1901
+ }
1902
+ negotiateAndroidMtu(uuid, manager, device) {
1903
+ return __awaiter(this, void 0, void 0, function* () {
1904
+ if (!shouldRefreshNegotiatedMtu(device.mtu))
1905
+ return device;
1906
+ const startedAt = Date.now();
1907
+ let timer;
1908
+ let timedOut = false;
1909
+ let negotiated = device;
1910
+ let failure;
1911
+ try {
1912
+ negotiated = yield Promise.race([
1913
+ device.requestMTU(ANDROID_REQUEST_MTU, `${device.id}:mtu:connected:0:${startedAt}`),
1914
+ new Promise((_, reject) => {
1915
+ timer = setTimeout(() => {
1916
+ timedOut = true;
1917
+ reject(new Error(`BLE MTU exchange timeout after ${ANDROID_MTU_EXCHANGE_TIMEOUT_MS}ms`));
1918
+ }, ANDROID_MTU_EXCHANGE_TIMEOUT_MS);
1919
+ }),
1920
+ ]);
1921
+ }
1922
+ catch (error) {
1923
+ failure = error instanceof Error ? error.message : String(error);
1924
+ }
1925
+ finally {
1926
+ if (timer)
1927
+ clearTimeout(timer);
1928
+ }
1929
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] BLE MTU exchange ${failure ? 'failed' : 'completed'}`, {
1930
+ connectIdSuffix: uuid.slice(-8),
1931
+ elapsedMs: Date.now() - startedAt,
1932
+ timedOut,
1933
+ actual: negotiated.mtu,
1934
+ error: failure,
1935
+ });
1936
+ if (this.stopped)
1937
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1938
+ if (!timedOut && !isKnownDefaultMtu(negotiated.mtu))
1939
+ return negotiated;
1940
+ const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'mtu-backstop' : 'mtu-default');
1941
+ yield this.dropAndroidLink(uuid, manager, negotiated, timedOut ? 'mtu exchange timeout' : 'default mtu');
1942
+ if (resetManager)
1943
+ throw this.createWedgedBleSetupError();
1944
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, timedOut
1945
+ ? 'BLE MTU exchange did not complete, reconnecting on a fresh link'
1946
+ : `BLE link stayed at the default MTU ${negotiated.mtu}, reconnecting on a fresh link`);
1947
+ });
1948
+ }
1949
+ dropAndroidLink(uuid, manager, device, reason) {
1950
+ return __awaiter(this, void 0, void 0, function* () {
1951
+ yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
1952
+ yield Promise.all([
1953
+ this.runBestEffortNativeOperation(`${reason}: cancel manager connection`, () => manager.cancelDeviceConnection(uuid)),
1954
+ this.runBestEffortNativeOperation(`${reason}: cancel device connection`, () => device.cancelConnection()),
1955
+ ]);
1956
+ }));
1957
+ const startedAt = Date.now();
1958
+ while (!this.stopped && Date.now() - startedAt < ANDROID_LINK_DROP_QUIET_MS) {
1959
+ yield delay(ANDROID_LINK_DROP_POLL_MS);
1960
+ }
1961
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE link drop', {
1962
+ connectIdSuffix: uuid.slice(-8),
1963
+ reason,
1964
+ stopped: this.stopped,
1965
+ });
1966
+ });
1572
1967
  }
1573
1968
  connectWithTimeout(uuid, connect) {
1574
1969
  return __awaiter(this, void 0, void 0, function* () {
1970
+ if (this.stopped)
1971
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1972
+ const startedAt = Date.now();
1973
+ let succeeded = false;
1575
1974
  let timer;
1576
1975
  let timedOut = false;
1577
1976
  const pending = connect();
@@ -1586,6 +1985,7 @@ class ReactNativeBleTransport {
1586
1985
  }, BLE_CONNECT_TIMEOUT_MS);
1587
1986
  }),
1588
1987
  ]);
1988
+ succeeded = true;
1589
1989
  return result;
1590
1990
  }
1591
1991
  catch (error) {
@@ -1600,11 +2000,19 @@ class ReactNativeBleTransport {
1600
2000
  finally {
1601
2001
  if (timer)
1602
2002
  clearTimeout(timer);
2003
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] connect completed', {
2004
+ connectIdSuffix: uuid.slice(-8),
2005
+ elapsedMs: Date.now() - startedAt,
2006
+ succeeded,
2007
+ backstopExpired: timedOut,
2008
+ });
1603
2009
  }
1604
2010
  });
1605
2011
  }
1606
2012
  resolveCharacteristicsWithTimeout(uuid, device) {
1607
2013
  return __awaiter(this, void 0, void 0, function* () {
2014
+ const startedAt = Date.now();
2015
+ let succeeded = false;
1608
2016
  let timer;
1609
2017
  let timedOut = false;
1610
2018
  const pending = this.resolveCharacteristics(device);
@@ -1620,6 +2028,7 @@ class ReactNativeBleTransport {
1620
2028
  }),
1621
2029
  ]);
1622
2030
  this.connectionSetupTimeoutCounts.delete(uuid);
2031
+ succeeded = true;
1623
2032
  return result;
1624
2033
  }
1625
2034
  catch (error) {
@@ -1629,11 +2038,20 @@ class ReactNativeBleTransport {
1629
2038
  throw this.createWedgedBleSetupError();
1630
2039
  }
1631
2040
  }
2041
+ if (reactNative.Platform.OS === 'android' && isMissingGattShapeError(error)) {
2042
+ this.androidGattCacheRefreshes.add(uuid);
2043
+ }
1632
2044
  throw error;
1633
2045
  }
1634
2046
  finally {
1635
2047
  if (timer)
1636
2048
  clearTimeout(timer);
2049
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] GATT setup completed', {
2050
+ connectIdSuffix: uuid.slice(-8),
2051
+ elapsedMs: Date.now() - startedAt,
2052
+ succeeded,
2053
+ backstopExpired: timedOut,
2054
+ });
1637
2055
  }
1638
2056
  });
1639
2057
  }
@@ -1735,6 +2153,8 @@ class ReactNativeBleTransport {
1735
2153
  }
1736
2154
  }
1737
2155
  resetPlxManager() {
2156
+ if (bleManagerResetPromise)
2157
+ return;
1738
2158
  const manager = this.blePlxManager;
1739
2159
  this.blePlxManager = undefined;
1740
2160
  const reason = 'React Native BLE manager reset';
@@ -1772,16 +2192,25 @@ class ReactNativeBleTransport {
1772
2192
  this.acquiringProtocolV2.clear();
1773
2193
  this.sessionProtocols.clear();
1774
2194
  this.protocolReprobeFailures.clear();
2195
+ this.silentDetections.clear();
1775
2196
  this.writeTimeoutCounts.clear();
1776
2197
  this.connectionSetupTimeoutCounts.clear();
1777
2198
  this.monitorTokens.clear();
1778
2199
  this.protocolV2Assemblers.clear();
2200
+ let reset;
1779
2201
  try {
1780
- manager === null || manager === void 0 ? void 0 : manager.destroy();
2202
+ reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
1781
2203
  }
1782
2204
  catch (error) {
1783
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
2205
+ reset = Promise.reject(error);
1784
2206
  }
2207
+ bleManagerResetPromise = reset;
2208
+ reset.then(() => {
2209
+ if (bleManagerResetPromise === reset)
2210
+ bleManagerResetPromise = undefined;
2211
+ }, error => {
2212
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE manager destroy failed:', error);
2213
+ });
1785
2214
  }
1786
2215
  createProtocolMismatchError(expected) {
1787
2216
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
@@ -1837,6 +2266,7 @@ class ReactNativeBleTransport {
1837
2266
  !protocolHint &&
1838
2267
  reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
1839
2268
  const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
2269
+ yield this.wakeSilentProtocolV1Device(uuid, probeOrder);
1840
2270
  for (let i = 0; i < probeOrder.length; i += 1) {
1841
2271
  const protocol = probeOrder[i];
1842
2272
  if (i > 0) {
@@ -1856,6 +2286,7 @@ class ReactNativeBleTransport {
1856
2286
  this.confirmedProtocolV2.add(uuid);
1857
2287
  }
1858
2288
  this.protocolReprobeFailures.delete(uuid);
2289
+ this.silentDetections.delete(uuid);
1859
2290
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1860
2291
  deviceId: uuid,
1861
2292
  protocol,
@@ -1864,6 +2295,8 @@ class ReactNativeBleTransport {
1864
2295
  return protocol;
1865
2296
  }
1866
2297
  }
2298
+ if (!this.silentDetections.has(uuid))
2299
+ this.silentDetections.set(uuid, 'silent');
1867
2300
  if (trustSessionProtocol) {
1868
2301
  this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
1869
2302
  }
@@ -1875,6 +2308,30 @@ class ReactNativeBleTransport {
1875
2308
  throw this.createProtocolDetectionError();
1876
2309
  });
1877
2310
  }
2311
+ wakeSilentProtocolV1Device(uuid, probeOrder) {
2312
+ return __awaiter(this, void 0, void 0, function* () {
2313
+ if (reactNative.Platform.OS !== 'android' ||
2314
+ probeOrder[0] !== 'V1' ||
2315
+ this.silentDetections.get(uuid) !== 'silent') {
2316
+ return;
2317
+ }
2318
+ this.silentDetections.set(uuid, 'woken');
2319
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] sending Protocol V1 Initialize wake', {
2320
+ connectIdSuffix: uuid.slice(-8),
2321
+ });
2322
+ try {
2323
+ this.probingProtocols.set(uuid, 'V1');
2324
+ yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
2325
+ }
2326
+ catch (error) {
2327
+ if (shouldRethrowProtocolProbeError(error))
2328
+ throw error;
2329
+ }
2330
+ finally {
2331
+ this.clearProbeProtocol(uuid, 'V1');
2332
+ }
2333
+ });
2334
+ }
1878
2335
  resetProbeStateAfterProtocolProbe(uuid, protocol) {
1879
2336
  var _a, _b, _c;
1880
2337
  return __awaiter(this, void 0, void 0, function* () {
@@ -1931,7 +2388,7 @@ class ReactNativeBleTransport {
1931
2388
  catch (error) {
1932
2389
  this.clearProbeProtocol(uuid, 'V1');
1933
2390
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
1934
- if (isWedgedWriteError(error)) {
2391
+ if (shouldRethrowProtocolProbeError(error)) {
1935
2392
  throw error;
1936
2393
  }
1937
2394
  return false;
@@ -1957,7 +2414,7 @@ class ReactNativeBleTransport {
1957
2414
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1958
2415
  this.resetProtocolV2Frames(uuid);
1959
2416
  },
1960
- shouldRethrow: hdShared.isBleStaleBondHardwareError,
2417
+ shouldRethrow: shouldRethrowProtocolProbeError,
1961
2418
  });
1962
2419
  if (!detected) {
1963
2420
  this.clearProbeProtocol(uuid, 'V2');
@@ -2084,6 +2541,9 @@ class ReactNativeBleTransport {
2084
2541
  this.rememberStaleBondError(uuid, bondError);
2085
2542
  throw bondError;
2086
2543
  }
2544
+ if (isNativeBleDisconnectError(error)) {
2545
+ throw toBleDisconnectHardwareError(error);
2546
+ }
2087
2547
  if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
2088
2548
  attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
2089
2549
  throw error;
@@ -2126,6 +2586,7 @@ class ReactNativeBleTransport {
2126
2586
  if (!this._messages || !this._messagesV2) {
2127
2587
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
2128
2588
  }
2589
+ const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
2129
2590
  const callOptions = options;
2130
2591
  const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
2131
2592
  if (highThroughputWrite) {
@@ -2166,6 +2627,14 @@ class ReactNativeBleTransport {
2166
2627
  }
2167
2628
  catch (e) {
2168
2629
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
2630
+ if (!isProtocolProbe &&
2631
+ (e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError &&
2632
+ !this.monitorTokens.has(uuid)) {
2633
+ yield this.runLifecycleOperation(uuid, () => __awaiter(this, void 0, void 0, function* () {
2634
+ if (!this.monitorTokens.has(uuid))
2635
+ yield this.disconnectUnlocked(uuid);
2636
+ }));
2637
+ }
2169
2638
  throw e;
2170
2639
  }
2171
2640
  finally {
@@ -2180,7 +2649,7 @@ class ReactNativeBleTransport {
2180
2649
  const transport = this.getCachedTransport(uuid);
2181
2650
  if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
2182
2651
  return;
2183
- const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
2652
+ const { device: refreshedDevice } = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1, transactionId => { var _a; return (_a = this.blePlxManager) === null || _a === void 0 ? void 0 : _a.cancelTransaction(transactionId); });
2184
2653
  transport.device = refreshedDevice;
2185
2654
  transport.mtuSize =
2186
2655
  typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
@@ -2297,6 +2766,8 @@ class ReactNativeBleTransport {
2297
2766
  }
2298
2767
  }
2299
2768
 
2769
+ exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
2770
+ exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
2300
2771
  exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
2301
2772
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
2302
2773
  exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;