@onekeyfe/hd-transport-electron 1.2.8-alpha.2 → 1.2.8-alpha.4

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.
@@ -55,13 +55,13 @@ function invokeNobleBleIpc(request) {
55
55
 
56
56
  function initNobleBleSupport(webContents) {
57
57
  return __awaiter(this, void 0, void 0, function* () {
58
- const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-043a7c23.js'); });
58
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d0991fa0.js'); });
59
59
  setupNobleBleHandlers(webContents);
60
60
  });
61
61
  }
62
62
  function disposeNobleBleSupport(releaseNoble) {
63
63
  return __awaiter(this, void 0, void 0, function* () {
64
- const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-043a7c23.js'); });
64
+ const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d0991fa0.js'); });
65
65
  yield handler.disposeNobleBleSupport(releaseNoble);
66
66
  });
67
67
  }
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('./index-5135e7b9.js');
5
+ var index = require('./index-e2e3d2ba.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-5135e7b9.js');
3
+ var index = require('./index-e2e3d2ba.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
5
  var pRetry = require('p-retry');
6
6
 
@@ -123,6 +123,13 @@ function assertBleActive() {
123
123
  }
124
124
  function createNobleBleConnectionError(error, messagePrefix = '') {
125
125
  const errorMessage = error.message;
126
+ const isInvalidMacOsBond = error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain';
127
+ if (isInvalidMacOsBond) {
128
+ const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
129
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
130
+ nativeErrorMessage,
131
+ });
132
+ }
126
133
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
127
134
  }
128
135
  function createNobleBleIpcErrorResponse(error) {
@@ -1169,7 +1176,8 @@ function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
1169
1176
  yield forceReconnectPeripheral(peripheral, deviceId);
1170
1177
  }
