@onekeyfe/hd-transport-electron 1.2.2-alpha.11 → 1.2.2-alpha.13

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.
@@ -32,7 +32,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
32
32
 
33
33
  function initNobleBleSupport(webContents) {
34
34
  return __awaiter(this, void 0, void 0, function* () {
35
- const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-95c5cf0d.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-de8d60e9.js'); });
36
36
  setupNobleBleHandlers(webContents);
37
37
  });
38
38
  }
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-00297050.js');
5
+ var index = require('./index-ef6298f9.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-00297050.js');
3
+ var index = require('./index-ef6298f9.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
5
  var pRetry = require('p-retry');
6
6
 
@@ -96,10 +96,20 @@ function softRefreshSubscription(params) {
96
96
  }
97
97
 
98
98
  const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
99
- const NOBLE_BLE_CONNECTION_TIMEOUT_MS = 10000;
99
+ const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10000;
100
100
 
101
101
  let noble = null;
102
102
  let logger = null;
103
+ function createNobleBleConnectionError(error, messagePrefix = '') {
104
+ const errorMessage = error.message;
105
+ if (hdShared.isBleStaleBondErrorText(errorMessage)) {
106
+ const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
107
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
108
+ nativeErrorMessage,
109
+ });
110
+ }
111
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
112
+ }
103
113
  const bluetoothState = {
104
114
  available: false,
105
115
  unsupported: false,
@@ -924,9 +934,14 @@ function forceReconnectPeripheral(peripheral, deviceId) {
924
934
  callback();
925
935
  }), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
926
936
  }
