@onekeyfe/hd-transport-react-native 1.2.2-alpha.104 → 1.2.2-alpha.106

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/README.md CHANGED
@@ -26,4 +26,4 @@ yar update:protobuf to generate new ./messages.json and ./src/types/messages.ts
26
26
 
27
27
  ## Docs
28
28
 
29
- Documentation is available [hardware-js-sdk](https://developer.onekey.so/connect-to-hardware/hardware-sdk/start)
29
+ Documentation is available [Hardware SDK Getting Started](https://developer.onekey.so/en/hardware-sdk/getting-started)
@@ -0,0 +1,3 @@
1
+ export declare const isNativeBleDisconnectError: (error: unknown) => boolean;
2
+ export declare const toBleDisconnectHardwareError: (error: unknown) => Error;
3
+ //# sourceMappingURL=bleNativeDisconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bleNativeDisconnect.d.ts","sourceRoot":"","sources":["../src/bleNativeDisconnect.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,0BAA0B,UAAW,OAAO,KAAG,OAU3D,CAAC;AAEF,eAAO,MAAM,4BAA4B,UAAW,OAAO,UAU1D,CAAC"}
package/dist/index.d.ts CHANGED
@@ -154,12 +154,15 @@ declare class ReactNativeBleTransport {
154
154
  private nextMonitorToken;
155
155
  /** Serializes transport lifecycle changes for the same physical device. */
156
156
  private lifecycleOperations;
157
+ private stopPromise?;
158
+ private scanCleanups;
157
159
  constructor(options: TransportOptions);
158
160
  init(logger: any, emitter: EventEmitter): void;
159
161
  configure(signedData: any): void;
160
162
  configureProtocolV2(signedData: any): void;
161
163
  listen(): void;
162
164
  getPlxManager(): Promise<BleManager>;
165
+ private waitForManagerReset;
163
166
  resolveCharacteristics(device: Device): Promise<ResolvedBleCharacteristics>;
164
167
  attachDisconnectSubscription(transport: BleTransport, device: Device, uuid: string): void;
165
168
  private emitDeviceDisconnect;
@@ -183,13 +186,13 @@ declare class ReactNativeBleTransport {
183
186
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
184
187
  call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
185
188
  private callProtocolV1;
186
- stop(): void;
189
+ stop(): Promise<void>;
187
190
  disconnect(session: string): Promise<void>;
188
191
  private disconnectUnlocked;
189
192
  private runNativeTeardown;
190
193
  private runBestEffortNativeOperation;
191
194
  private runLifecycleOperation;
192
- cancel(): void;
195
+ cancel(): Promise<void>;
193
196
  /** Run a native connect under the JS backstop budget. */
194
197
  private connectWithTimeout;
195
198
  /** Resolve the complete GATT shape under a budget so acquire() always settles. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAGL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AAgChC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE,KAAK,8BAA8B,GAAG,eAAe,GAAG;IAMtD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAkBF,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAClD,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAwBpD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AAkCD,eAAO,MAAM,sBAAsB,QAA2C,CAAC;AAO/E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAQhD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,eAAO,MAAM,2CAA2C,IAAI,CAAC;AAE7D,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AActE,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAgE1D,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC1C,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAEzC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,OAAO,CAAC,6BAA6B,CAAqB;IAE1D,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,kBAAkB,CAAuB;IAEjD,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAQ9D,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,kBAAkB,CAAkC;IAG5D,OAAO,CAAC,4BAA4B,CAAkC;IAEtE,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,mBAAmB,CAAqB;IAGhD,OAAO,CAAC,uBAAuB,CAAkC;IAOjE,OAAO,CAAC,eAAe,CAAiC;IAGxD,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,iCAAiC,CAAuC;IAEhF,OAAO,CAAC,0BAA0B,CAA0B;IAE5D,OAAO,CAAC,0BAA0B,CAAyD;IAE3F,OAAO,CAAC,gBAAgB,CAAK;IAG7B,OAAO,CAAC,mBAAmB,CAAyC;IAEpE,OAAO,CAAC,WAAW,CAAC,CAAgB;IAEpC,OAAO,CAAC,YAAY,CAAkC;gBAE1C,OAAO,EAAE,gBAAgB;IAIrC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAKvC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAgBnC,MAAM;IAIA,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;YAS/B,mBAAmB;IAqB3B,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmFjF,4BAA4B,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgClF,OAAO,CAAC,oBAAoB;IAgBtB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY;IAsDtE,SAAS;YA0JD,0BAA0B;IAyElC,OAAO,CAAC,KAAK,EAAE,8BAA8B;;;;YAUrC,eAAe;IAiS7B,sBAAsB,CACpB,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,YAAY;IAsIT,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ;YAI7B,eAAe;YAKf,aAAa;IA8ErB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAajE,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA6BlB,cAAc;IAyP5B,IAAI;IA+BE,UAAU,CAAC,OAAO,EAAE,MAAM;YAIlB,kBAAkB;YAmFlB,iBAAiB;IAkC/B,OAAO,CAAC,4BAA4B;YAQtB,qBAAqB;IAoB7B,MAAM;YAiBE,kBAAkB;YAiDlB,iCAAiC;IAwD/C,OAAO,CAAC,wBAAwB;IAoChC,OAAO,CAAC,yBAAyB;IAMjC,OAAO,CAAC,kBAAkB;YAcZ,cAAc;IA8C5B,OAAO,CAAC,kBAAkB;IA+B1B,OAAO,CAAC,eAAe;IAiEvB,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;YAIX,cAAc;YAuGd,iCAAiC;YAoDjC,eAAe;YAsBf,eAAe;IA4B7B,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,qBAAqB;YAOf,mBAAmB;YAiBnB,qBAAqB;YAmErB,oBAAoB;YAgCpB,cAAc;YAqEd,iCAAiC;IAiB/C,OAAO,CAAC,8BAA8B;YAQxB,mCAAmC;IAsBjD,OAAO,CAAC,yCAAyC;YAanC,gCAAgC;IAoB9C,OAAO,CAAC,uBAAuB;IAmD/B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
package/dist/index.js CHANGED
@@ -194,6 +194,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
194
194
  }, ms);
195
195
  });
196
196
 
197
+ const BLE_PLX_DEVICE_DISCONNECTED = 201;
198
+ const IOS_PERIPHERAL_DISCONNECTED = 7;
199
+ const nativeErrorText$1 = (error) => [error.reason, error.message]
200
+ .filter((value) => typeof value === 'string')
201
+ .join(' ');
202
+ const isNativeBleDisconnectError = (error) => {
203
+ if (!error || typeof error !== 'object') {
204
+ return false;
205
+ }
206
+ const nativeError = error;
207
+ return (nativeError.errorCode === BLE_PLX_DEVICE_DISCONNECTED ||
208
+ nativeError.iosErrorCode === IOS_PERIPHERAL_DISCONNECTED);
209
+ };
210
+ const toBleDisconnectHardwareError = (error) => {
211
+ if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
212
+ return error;
213
+ }
214
+ const nativeError = (error !== null && error !== void 0 ? error : {});
215
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, nativeErrorText$1(nativeError) || undefined);
216
+ };
217
+
197
218
  const ATT_INSUFFICIENT_AUTHENTICATION = 5;
198
219
  const ATT_INSUFFICIENT_ENCRYPTION = 15;
199
220
  const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
@@ -258,6 +279,7 @@ class BleTransport {
258
279
  const { check, ProtocolV1, parseConfigure } = transport__default["default"];
259
280
  const Log = bleLogger;
260
281
  const transportCache = {};
282
+ let bleManagerResetPromise;
261
283
  const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
262
284
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
263
285
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
@@ -316,6 +338,17 @@ const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
316
338
  const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
317
339
  typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
318
340
  error.message.startsWith(WEDGED_WRITE_MESSAGE);
341
+ const shouldRethrowProtocolProbeError = (error) => {
342
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
343
+ return (hdShared.isBleStaleBondHardwareError(error) ||
344
+ isNativeBleDisconnectError(error) ||
345
+ code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
346
+ code === hdShared.HardwareErrorCode.BleDeviceBondedCanceled ||
347
+ code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
348
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
349
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
350
+ code === hdShared.HardwareErrorCode.BleWriteCharacteristicError);
351
+ };
319
352
  const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
320
353
  const DEVICE_SCAN_TIMEOUT_MS = 3000;
321
354
  const IOS_NOTIFY_READY_DELAY_MS = 150;
@@ -474,6 +507,7 @@ class ReactNativeBleTransport {
474
507
  this.androidPriorityResetTimers = new Map();
475
508
  this.nextMonitorToken = 1;
476
509
  this.lifecycleOperations = new Map();
510
+ this.scanCleanups = new Set();
477
511
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
478
512
  }
479
513
  init(logger, emitter) {
@@ -502,10 +536,38 @@ class ReactNativeBleTransport {
502
536
  listen() {
503
537
  }
504
538
  getPlxManager() {
505
- if (this.blePlxManager)
506
- return Promise.resolve(this.blePlxManager);
507
- this.blePlxManager = new reactNativeBlePlx.BleManager();
508
- return Promise.resolve(this.blePlxManager);
539
+ return __awaiter(this, void 0, void 0, function* () {
540
+ while (bleManagerResetPromise) {
541
+ yield this.waitForManagerReset();
542
+ }
543
+ if (this.stopped)
544
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
545
+ if (!this.blePlxManager)
546
+ this.blePlxManager = new reactNativeBlePlx.BleManager();
547
+ return this.blePlxManager;
548
+ });
549
+ }
550
+ waitForManagerReset() {
551
+ return __awaiter(this, void 0, void 0, function* () {
552
+ if (!bleManagerResetPromise)
553
+ return;
554
+ let timeout;
555
+ try {
556
+ yield Promise.race([
557
+ bleManagerResetPromise,
558
+ new Promise((_, reject) => {
559
+ timeout = setTimeout(() => reject(this.createWedgedBleSetupError()), BLE_CONNECT_TIMEOUT_MS);
560
+ }),
561
+ ]);
562
+ }
563
+ catch (_a) {
564
+ throw this.createWedgedBleSetupError();
565
+ }
566
+ finally {
567
+ if (timeout)
568
+ clearTimeout(timeout);
569
+ }
570
+ });
509
571
  }
510
572
  resolveCharacteristics(device) {
511
573
  return __awaiter(this, void 0, void 0, function* () {
@@ -670,30 +732,55 @@ class ReactNativeBleTransport {
670
732
  }
671
733
  enumerate() {
672
734
  return __awaiter(this, void 0, void 0, function* () {
673
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
674
- const deviceList = [];
675
- const blePlxManager = yield this.getPlxManager();
676
- try {
677
- yield subscribeBleOn(blePlxManager);
678
- }
679
- catch (error) {
680
- Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
681
- reject(error);
682
- return;
683
- }
684
- if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
685
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
686
- const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
687
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
688
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
689
- ]);
690
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
691
- if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
692
- resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
693
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
694
- return;
695
- }
735
+ const scanStartedAt = Date.now();
736
+ let firstDeviceMs;
737
+ const blePlxManager = yield this.getPlxManager();
738
+ yield subscribeBleOn(blePlxManager);
739
+ if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
740
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
741
+ const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
742
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
743
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
744
+ ]);
745
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
746
+ if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
747
+ resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
748
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
696
749
  }
750
+ }
751
+ if (this.stopped)
752
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
753
+ return new Promise((resolve, reject) => {
754
+ const deviceList = [];
755
+ let finished = false;
756
+ let scanCleanup;
757
+ const finishScan = (error) => {
758
+ if (scanCleanup)
759
+ return scanCleanup;
760
+ finished = true;
761
+ clearScanTimer();
762
+ scanCleanup = this.runNativeTeardown('scan', blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
763
+ yield blePlxManager.stopDeviceScan();
764
+ })).then(() => {
765
+ this.scanCleanups.delete(cancelScan);
766
+ if (error)
767
+ reject(error);
768
+ else
769
+ resolve(deviceList);
770
+ });
771
+ return scanCleanup;
772
+ };
773
+ const cancelScan = () => finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
774
+ this.scanCleanups.add(cancelScan);
775
+ const clearScanTimer = timer.timeout(() => {
776
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan completed', {
777
+ elapsedMs: Date.now() - scanStartedAt,
778
+ firstDeviceMs,
779
+ deviceCount: deviceList.length,
780
+ scanWindowMs: this.scanTimeout,
781
+ });
782
+ finishScan();
783
+ }, this.scanTimeout);
697
784
  blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
698
785
  allowDuplicates: true,
699
786
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
@@ -702,19 +789,17 @@ class ReactNativeBleTransport {
702
789
  if (error) {
703
790
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
704
791
  if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
705
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
792
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
706
793
  }
707
794
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
708
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
795
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
709
796
  }
710
797
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
711
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
712
- }
713
- else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
714
- timer.timeout(() => { }, this.scanTimeout);
798
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
715
799
  }
800
+ else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
716
801
  else {
717
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
802
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
718
803
  }
719
804
  return;
720
805
  }
@@ -739,6 +824,8 @@ class ReactNativeBleTransport {
739
824
  });
740
825
  }
741
826
  });
827
+ if (finished)
828
+ return;
742
829
  getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
743
830
  for (const device of devices) {
744
831
  const localName = 'localName' in device && typeof device.localName === 'string'
@@ -754,10 +841,11 @@ class ReactNativeBleTransport {
754
841
  addDevice(device);
755
842
  }
756
843
  }
757
- });
844
+ }, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
758
845
  const addDevice = (device) => {
759
846
  var _a;
760
- if (deviceList.every(d => d.id !== device.id)) {
847
+ if (!finished && deviceList.every(d => d.id !== device.id)) {
848
+ firstDeviceMs !== null && firstDeviceMs !== void 0 ? firstDeviceMs : (firstDeviceMs = Date.now() - scanStartedAt);
761
849
  const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
762
850
  deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
763
851
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
@@ -767,11 +855,7 @@ class ReactNativeBleTransport {
767
855
  });
768
856
  }
769
857
  };
770
- timer.timeout(() => {
771
- blePlxManager.stopDeviceScan();
772
- resolve(deviceList);
773
- }, this.scanTimeout);
774
- }));
858
+ });
775
859
  });
776
860
  }
777
861
  installTransportForAcquire(uuid, device, characteristics) {
@@ -837,6 +921,8 @@ class ReactNativeBleTransport {
837
921
  acquireUnlocked(input) {
838
922
  var _a;
839
923
  return __awaiter(this, void 0, void 0, function* () {
924
+ if (this.stopped)
925
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
840
926
  const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
841
927
  const shouldMapProtocolV2StaleBond = expectedProtocol
842
928
  ? expectedProtocol === 'V2'
@@ -1042,7 +1128,7 @@ class ReactNativeBleTransport {
1042
1128
  return { uuid, protocolType };
1043
1129
  }
1044
1130
  catch (error) {
1045
- if (hdShared.isBleStaleBondHardwareError(error)) {
1131
+ if (hdShared.isBleStaleBondHardwareError(error) || shouldRethrowProtocolProbeError(error)) {
1046
1132
  yield this.disconnectUnlocked(uuid);
1047
1133
  }
1048
1134
  else {
@@ -1455,7 +1541,35 @@ class ReactNativeBleTransport {
1455
1541
  });
1456
1542
  }
1457
1543
  stop() {
1544
+ var _a;
1545
+ if (this.stopPromise)
1546
+ return this.stopPromise;
1458
1547
  this.stopped = true;
1548
+ const deviceIds = new Set([
1549
+ ...this.monitorTokens.keys(),
1550
+ ...this.sessionProtocols.keys(),
1551
+ ...this.lifecycleOperations.keys(),
1552
+ ...(this.runPromiseDeviceId ? [this.runPromiseDeviceId] : []),
1553
+ ]);
1554
+ const scans = Array.from(this.scanCleanups, cleanup => cleanup());
1555
+ this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
1556
+ this.androidPriorityResetTimers.clear();
1557
+ this.androidHighPriorityDevices.clear();
1558
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1559
+ (_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
1560
+ this.runPromise = null;
1561
+ this.runPromiseDeviceId = null;
1562
+ deviceIds.forEach(uuid => this.rejectProtocolV2Frames(uuid, error));
1563
+ this.stopPromise = Promise.all([
1564
+ ...scans,
1565
+ ...Array.from(deviceIds, uuid => this.disconnect(uuid)),
1566
+ ]).then(() => __awaiter(this, void 0, void 0, function* () {
1567
+ yield this.protocolV2Links.invalidateAllLinks('React Native BLE transport stopped');
1568
+ yield this.waitForManagerReset();
1569
+ this.blePlxManager = undefined;
1570
+ this.emitter = undefined;
1571
+ }));
1572
+ return this.stopPromise;
1459
1573
  }
1460
1574
  disconnect(session) {
1461
1575
  return __awaiter(this, void 0, void 0, function* () {
@@ -1585,13 +1699,25 @@ class ReactNativeBleTransport {
1585
1699
  });
1586
1700
  }
1587
1701
  cancel() {
1588
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1589
- if (this.runPromise) ;
1590
- this.runPromise = null;
1591
- this.runPromiseDeviceId = null;
1702
+ return __awaiter(this, void 0, void 0, function* () {
1703
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1704
+ const pending = this.runPromise;
1705
+ const deviceId = this.runPromiseDeviceId;
1706
+ if (pending) {
1707
+ pending.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
1708
+ if (this.runPromise === pending) {
1709
+ this.runPromise = null;
1710
+ this.runPromiseDeviceId = null;
1711
+ }
1712
+ if (deviceId)
1713
+ yield this.disconnect(deviceId);
1714
+ }
1715
+ });
1592
1716
  }
1593
1717
  connectWithTimeout(uuid, connect) {
1594
1718
  return __awaiter(this, void 0, void 0, function* () {
1719
+ const startedAt = Date.now();
1720
+ let succeeded = false;
1595
1721
  let timer;
1596
1722
  let timedOut = false;
1597
1723
  const pending = connect();
@@ -1606,6 +1732,7 @@ class ReactNativeBleTransport {
1606
1732
  }, BLE_CONNECT_TIMEOUT_MS);
1607
1733
  }),
1608
1734
  ]);
1735
+ succeeded = true;
1609
1736
  return result;
1610
1737
  }
1611
1738
  catch (error) {
@@ -1620,11 +1747,19 @@ class ReactNativeBleTransport {
1620
1747
  finally {
1621
1748
  if (timer)
1622
1749
  clearTimeout(timer);
1750
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] connect completed', {
1751
+ connectIdSuffix: uuid.slice(-8),
1752
+ elapsedMs: Date.now() - startedAt,
1753
+ succeeded,
1754
+ backstopExpired: timedOut,
1755
+ });
1623
1756
  }
1624
1757
  });
1625
1758
  }
1626
1759
  resolveCharacteristicsWithTimeout(uuid, device) {
1627
1760
  return __awaiter(this, void 0, void 0, function* () {
1761
+ const startedAt = Date.now();
1762
+ let succeeded = false;
1628
1763
  let timer;
1629
1764
  let timedOut = false;
1630
1765
  const pending = this.resolveCharacteristics(device);
@@ -1640,6 +1775,7 @@ class ReactNativeBleTransport {
1640
1775
  }),
1641
1776
  ]);
1642
1777
  this.connectionSetupTimeoutCounts.delete(uuid);
1778
+ succeeded = true;
1643
1779
  return result;
1644
1780
  }
1645
1781
  catch (error) {
@@ -1654,6 +1790,12 @@ class ReactNativeBleTransport {
1654
1790
  finally {
1655
1791
  if (timer)
1656
1792
  clearTimeout(timer);
1793
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] GATT setup completed', {
1794
+ connectIdSuffix: uuid.slice(-8),
1795
+ elapsedMs: Date.now() - startedAt,
1796
+ succeeded,
1797
+ backstopExpired: timedOut,
1798
+ });
1657
1799
  }
1658
1800
  });
1659
1801
  }
@@ -1755,6 +1897,8 @@ class ReactNativeBleTransport {
1755
1897
  }
1756
1898
  }
1757
1899
  resetPlxManager() {
1900
+ if (bleManagerResetPromise)
1901
+ return;
1758
1902
  const manager = this.blePlxManager;
1759
1903
  this.blePlxManager = undefined;
1760
1904
  const reason = 'React Native BLE manager reset';
@@ -1796,12 +1940,20 @@ class ReactNativeBleTransport {
1796
1940
  this.connectionSetupTimeoutCounts.clear();
1797
1941
  this.monitorTokens.clear();
1798
1942
  this.protocolV2Assemblers.clear();
1943
+ let reset;
1799
1944
  try {
1800
- manager === null || manager === void 0 ? void 0 : manager.destroy();
1945
+ reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
1801
1946
  }
1802
1947
  catch (error) {
1803
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
1948
+ reset = Promise.reject(error);
1804
1949
  }
1950
+ bleManagerResetPromise = reset;
1951
+ reset.then(() => {
1952
+ if (bleManagerResetPromise === reset)
1953
+ bleManagerResetPromise = undefined;
1954
+ }, error => {
1955
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE manager destroy failed:', error);
1956
+ });
1805
1957
  }
1806
1958
  createProtocolMismatchError(expected) {
1807
1959
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
@@ -1951,7 +2103,7 @@ class ReactNativeBleTransport {
1951
2103
  catch (error) {
1952
2104
  this.clearProbeProtocol(uuid, 'V1');
1953
2105
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
1954
- if (isWedgedWriteError(error)) {
2106
+ if (shouldRethrowProtocolProbeError(error)) {
1955
2107
  throw error;
1956
2108
  }
1957
2109
  return false;
@@ -1977,7 +2129,7 @@ class ReactNativeBleTransport {
1977
2129
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1978
2130
  this.resetProtocolV2Frames(uuid);
1979
2131
  },
1980
- shouldRethrow: hdShared.isBleStaleBondHardwareError,
2132
+ shouldRethrow: shouldRethrowProtocolProbeError,
1981
2133
  });
1982
2134
  if (!detected) {
1983
2135
  this.clearProbeProtocol(uuid, 'V2');
@@ -2104,6 +2256,9 @@ class ReactNativeBleTransport {
2104
2256
  this.rememberStaleBondError(uuid, bondError);
2105
2257
  throw bondError;
2106
2258
  }
2259
+ if (isNativeBleDisconnectError(error)) {
2260
+ throw toBleDisconnectHardwareError(error);
2261
+ }
2107
2262
  if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
2108
2263
  attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
2109
2264
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.2-alpha.104",
3
+ "version": "1.2.2-alpha.106",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,11 +20,11 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-core": "1.2.2-alpha.104",
24
- "@onekeyfe/hd-shared": "1.2.2-alpha.104",
25
- "@onekeyfe/hd-transport": "1.2.2-alpha.104",
23
+ "@onekeyfe/hd-core": "1.2.2-alpha.106",
24
+ "@onekeyfe/hd-shared": "1.2.2-alpha.106",
25
+ "@onekeyfe/hd-transport": "1.2.2-alpha.106",
26
26
  "@onekeyfe/react-native-ble-utils": "^0.1.6",
27
27
  "react-native-ble-plx": "3.5.1"
28
28
  },
29
- "gitHead": "67835939d9f779ffd50cd8b482d8c5b53bd580bd"
29
+ "gitHead": "e52ad091098aaab6b2845154457ace5e2f8c9098"
30
30
  }
@@ -0,0 +1,33 @@
1
+ import { HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import { isNativeBleDisconnectError, toBleDisconnectHardwareError } from '../bleNativeDisconnect';
4
+
5
+ describe('native BLE disconnect mapping', () => {
6
+ test.each([
7
+ [{ errorCode: 201, reason: 'The specified device has disconnected from us.' }],
8
+ [{ errorCode: 201, iosErrorCode: 7, reason: 'The specified device has disconnected from us.' }],
9
+ [{ iosErrorCode: 7, reason: 'Peripheral disconnected' }],
10
+ ])('recognizes %j as a native disconnect', nativeError => {
11
+ expect(isNativeBleDisconnectError(nativeError)).toBe(true);
12
+ expect(toBleDisconnectHardwareError(nativeError)).toMatchObject({
13
+ errorCode: HardwareErrorCode.BleDeviceDisconnected,
14
+ });
15
+ });
16
+
17
+ test('does not treat a stale-bond iOS code as a disconnect', () => {
18
+ expect(
19
+ isNativeBleDisconnectError({
20
+ iosErrorCode: 14,
21
+ reason: 'Peer removed pairing information',
22
+ })
23
+ ).toBe(false);
24
+ });
25
+
26
+ test('does not treat an already-canonical unpaired error as a native disconnect', () => {
27
+ expect(
28
+ isNativeBleDisconnectError({
29
+ errorCode: HardwareErrorCode.BleDeviceNotBonded,
30
+ })
31
+ ).toBe(false);
32
+ });
33
+ });