@onekeyfe/hd-transport-web-device 1.2.2-alpha.8 → 1.2.3-alpha.1

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.
@@ -182,6 +182,40 @@ describe('ElectronBleTransport protocol detection', () => {
182
182
  jest.clearAllMocks();
183
183
  });
184
184
 
185
+ test('does not treat an error envelope from a legacy preload as a successful connect', async () => {
186
+ const device = { id: 'stale-bond-id', name: 'OneKey Pro 2' };
187
+ const nobleBle = createNobleBle(device);
188
+ nobleBle.connect.mockResolvedValue({
189
+ type: 'NobleBleIpcError',
190
+ success: false,
191
+ error: {
192
+ name: 'HardwareError',
193
+ message: 'Bluetooth pairing information is no longer valid',
194
+ errorCode: HardwareErrorCode.BleBondInvalid,
195
+ },
196
+ } as never);
197
+ const bleTransport = configureTransport(nobleBle);
198
+
199
+ await expect(
200
+ bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
201
+ ).rejects.toMatchObject({
202
+ errorCode: HardwareErrorCode.BleBondInvalid,
203
+ });
204
+ expect(nobleBle.subscribe).not.toHaveBeenCalled();
205
+ expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
206
+ });
207
+
208
+ test('sends a native disconnect even before acquire marks the device connected', async () => {
209
+ const device = { id: 'pending-connect-id', name: 'OneKey Pro 2' };
210
+ const nobleBle = createNobleBle(device);
211
+ const bleTransport = configureTransport(nobleBle) as any;
212
+
213
+ await bleTransport.releaseNative(device.id);
214
+
215
+ expect(nobleBle.unsubscribe).not.toHaveBeenCalled();
216
+ expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
217
+ });
218
+
185
219
  test('keeps raw BLE lifecycle payloads off the public device event channel', async () => {
186
220
  const device = { id: 'lifecycle-pro2-id', name: 'OneKey Pro 2' };
187
221
  const nobleBle = createNobleBle(device);
@@ -553,14 +587,19 @@ describe('ElectronBleTransport protocol detection', () => {
553
587
  test('fails Protocol V2 acquire immediately when subscribe reports insufficient encryption', async () => {
554
588
  const device = { id: 'stale-bond-pro2-id', name: 'OneKey Pro 2' };
555
589
  const nobleBle = createNobleBle(device);
556
- nobleBle.subscribe.mockRejectedValue(new Error('Encryption is insufficient'));
590
+ nobleBle.subscribe.mockRejectedValue({
591
+ name: 'HardwareError',
592
+ message: 'Bluetooth pairing information is no longer valid',
593
+ errorCode: HardwareErrorCode.BleBondInvalid,
594
+ params: { nativeErrorMessage: 'Encryption is insufficient' },
595
+ });
557
596
  const transport = configureTransport(nobleBle);
558
597
  const probe = jest.spyOn(transport as any, 'probeProtocolV2');
559
598
 
560
599
  await expect(
561
600
  transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
562
601
  ).rejects.toMatchObject({
563
- errorCode: HardwareErrorCode.BleDeviceBondError,
602
+ errorCode: HardwareErrorCode.BleBondInvalid,
564
603
  });
565
604
 
566
605
  expect(probe).not.toHaveBeenCalled();
@@ -568,6 +607,56 @@ describe('ElectronBleTransport protocol detection', () => {
568
607
  expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
569
608
  });
570
609
 
610
+ test('rehydrates a structured stale-bond error before the protocol is known', async () => {
611
+ const device = { id: 'reset-unknown-protocol-id', name: 'OneKey Pro 2' };
612
+ const nobleBle = createNobleBle(device);
613
+ nobleBle.connect.mockRejectedValue({
614
+ name: 'HardwareError',
615
+ message: 'Bluetooth pairing information is no longer valid',
616
+ errorCode: HardwareErrorCode.BleBondInvalid,
617
+ params: { nativeErrorMessage: 'CBErrorDomain:14 native message' },
618
+ });
619
+ const transport = configureTransport(nobleBle);
620
+
621
+ await expect(transport.acquire({ uuid: device.id })).rejects.toMatchObject({
622
+ name: 'HardwareError',
623
+ errorCode: HardwareErrorCode.BleBondInvalid,
624
+ params: { nativeErrorMessage: 'CBErrorDomain:14 native message' },
625
+ });
626
+ });
627
+
628
+ test('does not infer hardware errors from native error text in the renderer', async () => {
629
+ const device = { id: 'reset-pro2-localized-id', name: 'OneKey Pro 2' };
630
+ const nobleBle = createNobleBle(device);
631
+ nobleBle.connect.mockRejectedValue(new Error('CBATTErrorDomain:14 localized native message'));
632
+ const transport = configureTransport(nobleBle);
633
+
634
+ try {
635
+ await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
636
+ throw new Error('Expected acquire to fail');
637
+ } catch (error) {
638
+ expect(error).toBeInstanceOf(Error);
639
+ expect((error as Error).message).toBe('CBATTErrorDomain:14 localized native message');
640
+ expect((error as { errorCode?: unknown }).errorCode).toBeUndefined();
641
+ }
642
+ });
643
+
644
+ test('does not classify a generic macOS connection failure as a stale bond', async () => {
645
+ const device = { id: 'offline-pro2-macos-id', name: 'OneKey Pro 2' };
646
+ const nobleBle = createNobleBle(device);
647
+ nobleBle.connect.mockRejectedValue(new Error('connection failed'));
648
+ const transport = configureTransport(nobleBle);
649
+
650
+ try {
651
+ await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
652
+ throw new Error('Expected acquire to fail');
653
+ } catch (error) {
654
+ expect(error).toBeInstanceOf(Error);
655
+ expect((error as Error).message).toBe('connection failed');
656
+ expect((error as { errorCode?: unknown }).errorCode).toBeUndefined();
657
+ }
658
+ });
659
+
571
660
  test('keeps stale-bond subscribe mapping out of Protocol V1 acquire', async () => {
572
661
  const device = { id: 'classic-v1-id', name: 'OneKey Classic' };
573
662
  const nobleBle = createNobleBle(device);
@@ -41,7 +41,7 @@ export default class ElectronBleTransport {
41
41
  private hostDisconnectCleanup?;
42
42
  private notificationTokens;
43
43
  private nextNotificationToken;
44
- private toStaleBondError;
44
+ private normalizeBluetoothError;
45
45
  private handleBluetoothError;
46
46
  private cleanupDeviceState;
47
47
  init(logger: any, emitter?: EventEmitter): void;
@@ -1 +1 @@
1
- {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -242,7 +242,7 @@ declare class ElectronBleTransport {
242
242
  private hostDisconnectCleanup?;
243
243
  private notificationTokens;
244
244
  private nextNotificationToken;
245
- private toStaleBondError;
245
+ private normalizeBluetoothError;
246
246
  private handleBluetoothError;
247
247
  private cleanupDeviceState;
248
248
  init(logger: any, emitter?: EventEmitter): void;
package/dist/index.js CHANGED
@@ -823,6 +823,19 @@ function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapa
823
823
 
824
824
  const { parseConfigure, ProtocolV1, check } = transport__default["default"];
825
825
  const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
826
+ const invokeNobleBle = (request) => __awaiter(void 0, void 0, void 0, function* () {
827
+ const response = yield request;
828
+ if (response &&
829
+ typeof response === 'object' &&
830
+ 'type' in response &&
831
+ response.type === 'NobleBleIpcError' &&
832
+ 'success' in response &&
833
+ response.success === false &&
834
+ 'error' in response) {
835
+ return Promise.reject(response.error);
836
+ }
837
+ return response;
838
+ });
826
839
  const BLE_PACKET_SIZE_FALLBACK = 192;
827
840
  const BLE_PACKET_SIZE_MAXIMUM = 244;
828
841
  const BLE_WRITE_DELAY_MS = 5;
@@ -871,39 +884,20 @@ class ElectronBleTransport {
871
884
  this.notificationTokens = new Map();
872
885
  this.nextNotificationToken = 1;
873
886
  }
874
- toStaleBondError(error) {
875
- var _a;
876
- if (hdShared.isBleStaleBondHardwareError(error)) {
877
- return error;
878
- }
879
- const errorMessage = error && typeof error === 'object' && 'message' in error
880
- ? String((_a = error.message) !== null && _a !== void 0 ? _a : '')
881
- : String(error !== null && error !== void 0 ? error : '');
882
- if (!hdShared.isBleStaleBondErrorText(errorMessage)) {
883
- return null;
884
- }
885
- const normalizedErrorMessage = errorMessage.toLowerCase();
886
- return hdShared.ERRORS.TypedError(normalizedErrorMessage.includes('peer removed pairing information')
887
- ? hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation
888
- : hdShared.HardwareErrorCode.BleDeviceBondError, errorMessage);
889
- }
890
- handleBluetoothError(error, mapProtocolV2StaleBond = false) {
891
- if (mapProtocolV2StaleBond) {
892
- const staleBondError = this.toStaleBondError(error);
893
- if (staleBondError) {
894
- throw staleBondError;
895
- }
896
- }
887
+ normalizeBluetoothError(error) {
897
888
  if (error && typeof error === 'object') {
889
+ if (typeof error.errorCode === 'number') {
890
+ return hdShared.ERRORS.TypedError(error.errorCode, typeof error.message === 'string' ? error.message : undefined, error.params);
891
+ }
898
892
  if ('code' in error) {
899
893
  if (error.code === hdShared.HardwareErrorCode.BlePoweredOff) {
900
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
894
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
901
895
  }
902
896
  if (error.code === hdShared.HardwareErrorCode.BleUnsupported) {
903
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
897
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
904
898
  }
905
899
  if (error.code === hdShared.HardwareErrorCode.BlePermissionError) {
906
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
900
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
907
901
  }
908
902
  }
909
903
  const errorMessage = error.message || String(error);
@@ -911,16 +905,19 @@ class ElectronBleTransport {
911
905
  const unsupportedMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleUnsupported];
912
906
  const permissionMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BlePermissionError];
913
907
  if (errorMessage.includes(poweredOffMessage) || errorMessage.includes('poweredOff')) {
914
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
908
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
915
909
  }
916
910
  if (errorMessage.includes(unsupportedMessage) || errorMessage.includes('unsupported')) {
917
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
911
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
918
912
  }
919
913
  if (errorMessage.includes(permissionMessage) || errorMessage.includes('unauthorized')) {
920
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
914
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
921
915
  }
922
916
  }
923
- throw error;
917
+ return error;
918
+ }
919
+ handleBluetoothError(error) {
920
+ throw this.normalizeBluetoothError(error);
924
921
  }
925
922
  cleanupDeviceState(deviceId) {
926
923
  this.protocolV2Links
@@ -1007,7 +1004,7 @@ class ElectronBleTransport {
1007
1004
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1008
1005
  throw new Error('Noble BLE API not available');
1009
1006
  }
1010
- const devices = yield window.desktopApi.nobleBle.enumerate();
1007
+ const devices = yield invokeNobleBle(window.desktopApi.nobleBle.enumerate());
1011
1008
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
1012
1009
  for (const dev of devices) {
1013
1010
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
@@ -1024,9 +1021,6 @@ class ElectronBleTransport {
1024
1021
  var _a, _b, _c, _d, _e, _f, _g;
1025
1022
  return __awaiter(this, void 0, void 0, function* () {
1026
1023
  const { uuid, forceCleanRunPromise, expectedProtocol } = input;
1027
- const shouldMapProtocolV2StaleBond = expectedProtocol
1028
- ? expectedProtocol === 'V2'
1029
- : this.confirmedProtocolV2.has(uuid);
1030
1024
  if (!uuid) {
1031
1025
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
1032
1026
  }
@@ -1043,7 +1037,7 @@ class ElectronBleTransport {
1043
1037
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1044
1038
  throw new Error('Noble BLE API not available');
1045
1039
  }
1046
- const device = yield window.desktopApi.nobleBle.getDevice(uuid);
1040
+ const device = yield invokeNobleBle(window.desktopApi.nobleBle.getDevice(uuid));
1047
1041
  if (!device) {
1048
1042
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
1049
1043
  }
@@ -1054,11 +1048,11 @@ class ElectronBleTransport {
1054
1048
  this.deviceProtocolHints.set(uuid, protocolHint);
1055
1049
  }
1056
1050
  try {
1057
- yield window.desktopApi.nobleBle.connect(uuid);
1051
+ yield invokeNobleBle(window.desktopApi.nobleBle.connect(uuid));
1058
1052
  this.connectedDevices.add(uuid);
1059
1053
  }
1060
1054
  catch (error) {
1061
- this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
1055
+ this.handleBluetoothError(error);
1062
1056
  }
1063
1057
  const mtuCleanup = this.createMtuSubscription(uuid);
1064
1058
  if (mtuCleanup) {
@@ -1067,10 +1061,10 @@ class ElectronBleTransport {
1067
1061
  this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
1068
1062
  this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
1069
1063
  try {
1070
- yield window.desktopApi.nobleBle.subscribe(uuid);
1064
+ yield invokeNobleBle(window.desktopApi.nobleBle.subscribe(uuid));
1071
1065
  }
1072
1066
  catch (error) {
1073
- this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
1067
+ this.handleBluetoothError(error);
1074
1068
  }
1075
1069
  yield this.refreshBlePacketCapacity(uuid);
1076
1070
  const cleanup = this.createNotificationSubscription(uuid);
@@ -1088,16 +1082,22 @@ class ElectronBleTransport {
1088
1082
  catch (error) {
1089
1083
  (_e = this.Log) === null || _e === void 0 ? void 0 : _e.error('[Electron BLE] acquire failed:', error);
1090
1084
  try {
1091
- if (((_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle) && this.connectedDevices.has(uuid)) {
1092
- yield window.desktopApi.nobleBle.unsubscribe(uuid);
1093
- yield window.desktopApi.nobleBle.disconnect(uuid);
1085
+ const nobleBle = (_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle;
1086
+ if (nobleBle) {
1087
+ if (this.connectedDevices.has(uuid)) {
1088
+ yield invokeNobleBle(nobleBle.unsubscribe(uuid)).catch(cleanupError => {
1089
+ var _a;
1090
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] acquire unsubscribe failed:', cleanupError);
1091
+ });
1092
+ }
1093
+ yield invokeNobleBle(nobleBle.disconnect(uuid));
1094
1094
  }
1095
1095
  }
1096
1096
  catch (cleanupError) {
1097
1097
  (_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
1098
1098
  }
1099
1099
  this.cleanupDeviceState(uuid);
1100
- throw error;
1100
+ this.handleBluetoothError(error);
1101
1101
  }
1102
1102
  });
1103
1103
  }
@@ -1123,13 +1123,17 @@ class ElectronBleTransport {
1123
1123
  var _a, _b;
1124
1124
  return __awaiter(this, void 0, void 0, function* () {
1125
1125
  try {
1126
- if (this.connectedDevices.has(id)) {
1127
- if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
1128
- yield window.desktopApi.nobleBle.unsubscribe(id);
1129
- yield window.desktopApi.nobleBle.disconnect(id);
1126
+ const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
1127
+ if (nobleBle) {
1128
+ if (this.connectedDevices.has(id)) {
1129
+ yield invokeNobleBle(nobleBle.unsubscribe(id)).catch(error => {
1130
+ var _a;
1131
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] release unsubscribe failed:', error);
1132
+ });
1130
1133
  }
1131
- this.cleanupDeviceState(id);
1134
+ yield invokeNobleBle(nobleBle.disconnect(id));
1132
1135
  }
1136
+ this.cleanupDeviceState(id);
1133
1137
  }
1134
1138
  catch (error) {
1135
1139
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] release failed:', error);
@@ -1153,7 +1157,7 @@ class ElectronBleTransport {
1153
1157
  }
1154
1158
  return;
1155
1159
  }
1156
- yield release(id, keepSession);
1160
+ yield invokeNobleBle(release(id, keepSession));
1157
1161
  }
1158
1162
  catch (error) {
1159
1163
  (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] logical release failed:', error);
@@ -1298,21 +1302,18 @@ class ElectronBleTransport {
1298
1302
  throw new Error('Noble BLE API not available');
1299
1303
  }
1300
1304
  try {
1301
- yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
1305
+ yield invokeNobleBle(nobleBle.write(uuid, hexData, { pacingDelayMs: 0 }));
1302
1306
  }
1303
1307
  catch (error) {
1304
- const staleBondError = this.toStaleBondError(error);
1305
- if (staleBondError) {
1306
- throw staleBondError;
1307
- }
1308
- throw error;
1308
+ this.handleBluetoothError(error);
1309
1309
  }
1310
1310
  });
1311
1311
  }
1312
1312
  refreshBlePacketCapacity(uuid) {
1313
- var _a, _b;
1313
+ var _a;
1314
1314
  return __awaiter(this, void 0, void 0, function* () {
1315
- const device = yield ((_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.getDevice(uuid));
1315
+ const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
1316
+ const device = nobleBle ? yield invokeNobleBle(nobleBle.getDevice(uuid)) : undefined;
1316
1317
  this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
1317
1318
  });
1318
1319
  }
@@ -1535,7 +1536,7 @@ class ElectronBleTransport {
1535
1536
  if (hexString.length === 0) {
1536
1537
  throw new Error(`Buffer ${i + 1} is empty`);
1537
1538
  }
1538
- yield window.desktopApi.nobleBle.write(uuid, hexString);
1539
+ yield invokeNobleBle(window.desktopApi.nobleBle.write(uuid, hexString));
1539
1540
  }
1540
1541
  const response = yield Promise.race([
1541
1542
  runPromise.promise,
@@ -1568,7 +1569,7 @@ class ElectronBleTransport {
1568
1569
  yield this.releaseNative(uuid);
1569
1570
  }
1570
1571
  }
1571
- throw e;
1572
+ throw this.normalizeBluetoothError(e);
1572
1573
  }
1573
1574
  finally {
1574
1575
  if (timeout)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-web-device",
3
- "version": "1.2.2-alpha.8",
3
+ "version": "1.2.3-alpha.1",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -21,13 +21,13 @@
21
21
  "lint:fix": "eslint . --fix"
22
22
  },
23
23
  "dependencies": {
24
- "@onekeyfe/hd-shared": "1.2.2-alpha.8",
25
- "@onekeyfe/hd-transport": "1.2.2-alpha.8"
24
+ "@onekeyfe/hd-shared": "1.2.3-alpha.1",
25
+ "@onekeyfe/hd-transport": "1.2.3-alpha.1"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.2-alpha.8",
28
+ "@onekeyfe/hd-transport-electron": "1.2.3-alpha.1",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "7a5d129ea1db0b3eb230e309ab29ed3e9e7f141e"
32
+ "gitHead": "fd4221863c00240fc4870fc50f8c517d97426de2"
33
33
  }
@@ -18,7 +18,6 @@ import {
18
18
  HardwareErrorCode,
19
19
  HardwareErrorCodeMessage,
20
20
  createDeferred,
21
- isBleStaleBondErrorText,
22
21
  isBleStaleBondHardwareError,
23
22
  isHeaderChunk,
24
23
  } from '@onekeyfe/hd-shared';
@@ -26,7 +25,7 @@ import {
26
25
  import { resolveBlePacketCapacity } from './ble-packet-capacity';
27
26
 
28
27
  import type { Deferred } from '@onekeyfe/hd-shared';
29
- import type { DesktopAPI } from '@onekeyfe/hd-transport-electron';
28
+ import type { DesktopAPI, NobleBleIpcErrorResponse } from '@onekeyfe/hd-transport-electron';
30
29
  import type {
31
30
  OneKeyDeviceInfo,
32
31
  ProtocolType,
@@ -69,6 +68,22 @@ const toBleDescriptor = (
69
68
  ...(protocolType ? { protocolType } : {}),
70
69
  } as OneKeyDeviceInfo);
71
70
 
71
+ const invokeNobleBle = async <T>(request: Promise<T>): Promise<T> => {
72
+ const response = await (request as Promise<T | NobleBleIpcErrorResponse>);
73
+ if (
74
+ response &&
75
+ typeof response === 'object' &&
76
+ 'type' in response &&
77
+ response.type === 'NobleBleIpcError' &&
78
+ 'success' in response &&
79
+ response.success === false &&
80
+ 'error' in response
81
+ ) {
82
+ return Promise.reject(response.error);
83
+ }
84
+ return response as T;
85
+ };
86
+
72
87
  const BLE_PACKET_SIZE_FALLBACK = 192;
73
88
  const BLE_PACKET_SIZE_MAXIMUM = 244;
74
89
  const BLE_WRITE_DELAY_MS = 5;
@@ -163,43 +178,24 @@ export default class ElectronBleTransport {
163
178
 
164
179
  private nextNotificationToken = 1;
165
180
 
166
- private toStaleBondError(error: unknown): Error | null {
167
- if (isBleStaleBondHardwareError(error)) {
168
- return error as Error;
169
- }
170
- const errorMessage =
171
- error && typeof error === 'object' && 'message' in error
172
- ? String((error as { message?: unknown }).message ?? '')
173
- : String(error ?? '');
174
- if (!isBleStaleBondErrorText(errorMessage)) {
175
- return null;
176
- }
177
- const normalizedErrorMessage = errorMessage.toLowerCase();
178
- return ERRORS.TypedError(
179
- normalizedErrorMessage.includes('peer removed pairing information')
180
- ? HardwareErrorCode.BlePeerRemovedPairingInformation
181
- : HardwareErrorCode.BleDeviceBondError,
182
- errorMessage
183
- );
184
- }
185
-
186
- private handleBluetoothError(error: any, mapProtocolV2StaleBond = false): never {
187
- if (mapProtocolV2StaleBond) {
188
- const staleBondError = this.toStaleBondError(error);
189
- if (staleBondError) {
190
- throw staleBondError;
191
- }
192
- }
181
+ private normalizeBluetoothError(error: any): any {
193
182
  if (error && typeof error === 'object') {
183
+ if (typeof error.errorCode === 'number') {
184
+ return ERRORS.TypedError(
185
+ error.errorCode,
186
+ typeof error.message === 'string' ? error.message : undefined,
187
+ error.params
188
+ );
189
+ }
194
190
  if ('code' in error) {
195
191
  if (error.code === HardwareErrorCode.BlePoweredOff) {
196
- throw ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
192
+ return ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
197
193
  }
198
194
  if (error.code === HardwareErrorCode.BleUnsupported) {
199
- throw ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
195
+ return ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
200
196
  }
201
197
  if (error.code === HardwareErrorCode.BlePermissionError) {
202
- throw ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
198
+ return ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
203
199
  }
204
200
  }
205
201
  const errorMessage = error.message || String(error);
@@ -208,16 +204,20 @@ export default class ElectronBleTransport {
208
204
  const permissionMessage = HardwareErrorCodeMessage[HardwareErrorCode.BlePermissionError];
209
205
 
210
206
  if (errorMessage.includes(poweredOffMessage) || errorMessage.includes('poweredOff')) {
211
- throw ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
207
+ return ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
212
208
  }
213
209
  if (errorMessage.includes(unsupportedMessage) || errorMessage.includes('unsupported')) {
214
- throw ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
210
+ return ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
215
211
  }
216
212
  if (errorMessage.includes(permissionMessage) || errorMessage.includes('unauthorized')) {
217
- throw ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
213
+ return ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
218
214
  }
219
215
  }
220
- throw error;
216
+ return error;
217
+ }
218
+
219
+ private handleBluetoothError(error: any): never {
220
+ throw this.normalizeBluetoothError(error);
221
221
  }
222
222
 
223
223
  private cleanupDeviceState(deviceId: string): void {
@@ -336,7 +336,7 @@ export default class ElectronBleTransport {
336
336
  if (!window.desktopApi?.nobleBle) {
337
337
  throw new Error('Noble BLE API not available');
338
338
  }
339
- const devices = await window.desktopApi.nobleBle.enumerate();
339
+ const devices = await invokeNobleBle(window.desktopApi.nobleBle.enumerate());
340
340
  this.Log?.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
341
341
  for (const dev of devices) {
342
342
  this.Log?.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
@@ -350,9 +350,6 @@ export default class ElectronBleTransport {
350
350
 
351
351
  async acquire(input: BleAcquireInput) {
352
352
  const { uuid, forceCleanRunPromise, expectedProtocol } = input;
353
- const shouldMapProtocolV2StaleBond = expectedProtocol
354
- ? expectedProtocol === 'V2'
355
- : this.confirmedProtocolV2.has(uuid);
356
353
 
357
354
  if (!uuid) {
358
355
  throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
@@ -374,7 +371,7 @@ export default class ElectronBleTransport {
374
371
  throw new Error('Noble BLE API not available');
375
372
  }
376
373
 
377
- const device = await window.desktopApi.nobleBle.getDevice(uuid);
374
+ const device = await invokeNobleBle(window.desktopApi.nobleBle.getDevice(uuid));
378
375
  if (!device) {
379
376
  throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
380
377
  }
@@ -386,10 +383,10 @@ export default class ElectronBleTransport {
386
383
  }
387
384
 
388
385
  try {
389
- await window.desktopApi.nobleBle.connect(uuid);
386
+ await invokeNobleBle(window.desktopApi.nobleBle.connect(uuid));
390
387
  this.connectedDevices.add(uuid);
391
388
  } catch (error) {
392
- this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
389
+ this.handleBluetoothError(error);
393
390
  }
394
391
 
395
392
  const mtuCleanup = this.createMtuSubscription(uuid);
@@ -401,9 +398,9 @@ export default class ElectronBleTransport {
401
398
  this.v2Assemblers.set(uuid, new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
402
399
 
403
400
  try {
404
- await window.desktopApi.nobleBle.subscribe(uuid);
401
+ await invokeNobleBle(window.desktopApi.nobleBle.subscribe(uuid));
405
402
  } catch (error) {
406
- this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
403
+ this.handleBluetoothError(error);
407
404
  }
408
405
  await this.refreshBlePacketCapacity(uuid);
409
406
 
@@ -426,15 +423,20 @@ export default class ElectronBleTransport {
426
423
  } catch (error) {
427
424
  this.Log?.error('[Electron BLE] acquire failed:', error);
428
425
  try {
429
- if (window.desktopApi?.nobleBle && this.connectedDevices.has(uuid)) {
430
- await window.desktopApi.nobleBle.unsubscribe(uuid);
431
- await window.desktopApi.nobleBle.disconnect(uuid);
426
+ const nobleBle = window.desktopApi?.nobleBle;
427
+ if (nobleBle) {
428
+ if (this.connectedDevices.has(uuid)) {
429
+ await invokeNobleBle(nobleBle.unsubscribe(uuid)).catch(cleanupError => {
430
+ this.Log?.debug('[Electron BLE] acquire unsubscribe failed:', cleanupError);
431
+ });
432
+ }
433
+ await invokeNobleBle(nobleBle.disconnect(uuid));
432
434
  }
433
435
  } catch (cleanupError) {
434
436
  this.Log?.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
435
437
  }
436
438
  this.cleanupDeviceState(uuid);
437
- throw error;
439
+ this.handleBluetoothError(error);
438
440
  }
439
441
  }
440
442
 
@@ -457,13 +459,16 @@ export default class ElectronBleTransport {
457
459
  // Hard teardown, error paths only: a link presumed dead must not be reused.
458
460
  private async releaseNative(id: string) {
459
461
  try {
460
- if (this.connectedDevices.has(id)) {
461
- if (window.desktopApi?.nobleBle) {
462
- await window.desktopApi.nobleBle.unsubscribe(id);
463
- await window.desktopApi.nobleBle.disconnect(id);
462
+ const nobleBle = window.desktopApi?.nobleBle;
463
+ if (nobleBle) {
464
+ if (this.connectedDevices.has(id)) {
465
+ await invokeNobleBle(nobleBle.unsubscribe(id)).catch(error => {
466
+ this.Log?.debug('[Electron BLE] release unsubscribe failed:', error);
467
+ });
464
468
  }
465
- this.cleanupDeviceState(id);
469
+ await invokeNobleBle(nobleBle.disconnect(id));
466
470
  }
471
+ this.cleanupDeviceState(id);
467
472
  } catch (error) {
468
473
  this.Log?.error('[Electron BLE] release failed:', error);
469
474
  this.cleanupDeviceState(id);
@@ -489,7 +494,7 @@ export default class ElectronBleTransport {
489
494
  }
490
495
  return;
491
496
  }
492
- await release(id, keepSession);
497
+ await invokeNobleBle(release(id, keepSession));
493
498
  } catch (error) {
494
499
  this.Log?.error('[Electron BLE] logical release failed:', error);
495
500
  this.cleanupDeviceState(id);
@@ -671,18 +676,15 @@ export default class ElectronBleTransport {
671
676
  }
672
677
 
673
678
  try {
674
- await nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
679
+ await invokeNobleBle(nobleBle.write(uuid, hexData, { pacingDelayMs: 0 }));
675
680
  } catch (error) {
676
- const staleBondError = this.toStaleBondError(error);
677
- if (staleBondError) {
678
- throw staleBondError;
679
- }
680
- throw error;
681
+ this.handleBluetoothError(error);
681
682
  }
682
683
  }
683
684
 
684
685
  private async refreshBlePacketCapacity(uuid: string): Promise<void> {
685
- const device = await window.desktopApi?.nobleBle?.getDevice(uuid);
686
+ const nobleBle = window.desktopApi?.nobleBle;
687
+ const device = nobleBle ? await invokeNobleBle(nobleBle.getDevice(uuid)) : undefined;
686
688
  this.updateBlePacketCapacity(uuid, device?.mtu);
687
689
  }
688
690
 
@@ -940,7 +942,7 @@ export default class ElectronBleTransport {
940
942
  if (hexString.length === 0) {
941
943
  throw new Error(`Buffer ${i + 1} is empty`);
942
944
  }
943
- await window.desktopApi.nobleBle.write(uuid, hexString);
945
+ await invokeNobleBle(window.desktopApi.nobleBle.write(uuid, hexString));
944
946
  }
945
947
 
946
948
  const response = await Promise.race([
@@ -978,7 +980,7 @@ export default class ElectronBleTransport {
978
980
  await this.releaseNative(uuid);
979
981
  }
980
982
  }
981
- throw e;
983
+ throw this.normalizeBluetoothError(e);
982
984
  } finally {
983
985
  if (timeout) clearTimeout(timeout);
984
986
  if (this.runPromise === runPromise) {