927
- yield runBleCallbackOperation(callback => peripheral.connect(callback), {
928
- timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
929
- timeoutBehavior: 'reject',
937
+ yield new Promise((resolve, reject) => {
938
+ peripheral.connect(error => {
939
+ if (error) {
940
+ reject(createNobleBleConnectionError(error));
941
+ return;
942
+ }
943
+ resolve();
944
+ });
930
945
  });
931
946
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
932
947
  connectedDevices.set(deviceId, peripheral);
@@ -949,7 +964,7 @@ function freshScanAndDiscover(deviceId, webContents) {
949
964
  yield new Promise((resolve, reject) => {
950
965
  freshPeripheral.connect((error) => {
951
966
  if (error) {
952
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Fresh peripheral connection failed: ${error.message}`));
967
+ reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
953
968
  }
954
969
  else {
955
970
  connectedDevices.set(deviceId, freshPeripheral);
@@ -1010,6 +1025,9 @@ function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
1010
1025
  yield forceReconnectPeripheral(peripheral, deviceId);
1011
1026
  }
1012
1027
  catch (resetError) {
1028
+ if (hdShared.isBleStaleBondHardwareError(resetError)) {
1029
+ throw resetError;
1030
+ }
1013
1031
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
1014
1032
  }
1015
1033
  setupDisconnectListener(peripheral, deviceId, webContents);
@@ -1177,27 +1195,11 @@ function connectDevice(deviceId, webContents) {
1177
1195
  return;
1178
1196
  }
1179
1197
  return new Promise((resolve, reject) => {
1180
- let connectionTimedOut = false;
1181
- const timeout = setTimeout(() => {
1182
- connectionTimedOut = true;
1183
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'Connection timeout'));
1184
- }, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
1185
1198
  const connectedPeripheral = peripheral;
1186
1199
  connectedPeripheral.connect((error) => index.__awaiter(this, void 0, void 0, function* () {
1187
- clearTimeout(timeout);
1188
- if (connectionTimedOut) {
1189
- if (!error) {
1190
- try {
1191
- connectedPeripheral.disconnect(() => undefined);
1192
- }
1193
- catch (_a) {
1194
- }
1195
- }
1196
- return;
1197
- }
1198
1200
  if (error) {
1199
1201
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
1200
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, error.message));
1202
+ reject(createNobleBleConnectionError(error));
1201
1203
  return;
1202
1204
  }
1203
1205
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connected to device:', deviceId);
@@ -1317,7 +1319,7 @@ function subscribeNotifications(deviceId, callback) {
1317
1319
  timeoutBehavior: 'resolve',
1318
1320
  });
1319
1321
  yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
1320
- timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
1322
+ timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
1321
1323
  timeoutBehavior: 'reject',
1322
1324
  });
1323
1325
  notifyCharacteristic.on('data', (data) => {
@@ -1469,5 +1471,6 @@ function setupNobleBleHandlers(webContents) {
1469
1471
  }
1470
1472
  }
1471
1473
 
1474
+ exports.createNobleBleConnectionError = createNobleBleConnectionError;
1472
1475
  exports.resolveNobleBleWritePacingDelay = resolveNobleBleWritePacingDelay;
1473
1476
  exports.setupNobleBleHandlers = setupNobleBleHandlers;
@@ -1,5 +1,6 @@
1
1
  import type { WebContents } from 'electron';
2
2
  import type { NobleBleWriteOptions } from './types/desktop-api';
3
+ export declare function createNobleBleConnectionError(error: Error, messagePrefix?: string): import("@onekeyfe/hd-shared").HardwareError;
3
4
  export declare function resolveNobleBleWritePacingDelay(options?: NobleBleWriteOptions): number;
4
5
  export declare function setupNobleBleHandlers(webContents: WebContents): void;
5
6
  //# sourceMappingURL=noble-ble-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAoFhE,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAyvDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkMpE"}
1
+ {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAOhE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,SAAK,+CAc7E;AA+ED,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAuuDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkMpE"}
@@ -1,3 +1,3 @@
1
1
  export declare const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
2
- export declare const NOBLE_BLE_CONNECTION_TIMEOUT_MS = 10000;
2
+ export declare const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10000;
3
3
  //# sourceMappingURL=noble-ble-timeouts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,+BAA+B,QAAS,CAAC"}
1
+ {"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,8BAA8B,QAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-electron",
3
- "version": "1.2.2-alpha.11",
3
+ "version": "1.2.2-alpha.13",
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.2-alpha.11",
29
- "@onekeyfe/hd-shared": "1.2.2-alpha.11",
30
- "@onekeyfe/hd-transport": "1.2.2-alpha.11",
28
+ "@onekeyfe/hd-core": "1.2.2-alpha.13",
29
+ "@onekeyfe/hd-shared": "1.2.2-alpha.13",
30
+ "@onekeyfe/hd-transport": "1.2.2-alpha.13",
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": "8928100acb893d72361eb74422d5e2a0f7af77d8"
39
+ "gitHead": "c901cdc6b474d015c7f50390fc5dc3db0ca4fbdb"
40
40
  }
@@ -1,8 +1,8 @@
1
1
  import { EventEmitter } from 'events';
2
- import { EOneKeyBleMessageKeys } from '@onekeyfe/hd-shared';
2
+ import { EOneKeyBleMessageKeys, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
3
 
4
4
  import {
5
- NOBLE_BLE_CONNECTION_TIMEOUT_MS,
5
+ NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
6
6
  NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
7
7
  } from '../noble-ble-timeouts';
8
8
 
@@ -26,9 +26,40 @@ describe('Electron Noble BLE device discovery', () => {
26
26
  jest.clearAllMocks();
27
27
  });
28
28
 
29
- test('allows enough time for a slow targeted scan and connection', () => {
29
+ test('bounds targeted scans and subscription callbacks independently', () => {
30
30
  expect(NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS).toBe(5_000);
31
- expect(NOBLE_BLE_CONNECTION_TIMEOUT_MS).toBe(10_000);
31
+ expect(NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS).toBe(10_000);
32
+ });
33
+
34
+ test('maps macOS stale pairing failures without reclassifying generic connection errors', async () => {
35
+ const { createNobleBleConnectionError } = await import('../noble-ble-handler');
36
+
37
+ const staleBondError = createNobleBleConnectionError(
38
+ new Error('CBErrorDomain:14 Peer removed pairing information on the device side')
39
+ );
40
+ expect(staleBondError).toMatchObject({
41
+ errorCode: HardwareErrorCode.BleBondInvalid,
42
+ params: {
43
+ nativeErrorMessage: 'CBErrorDomain:14 Peer removed pairing information on the device side',
44
+ },
45
+ });
46
+ expect(staleBondError.message).toContain(
47
+ 'CBErrorDomain:14 Peer removed pairing information on the device side'
48
+ );
49
+ expect(createNobleBleConnectionError(new Error('Encryption is insufficient'))).toMatchObject({
50
+ errorCode: HardwareErrorCode.BleBondInvalid,
51
+ params: {
52
+ nativeErrorMessage: 'Encryption is insufficient',
53
+ },
54
+ });
55
+ expect(
56
+ createNobleBleConnectionError(new Error('CBATTErrorDomain:14 localized native message'))
57
+ ).toMatchObject({
58
+ errorCode: HardwareErrorCode.BleBondInvalid,
59
+ });
60
+ expect(createNobleBleConnectionError(new Error('connection failed'))).toMatchObject({
61
+ errorCode: HardwareErrorCode.BleConnectedError,
62
+ });
32
63
  });
33
64
 
34
65
  test('keeps safe pacing by default and allows an explicit high-throughput bypass', async () => {
@@ -180,75 +211,33 @@ describe('Electron Noble BLE device discovery', () => {
180
211
  expect(peripheral.connect).toHaveBeenCalledTimes(1);
181
212
  });
182
213
 
183
- test('disconnects a connection callback that arrives after timeout', async () => {
184
- jest.useFakeTimers({ doNotFake: ['performance'] });
185
-
186
- const handlers = new Map<string, IpcHandler>();
187
- const ipcMain = {
188
- handle: jest.fn((channel: string, handler: IpcHandler) => {
189
- handlers.set(channel, handler);
190
- }),
191
- removeHandler: jest.fn((channel: string) => {
192
- handlers.delete(channel);
193
- }),
194
- };
195
- const noble = new EventEmitter() as EventEmitter & {
196
- state: string;
197
- startScanning: jest.Mock;
198
- stopScanning: jest.Mock;
199
- };
200
- let connectCallback: ((error?: Error) => void) | undefined;
201
- let resolveConnectStarted = () => undefined;
202
- const connectStarted = new Promise<void>(resolve => {
203
- resolveConnectStarted = resolve;
214
+ test('settles a pending Noble connect with the native disconnect error', () => {
215
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
216
+ const Noble = require('@stoprocent/noble/lib/noble');
217
+ const bindings = Object.assign(new EventEmitter(), {
218
+ connect: jest.fn(),
204
219
  });
205
- const peripheral = Object.assign(
206
- new EventEmitter(),
207
- createPeripheral('slow-device', 'Pro2 A1B2'),
208
- {
209
- connect: jest.fn((callback: (error?: Error) => void) => {
210
- connectCallback = callback;
211
- resolveConnectStarted();
212
- }),
213
- disconnect: jest.fn((callback: () => void) => callback()),
214
- }
220
+ const noble = new Noble(bindings);
221
+ noble._registerListeners();
222
+ const peripheral = noble._createPeripheral(
223
+ 'aabbccdd',
224
+ '',
225
+ 'unknown',
226
+ true,
227
+ { localName: 'Pro2 A1B2', serviceUuids: ['0001'] },
228
+ -50,
229
+ false
215
230
  );
216
- noble.state = 'poweredOn';
217
- noble.startScanning = jest.fn((_services, _duplicates, callback) => {
218
- callback?.();
219
- noble.emit('discover', peripheral);
220
- });
221
- noble.stopScanning = jest.fn(callback => callback?.());
222
-
223
- jest.doMock('@stoprocent/noble', () => noble);
224
- jest.doMock('electron', () => ({ ipcMain }));
225
- jest.doMock('electron-log', () => ({
226
- info: jest.fn(),
227
- debug: jest.fn(),
228
- error: jest.fn(),
229
- }));
231
+ const connectCallback = jest.fn();
230
232
 
231
- const { setupNobleBleHandlers } = await import('../noble-ble-handler');
232
- setupNobleBleHandlers({
233
- on: jest.fn(),
234
- send: jest.fn(),
235
- } as unknown as WebContents);
236
-
237
- const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
238
- if (!connect) {
239
- throw new Error('Electron Noble BLE connect handler was not registered');
240
- }
241
-
242
- const connectPromise = Promise.resolve(connect(undefined, 'slow-device'));
243
- await connectStarted;
244
- expect(peripheral.connect).toHaveBeenCalledTimes(1);
245
-
246
- jest.advanceTimersByTime(NOBLE_BLE_CONNECTION_TIMEOUT_MS);
247
- await expect(connectPromise).rejects.toThrow('Connection timeout');
233
+ peripheral.connect(connectCallback);
234
+ const nativeError = new Error(
235
+ 'CBATTErrorDomain:14 Peer removed pairing information on the device side'
236
+ );
237
+ bindings.emit('disconnect', 'aabbccdd', nativeError);
248
238
 
249
- connectCallback?.();
250
- await Promise.resolve();
251
- expect(peripheral.disconnect).toHaveBeenCalledTimes(1);
239
+ expect(connectCallback).toHaveBeenCalledWith(nativeError);
240
+ expect(peripheral.state).toBe('disconnected');
252
241
  });
253
242
 
254
243
  test('enumerates a Pro2 communication advertisement after Find My changes its name', async () => {
@@ -10,11 +10,14 @@ import {
10
10
  EOneKeyBleMessageKeys,
11
11
  ERRORS,
12
12
  HardwareErrorCode,
13
+ HardwareErrorCodeMessage,
13
14
  ONEKEY_NOTIFY_CHARACTERISTIC_UUID,
14
15
  ONEKEY_SERVICE_UUID,
15
16
  ONEKEY_WRITE_CHARACTERISTIC_UUID,
16
17
  createKnownBleUuidAliases,
17
18
  hasOnekeyCommunicationService,
19
+ isBleStaleBondErrorText,
20
+ isBleStaleBondHardwareError,
18
21
  isOnekeyBluetoothDevice,
19
22
  isPro2FamilyBleName,
20
23
  matchesKnownBleUuid,
@@ -26,7 +29,7 @@ import { resolveBlePacketCapacity, resolveNobleAttMtu } from './ble-packet-capac
26
29
  import { safeLog } from './types/noble-extended';
27
30
  import { runBleCallbackOperation, softRefreshSubscription } from './ble-ops';
28
31
  import {
29
- NOBLE_BLE_CONNECTION_TIMEOUT_MS,
32
+ NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
30
33
  NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
31
34
  } from './noble-ble-timeouts';
32
35
 
@@ -39,6 +42,22 @@ import type { CharacteristicPair, DeviceInfo, Logger, NobleModule } from './type
39
42
  let noble: NobleModule | null = null;
40
43
  let logger: Logger | null = null;
41
44
 
45
+ export function createNobleBleConnectionError(error: Error, messagePrefix = '') {
46
+ const errorMessage = error.message;
47
+ if (isBleStaleBondErrorText(errorMessage)) {
48
+ const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
49
+ return ERRORS.TypedError(
50
+ HardwareErrorCode.BleBondInvalid,
51
+ `${HardwareErrorCodeMessage[HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`,
52
+ {
53
+ nativeErrorMessage,
54
+ }
55
+ );
56
+ }
57
+
58
+ return ERRORS.TypedError(HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
59
+ }
60
+
42
61
  // Bluetooth state management
43
62
  const bluetoothState: {
44
63
  available: boolean;
@@ -1252,9 +1271,14 @@ async function forceReconnectPeripheral(peripheral: Peripheral, deviceId: string
1252
1271
  }
1253
1272
 
1254
1273
  // Step 3: Re-establish connection
1255
- await runBleCallbackOperation(callback => peripheral.connect(callback), {
1256
- timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
1257
- timeoutBehavior: 'reject',
1274
+ await new Promise<void>((resolve, reject) => {
1275
+ peripheral.connect(error => {
1276
+ if (error) {
1277
+ reject(createNobleBleConnectionError(error));
1278
+ return;
1279
+ }
1280
+ resolve();
1281
+ });
1258
1282
  });
1259
1283
  logger?.info('[NobleBLE] Force reconnect successful');
1260
1284
  connectedDevices.set(deviceId, peripheral);
@@ -1296,12 +1320,7 @@ async function freshScanAndDiscover(
1296
1320
  await new Promise<void>((resolve, reject) => {
1297
1321
  freshPeripheral.connect((error: Error | undefined) => {
1298
1322
  if (error) {
1299
- reject(
1300
- ERRORS.TypedError(
1301
- HardwareErrorCode.BleConnectedError,
1302
- `Fresh peripheral connection failed: ${error.message}`
1303
- )
1304
- );
1323
+ reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
1305
1324
  } else {
1306
1325
  connectedDevices.set(deviceId, freshPeripheral);
1307
1326
  resolve();
@@ -1414,6 +1433,9 @@ async function setupConnectionAndDiscoverServices(
1414
1433
  try {
1415
1434
  await forceReconnectPeripheral(peripheral, deviceId);
1416
1435
  } catch (resetError) {
1436
+ if (isBleStaleBondHardwareError(resetError)) {
1437
+ throw resetError;
1438
+ }
1417
1439
  // A failed reset must not abort the attempt: discovery on the existing
1418
1440
  // link, then the fresh-scan fallback, still have a chance to recover.
1419
1441
  logger?.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
@@ -1666,33 +1688,12 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1666
1688
  }
1667
1689
 
1668
1690
  return new Promise((resolve, reject) => {
1669
- let connectionTimedOut = false;
1670
- const timeout = setTimeout(() => {
1671
- connectionTimedOut = true;
1672
- reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, 'Connection timeout'));
1673
- }, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
1674
-
1675
1691
  // TypeScript type assertion - peripheral is guaranteed to be defined at this point
1676
1692
  const connectedPeripheral = peripheral as Peripheral;
1677
1693
  connectedPeripheral.connect(async (error: Error | undefined) => {
1678
- clearTimeout(timeout);
1679
-
1680
- // Noble may invoke the callback after the SDK timed out and released the request.
1681
- // Ignore it to avoid initializing disposed commands or leaving an orphaned connection.
1682
- if (connectionTimedOut) {
1683
- if (!error) {
1684
- try {
1685
- connectedPeripheral.disconnect(() => undefined);
1686
- } catch {
1687
- // Best-effort cleanup only.
1688
- }
1689
- }
1690
- return;
1691
- }
1692
-
1693
1694
  if (error) {
1694
1695
  logger?.error('[NobleBLE] Connection failed:', error);
1695
- reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, error.message));
1696
+ reject(createNobleBleConnectionError(error));
1696
1697
  return;
1697
1698
  }
1698
1699
 
@@ -1875,7 +1876,7 @@ async function subscribeNotifications(
1875
1876
  timeoutBehavior: 'resolve',
1876
1877
  });
1877
1878
  await runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
1878
- timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
1879
+ timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
1879
1880
  timeoutBehavior: 'reject',
1880
1881
  });
1881
1882
 
@@ -1,2 +1,2 @@
1
1
  export const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5_000;
2
- export const NOBLE_BLE_CONNECTION_TIMEOUT_MS = 10_000;
2
+ export const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10_000;