1171
1178
  catch (resetError) {
1172
- if ((resetError === null || resetError === void 0 ? void 0 : resetError.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
1179
+ if (hdShared.isBleStaleBondHardwareError(resetError) ||
1180
+ (resetError === null || resetError === void 0 ? void 0 : resetError.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
1173
1181
  throw resetError;
1174
1182
  }
1175
1183
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
@@ -1305,17 +1313,29 @@ function connectDevice(deviceId, webContents) {
1305
1313
  return undefined;
1306
1314
  }
1307
1315
  });
1316
+ let staleBondError;
1308
1317
  const connectById = () => index.__awaiter(this, void 0, void 0, function* () {
1309
- const found = yield tryDirectConnectById(deviceId);
1310
- if (found) {
1311
- discoveredDevices.set(deviceId, found);
1318
+ try {
1319
+ const found = yield tryDirectConnectById(deviceId);
1320
+ if (found) {
1321
+ discoveredDevices.set(deviceId, found);
1322
+ }
1323
+ return found;
1324
+ }
1325
+ catch (error) {
1326
+ if (error.errorCode !== hdShared.HardwareErrorCode.BleBondInvalid) {
1327
+ throw error;
1328
+ }
1329
+ staleBondError = error;
1330
+ return undefined;
1312
1331
  }
1313
- return found;
1314
1332
  });
1315
1333
  peripheral = byIdFirst ? yield connectById() : yield scanForPeripheral();
1316
1334
  if (!peripheral) {
1317
1335
  peripheral = byIdFirst ? yield scanForPeripheral() : yield connectById();
1318
1336
  }
1337
+ if (!peripheral && staleBondError)
1338
+ throw staleBondError;
1319
1339
  }
1320
1340
  assertBleActive();
1321
1341
  if (!peripheral) {
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAG3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAgzDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkOpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,GAAE,CAAC,QAAQ,EAAE;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,KAAK,IAAkC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAiEf"}
1
+ {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAgB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AA2zDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkOpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,GAAE,CAAC,QAAQ,EAAE;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,KAAK,IAAkC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAiEf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-electron",
3
- "version": "1.2.8-alpha.2",
3
+ "version": "1.2.8-alpha.4",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -25,9 +25,9 @@
25
25
  "electron-log": ">=4.0.0"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-core": "1.2.8-alpha.2",
29
- "@onekeyfe/hd-shared": "1.2.8-alpha.2",
30
- "@onekeyfe/hd-transport": "1.2.8-alpha.2",
28
+ "@onekeyfe/hd-core": "1.2.8-alpha.4",
29
+ "@onekeyfe/hd-shared": "1.2.8-alpha.4",
30
+ "@onekeyfe/hd-transport": "1.2.8-alpha.4",
31
31
  "@stoprocent/noble": "2.3.16",
32
32
  "p-retry": "^4.6.2"
33
33
  },
@@ -36,5 +36,5 @@
36
36
  "electron": "^25.0.0",
37
37
  "typescript": "^5.3.3"
38
38
  },
39
- "gitHead": "74ac64464df3806ef44ad54d313378754c3eaed2"
39
+ "gitHead": "82fcab32fa1a37d1b82f73da825e39360624e0c9"
40
40
  }
@@ -31,17 +31,22 @@ describe('Electron Noble BLE device discovery', () => {
31
31
  expect(NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS).toBe(10_000);
32
32
  });
33
33
 
34
- test('maps native macOS connection failures to the generic connection error', async () => {
34
+ test('maps structured macOS stale pairing failures without parsing localized text', async () => {
35
35
  const { createNobleBleConnectionError } = await import('../noble-ble-handler');
36
36
 
37
- expect(
38
- createNobleBleConnectionError(
39
- Object.assign(new Error('Peer removed pairing information on the device side'), {
40
- nativeErrorCode: 14,
41
- nativeErrorDomain: 'CBErrorDomain',
42
- })
43
- )
44
- ).toMatchObject({ errorCode: HardwareErrorCode.BleConnectedError });
37
+ const staleBondError = createNobleBleConnectionError(
38
+ Object.assign(new Error('Peer removed pairing information on the device side'), {
39
+ nativeErrorCode: 14,
40
+ nativeErrorDomain: 'CBErrorDomain',
41
+ })
42
+ );
43
+ expect(staleBondError).toMatchObject({
44
+ errorCode: HardwareErrorCode.BleBondInvalid,
45
+ params: {
46
+ nativeErrorMessage: 'Peer removed pairing information on the device side',
47
+ },
48
+ });
49
+ expect(staleBondError.message).toContain('Peer removed pairing information on the device side');
45
50
  expect(createNobleBleConnectionError(new Error('Encryption is insufficient'))).toMatchObject({
46
51
  errorCode: HardwareErrorCode.BleConnectedError,
47
52
  });
@@ -76,16 +81,18 @@ describe('Electron Noble BLE device discovery', () => {
76
81
  expect(
77
82
  createNobleBleIpcErrorResponse({
78
83
  name: 'HardwareError',
79
- message: 'Bluetooth connection failed',
80
- errorCode: HardwareErrorCode.BleConnectedError,
84
+ message: 'Bluetooth pairing information is no longer valid',
85
+ errorCode: HardwareErrorCode.BleBondInvalid,
86
+ params: { nativeErrorMessage: 'native message' },
81
87
  })
82
88
  ).toEqual({
83
89
  type: 'NobleBleIpcError',
84
90
  success: false,
85
91
  error: {
86
92
  name: 'HardwareError',
87
- message: 'Bluetooth connection failed',
88
- errorCode: HardwareErrorCode.BleConnectedError,
93
+ message: 'Bluetooth pairing information is no longer valid',
94
+ errorCode: HardwareErrorCode.BleBondInvalid,
95
+ params: { nativeErrorMessage: 'native message' },
89
96
  },
90
97
  });
91
98
 
@@ -128,14 +135,14 @@ describe('Electron Noble BLE device discovery', () => {
128
135
  success: false as const,
129
136
  error: {
130
137
  name: 'HardwareError',
131
- message: 'Bluetooth connection failed',
132
- errorCode: HardwareErrorCode.BleConnectedError,
138
+ message: 'Bluetooth pairing information is no longer valid',
139
+ errorCode: HardwareErrorCode.BleBondInvalid,
133
140
  },
134
141
  })
135
142
  )
136
143
  ).rejects.toMatchObject({
137
144
  name: 'HardwareError',
138
- errorCode: HardwareErrorCode.BleConnectedError,
145
+ errorCode: HardwareErrorCode.BleBondInvalid,
139
146
  });
140
147
 
141
148
  await expect(invokeNobleBleIpc(Promise.resolve('connected'))).resolves.toBe('connected');
@@ -345,6 +352,87 @@ describe('Electron Noble BLE device discovery', () => {
345
352
  }
346
353
  );
347
354
 
355
+ test.each([
356
+ { rediscovered: false, expectedCode: HardwareErrorCode.BleBondInvalid },
357
+ { rediscovered: true, expectedCode: HardwareErrorCode.BleConnectedError },
358
+ ])(
359
+ 'reports a macOS stale bond only when fallback scan misses (rediscovered=$rediscovered)',
360
+ async ({ rediscovered, expectedCode }) => {
361
+ jest.useFakeTimers({ doNotFake: ['performance'] });
362
+ const handlers = new Map<string, IpcHandler>();
363
+ const stalePeripheral = createPeripheral('device', 'Pro2 A1B2');
364
+ const freshPeripheral = Object.assign(
365
+ new EventEmitter(),
366
+ createPeripheral('device', 'Pro2 A1B2'),
367
+ {
368
+ connect: jest.fn((callback: (error?: Error) => void) => {
369
+ callback(new Error('fresh connection failed'));
370
+ }),
371
+ }
372
+ );
373
+ const staleBondError = Object.assign(new Error('Peer removed pairing information'), {
374
+ nativeErrorCode: 14,
375
+ nativeErrorDomain: 'CBErrorDomain',
376
+ });
377
+ let scanStarted: (() => void) | undefined;
378
+ const scanning = new Promise<void>(resolve => {
379
+ scanStarted = resolve;
380
+ });
381
+ const noble = Object.assign(new EventEmitter(), {
382
+ state: 'poweredOn',
383
+ startScanning: jest.fn((_services, _duplicates, callback) => {
384
+ callback?.();
385
+ if (rediscovered) noble.emit('discover', freshPeripheral);
386
+ scanStarted?.();
387
+ }),
388
+ stopScanning: jest.fn(callback => callback?.()),
389
+ connectAsync: jest.fn(() => Promise.reject(staleBondError)),
390
+ });
391
+ jest.doMock('@stoprocent/noble', () => noble);
392
+ jest.doMock('electron', () => ({
393
+ ipcMain: {
394
+ handle: (channel: string, handler: IpcHandler) => handlers.set(channel, handler),
395
+ removeHandler: (channel: string) => handlers.delete(channel),
396
+ },
397
+ }));
398
+ jest.doMock('electron-log', () => ({
399
+ info: jest.fn(),
400
+ debug: jest.fn(),
401
+ error: jest.fn(),
402
+ }));
403
+ const { setupNobleBleHandlers } = await import('../noble-ble-handler');
404
+ setupNobleBleHandlers({ on: jest.fn(), send: jest.fn() } as unknown as WebContents);
405
+ const availability = handlers.get(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK);
406
+ const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
407
+ if (!availability || !connect) throw new Error('Noble handlers were not registered');
408
+ await availability();
409
+ noble.emit('discover', stalePeripheral);
410
+
411
+ const connecting = Promise.resolve(connect(undefined, stalePeripheral.id));
412
+ await scanning;
413
+ jest.advanceTimersByTime(1500);
414
+ await expect(connecting).resolves.toMatchObject({
415
+ success: false,
416
+ error: { errorCode: expectedCode },
417
+ });
418
+ if (!rediscovered) {
419
+ const secondScan = new Promise<void>(resolve => {
420
+ scanStarted = resolve;
421
+ });
422
+ const retry = Promise.resolve(connect(undefined, stalePeripheral.id));
423
+ await secondScan;
424
+ jest.advanceTimersByTime(1500);
425
+ await expect(retry).resolves.toMatchObject({
426
+ success: false,
427
+ error: { errorCode: HardwareErrorCode.BleBondInvalid },
428
+ });
429
+ }
430
+ expect(noble.connectAsync).toHaveBeenCalledTimes(rediscovered ? 1 : 2);
431
+ expect(noble.startScanning).toHaveBeenCalledTimes(rediscovered ? 1 : 2);
432
+ expect(freshPeripheral.connect).toHaveBeenCalledTimes(rediscovered ? 1 : 0);
433
+ }
434
+ );
435
+
348
436
  test('waits for a targeted scan to stop before connecting', async () => {
349
437
  jest.useFakeTimers({ doNotFake: ['performance'] });
350
438
 
@@ -16,6 +16,7 @@ import {
16
16
  ONEKEY_WRITE_CHARACTERISTIC_UUID,
17
17
  createKnownBleUuidAliases,
18
18
  hasOnekeyCommunicationService,
19
+ isBleStaleBondHardwareError,
19
20
  isOnekeyBluetoothDevice,
20
21
  isPro2FamilyBleName,
21
22
  matchesKnownBleUuid,
@@ -73,6 +74,19 @@ type NobleBleNativeError = Error & {
73
74
 
74
75
  export function createNobleBleConnectionError(error: NobleBleNativeError, messagePrefix = '') {
75
76
  const errorMessage = error.message;
77
+ const isInvalidMacOsBond =
78
+ error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain';
79
+ if (isInvalidMacOsBond) {
80
+ const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
81
+ return ERRORS.TypedError(
82
+ HardwareErrorCode.BleBondInvalid,
83
+ `${HardwareErrorCodeMessage[HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`,
84
+ {
85
+ nativeErrorMessage,
86
+ }
87
+ );
88
+ }
89
+
76
90
  return ERRORS.TypedError(HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
77
91
  }
78
92
 
@@ -1620,6 +1634,7 @@ async function setupConnectionAndDiscoverServices(
1620
1634
  await forceReconnectPeripheral(peripheral, deviceId);
1621
1635
  } catch (resetError) {
1622
1636
  if (
1637
+ isBleStaleBondHardwareError(resetError) ||
1623
1638
  (resetError as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleDeviceDisconnected
1624
1639
  ) {
1625
1640
  throw resetError;
@@ -1797,12 +1812,21 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1797
1812
  }
1798
1813
  };
1799
1814
 
1815
+ let staleBondError: Error | undefined;
1800
1816
  const connectById = async () => {
1801
- const found = await tryDirectConnectById(deviceId);
1802
- if (found) {
1803
- discoveredDevices.set(deviceId, found);
1817
+ try {
1818
+ const found = await tryDirectConnectById(deviceId);
1819
+ if (found) {
1820
+ discoveredDevices.set(deviceId, found);
1821
+ }
1822
+ return found;
1823
+ } catch (error) {
1824
+ if ((error as { errorCode?: number }).errorCode !== HardwareErrorCode.BleBondInvalid) {
1825
+ throw error;
1826
+ }
1827
+ staleBondError = error as Error;
1828
+ return undefined;
1804
1829
  }
1805
- return found;
1806
1830
  };
1807
1831
 
1808
1832
  peripheral = byIdFirst ? await connectById() : await scanForPeripheral();
@@ -1811,6 +1835,7 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1811
1835
  // silent), or not reachable by id. Try the other one before giving up.
1812
1836
  peripheral = byIdFirst ? await scanForPeripheral() : await connectById();
1813
1837
  }
1838
+ if (!peripheral && staleBondError) throw staleBondError;
1814
1839
  }
1815
1840
 
1816
1841
  assertBleActive();