@onekeyfe/hd-transport-electron 1.2.0-alpha.4 → 1.2.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ble-ops.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  /// <reference types="node" />
2
2
  import type { Characteristic } from '@stoprocent/noble';
3
3
  import type { Logger } from './types/noble-extended';
4
+ type BleCallback = (error?: Error) => void;
5
+ export declare function runBleCallbackOperation(operation: (callback: BleCallback) => void, options: {
6
+ timeoutMs: number;
7
+ timeoutBehavior: 'resolve' | 'reject';
8
+ }): Promise<void>;
4
9
  export interface SoftRefreshParams {
5
10
  deviceId: string;
6
11
  notifyCharacteristic: Characteristic | null | undefined;
@@ -11,4 +16,5 @@ export interface SoftRefreshParams {
11
16
  logger: Logger | null;
12
17
  }
13
18
  export declare function softRefreshSubscription(params: SoftRefreshParams): Promise<void>;
19
+ export {};
14
20
  //# sourceMappingURL=ble-ops.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ble-ops.d.ts","sourceRoot":"","sources":["../src/ble-ops.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG,MAAM,CAAC,CAAC;IAC9E,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CtF"}
1
+ {"version":3,"file":"ble-ops.d.ts","sourceRoot":"","sources":["../src/ble-ops.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,KAAK,WAAW,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;AAE3C,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,EAC1C,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,GACpE,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG,MAAM,CAAC,CAAC;IAC9E,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CtF"}
@@ -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-94c42077.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d58af248.js'); });
36
36
  setupNobleBleHandlers(webContents);
37
37
  });
38
38
  }
package/dist/index.d.ts CHANGED
@@ -26,6 +26,10 @@ interface Logger {
26
26
  error(message: string, ...args: any[]): void;
27
27
  }
28
28
 
29
+ /**
30
+ * Desktop API types for Electron preload script
31
+ * These types define the core interface for Noble BLE communication
32
+ */
29
33
  interface NobleBleAPI {
30
34
  enumerate: () => Promise<{
31
35
  id: string;
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-02fc07fe.js');
5
+ var index = require('./index-5f728113.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-02fc07fe.js');
3
+ var index = require('./index-5f728113.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
5
  var pRetry = require('p-retry');
6
6
 
@@ -17,6 +17,37 @@ function safeLog(logger, level, message, ...args) {
17
17
  }
18
18
  }
19
19
 
20
+ function runBleCallbackOperation(operation, options) {
21
+ return new Promise((resolve, reject) => {
22
+ let settled = false;
23
+ const settle = (error) => {
24
+ if (settled)
25
+ return;
26
+ settled = true;
27
+ clearTimeout(timeout);
28
+ if (error) {
29
+ reject(error);
30
+ }
31
+ else {
32
+ resolve();
33
+ }
34
+ };
35
+ const timeout = setTimeout(() => {
36
+ if (options.timeoutBehavior === 'reject') {
37
+ settle(new Error(`BLE operation timed out after ${options.timeoutMs}ms`));
38
+ }
39
+ else {
40
+ settle();
41
+ }
42
+ }, options.timeoutMs);
43
+ try {
44
+ operation(settle);
45
+ }
46
+ catch (error) {
47
+ settle(error instanceof Error ? error : new Error(String(error)));
48
+ }
49
+ });
50
+ }
20
51
  function softRefreshSubscription(params) {
21
52
  return index.__awaiter(this, void 0, void 0, function* () {
22
53
  const { deviceId, notifyCharacteristic, subscriptionOperations, subscribedDevices, pairedDevices, onNotificationData, logger, } = params;
@@ -25,17 +56,13 @@ function softRefreshSubscription(params) {
25
56
  }
26
57
  logger === null || logger === void 0 ? void 0 : logger.info('[BLE-OPS] Starting subscription refresh', { deviceId });
27
58
  subscriptionOperations.set(deviceId, 'subscribing');
28
- yield new Promise(resolve => {
29
- notifyCharacteristic.unsubscribe(() => resolve());
59
+ yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
60
+ timeoutMs: 250,
61
+ timeoutBehavior: 'resolve',
30
62
  });
31
- yield new Promise((resolve, reject) => {
32
- notifyCharacteristic.subscribe((error) => {
33
- if (error) {
34
- reject(error);
35
- return;
36
- }
37
- resolve();
38
- });
63
+ yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
64
+ timeoutMs: 8000,
65
+ timeoutBehavior: 'reject',
39
66
  });
40
67
  notifyCharacteristic.removeAllListeners('data');
41
68
  notifyCharacteristic.on('data', (data) => {
@@ -59,6 +86,7 @@ const bluetoothState = {
59
86
  initialized: false,
60
87
  };
61
88
  let persistentStateListener = null;
89
+ let persistentDiscoverListener = null;
62
90
  const discoveredDevices = new Map();
63
91
  const connectedDevices = new Map();
64
92
  const pairedDevices = new Set();
@@ -66,16 +94,18 @@ const deviceCharacteristics = new Map();
66
94
  const notificationCallbacks = new Map();
67
95
  const subscribedDevices = new Map();
68
96
  const subscriptionOperations = new Map();
97
+ const deviceDisconnectListeners = new Map();
69
98
  const ONEKEY_SERVICE_UUIDS = [hdShared.ONEKEY_SERVICE_UUID];
70
- const PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS = new Set(['fffd']);
71
- const NORMALIZED_WRITE_UUID = '0002';
72
- const NORMALIZED_NOTIFY_UUID = '0003';
99
+ const ONEKEY_SERVICE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_SERVICE_UUID);
100
+ const ONEKEY_WRITE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_WRITE_CHARACTERISTIC_UUID);
101
+ const ONEKEY_NOTIFY_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_NOTIFY_CHARACTERISTIC_UUID);
73
102
  const BLUETOOTH_INIT_TIMEOUT = 10000;
74
103
  const DEVICE_SCAN_TIMEOUT = 8000;
75
104
  const FAST_SCAN_TIMEOUT = 8000;
76
105
  const DEVICE_CHECK_INTERVAL = 500;
77
106
  const CONNECTION_TIMEOUT = 8000;
78
107
  const SERVICE_DISCOVERY_TIMEOUT = 10000;
108
+ const BLE_CLEANUP_TIMEOUT = 250;
79
109
  const BLE_PACKET_SIZE = 192;
80
110
  const UNIFIED_WRITE_DELAY = 5;
81
111
  const RETRY_CONFIG = { MAX_ATTEMPTS: 15, WRITE_TIMEOUT: 2000 };
@@ -83,37 +113,17 @@ const IS_WINDOWS = process.platform === 'win32';
83
113
  const ABORTABLE_WRITE_ERROR_PATTERNS = [
84
114
  /status:\s*3/i,
85
115
  ];
86
- function getBleUuidKey(uuid) {
87
- const normalized = (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
88
- return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
89
- }
90
- const NORMALIZED_ONEKEY_SERVICE_UUIDS = new Set([
91
- ...ONEKEY_SERVICE_UUIDS.map(uuid => getBleUuidKey(uuid)),
92
- '0001',
93
- ]);
94
- function isGenericBleService(uuid) {
95
- return ['1800', '1801', '180a', '180f'].includes(getBleUuidKey(uuid));
96
- }
97
- function hasOneKeyAdvertisementService(peripheral) {
98
- var _a, _b;
99
- const serviceUuids = (_b = (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.serviceUuids) !== null && _b !== void 0 ? _b : [];
100
- return serviceUuids.some(uuid => {
101
- const uuidKey = getBleUuidKey(uuid);
102
- return (NORMALIZED_ONEKEY_SERVICE_UUIDS.has(uuidKey) ||
103
- PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(uuidKey));
104
- });
105
- }
106
116
  function isOneKeyPeripheral(peripheral) {
107
- var _a;
108
- const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || null;
109
- return hdShared.isOnekeyDevice(deviceName, peripheral.id) || hasOneKeyAdvertisementService(peripheral);
117
+ var _a, _b;
118
+ const serviceUuids = (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.serviceUuids;
119
+ return (hdShared.hasOnekeyCommunicationService(serviceUuids) &&
120
+ hdShared.isOnekeyBluetoothDevice({
121
+ id: peripheral.id,
122
+ localName: (_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName,
123
+ serviceUuids,
124
+ }));
110
125
  }
111
126
  function emitRawNotification(deviceId, data) {
112
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Raw notification', {
113
- deviceId,
114
- dataLength: data.length,
115
- firstBytes: data.subarray(0, 8).toString('hex'),
116
- });
117
127
  const appCb = notificationCallbacks.get(deviceId);
118
128
  if (appCb)
119
129
  appCb(data.toString('hex'));
@@ -250,9 +260,12 @@ function initializeNoble() {
250
260
  };
251
261
  noble.on('stateChange', onStateChange);
252
262
  });
253
- noble.on('discover', (peripheral) => {
254
- handleDeviceDiscovered(peripheral);
255
- });
263
+ if (!persistentDiscoverListener) {
264
+ persistentDiscoverListener = (peripheral) => {
265
+ handleDeviceDiscovered(peripheral);
266
+ };
267
+ noble.on('discover', persistentDiscoverListener);
268
+ }
256
269
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble initialized successfully');
257
270
  }
258
271
  catch (error) {
@@ -277,6 +290,11 @@ function cleanupDevice(deviceId, webContents, options = {}) {
277
290
  const peripheral = connectedDevices.get(deviceId);
278
291
  const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
279
292
  if (cleanupConnection) {
293
+ const disconnectEntry = deviceDisconnectListeners.get(deviceId);
294
+ if (disconnectEntry) {
295
+ disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
296
+ deviceDisconnectListeners.delete(deviceId);
297
+ }
280
298
  connectedDevices.delete(deviceId);
281
299
  deviceCharacteristics.delete(deviceId);
282
300
  notificationCallbacks.delete(deviceId);
@@ -311,10 +329,15 @@ function handleDeviceDisconnect(deviceId, webContents) {
311
329
  });
312
330
  }
313
331
  function setupDisconnectListener(peripheral, deviceId, webContents) {
314
- peripheral.removeAllListeners('disconnect');
315
- peripheral.on('disconnect', () => {
332
+ const existing = deviceDisconnectListeners.get(deviceId);
333
+ if (existing) {
334
+ existing.peripheral.removeListener('disconnect', existing.listener);
335
+ }
336
+ const listener = () => {
316
337
  handleDeviceDisconnect(deviceId, webContents);
317
- });
338
+ };
339
+ deviceDisconnectListeners.set(deviceId, { peripheral, listener });
340
+ peripheral.on('disconnect', listener);
318
341
  }
319
342
  function writeCharacteristicWithAck(deviceId, writeCharacteristic, buffer) {
320
343
  return index.__awaiter(this, void 0, void 0, function* () {
@@ -415,11 +438,6 @@ function transmitHexDataToDevice(deviceId, hexData) {
415
438
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, `Device ${deviceId} not connected or characteristics not available`);
416
439
  }
417
440
  const toBuffer = Buffer.from(hexData, 'hex');
418
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Writing data:', {
419
- deviceId,
420
- dataLength: toBuffer.length,
421
- firstBytes: toBuffer.subarray(0, 8).toString('hex'),
422
- });
423
441
  const doGetWriteCharacteristic = () => { var _a; return (_a = deviceCharacteristics.get(deviceId)) === null || _a === void 0 ? void 0 : _a.write; };
424
442
  if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
425
443
  const writeCharacteristic = doGetWriteCharacteristic();
@@ -464,33 +482,31 @@ function transmitHexDataToDevice(deviceId, hexData) {
464
482
  }
465
483
  function handleDeviceDiscovered(peripheral) {
466
484
  var _a, _b;
467
- const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
468
- const serviceUuids = ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [];
469
485
  if (!isOneKeyPeripheral(peripheral)) {
470
486
  return;
471
487
  }
472
488
  const isNewDevice = !discoveredDevices.has(peripheral.id);
473
489
  discoveredDevices.set(peripheral.id, peripheral);
474
490
  if (isNewDevice) {
475
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discovered OneKey BLE device:', {
476
- name: deviceName,
477
- id: peripheral.id,
478
- serviceUUIDs: serviceUuids,
491
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] OneKey BLE device discovered', {
492
+ deviceId: peripheral.id,
493
+ name: ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device',
494
+ serviceUUIDs: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [],
479
495
  });
480
496
  }
481
497
  }
482
498
  function ensureDiscoverListener() {
483
499
  if (!noble)
484
500
  return;
485
- const listenerCount = noble.listenerCount('discover');
486
- if (listenerCount === 0) {
501
+ if (!persistentDiscoverListener) {
487
502
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discover listener missing, re-adding it');
488
- noble.on('discover', (peripheral) => {
503
+ persistentDiscoverListener = (peripheral) => {
489
504
  handleDeviceDiscovered(peripheral);
490
- });
505
+ };
506
+ noble.on('discover', persistentDiscoverListener);
491
507
  }
492
508
  else {
493
- logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] Discover listener already exists, count:', listenerCount);
509
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] Discover listener already registered');
494
510
  }
495
511
  }
496
512
  function performTargetedScan(targetDeviceId) {
@@ -503,7 +519,7 @@ function performTargetedScan(targetDeviceId) {
503
519
  return new Promise((resolve, reject) => {
504
520
  const onDiscover = (peripheral) => {
505
521
  var _a;
506
- if (peripheral.id === targetDeviceId) {
522
+ if (peripheral.id === targetDeviceId && isOneKeyPeripheral(peripheral)) {
507
523
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Target device found during targeted scan:', {
508
524
  id: peripheral.id,
509
525
  name: (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName,
@@ -595,25 +611,23 @@ function stopScanning() {
595
611
  return index.__awaiter(this, void 0, void 0, function* () {
596
612
  if (!noble)
597
613
  return;
598
- return new Promise(resolve => {
599
- if (!noble) {
600
- resolve();
601
- return;
602
- }
603
- noble.stopScanning(() => {
604
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning stopped');
605
- resolve();
606
- });
614
+ const nobleInstance = noble;
615
+ yield runBleCallbackOperation(callback => nobleInstance.stopScanning(() => callback()), {
616
+ timeoutMs: BLE_CLEANUP_TIMEOUT,
617
+ timeoutBehavior: 'resolve',
607
618
  });
619
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning stopped');
608
620
  });
609
621
  }
610
622
  function cleanupNobleListeners() {
611
623
  if (!noble)
612
624
  return;
613
625
  try {
614
- noble.removeAllListeners('discover');
615
- noble.removeAllListeners('stateChange');
616
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] All Noble listeners cleaned up');
626
+ if (persistentDiscoverListener) {
627
+ noble.removeListener('discover', persistentDiscoverListener);
628
+ persistentDiscoverListener = null;
629
+ }
630
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Owned Noble listeners cleaned up');
617
631
  }
618
632
  catch (error) {
619
633
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to clean up some listeners:', error);
@@ -683,23 +697,22 @@ function discoverServicesAndCharacteristics(peripheral) {
683
697
  }
684
698
  });
685
699
  });
686
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] All services:', services === null || services === void 0 ? void 0 : services.map(s => s.uuid));
687
700
  if (!services || services.length === 0) {
688
701
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No services found');
689
702
  }
690
- let service = services.find(s => NORMALIZED_ONEKEY_SERVICE_UUIDS.has(getBleUuidKey(s.uuid)));
691
- if (!service) {
692
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Known OneKey service UUID not found, trying first vendor service');
693
- service =
694
- services.find(s => PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(getBleUuidKey(s.uuid))) ||
695
- services.find(s => !isGenericBleService(s.uuid)) ||
696
- services[0];
697
- }
703
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] services discovered', {
704
+ deviceId: peripheral.id,
705
+ serviceUUIDs: services.map(service => service.uuid),
706
+ });
707
+ const service = services.find(s => hdShared.matchesKnownBleUuid(s.uuid, ONEKEY_SERVICE_UUID_ALIASES));
698
708
  if (!service) {
699
709
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
700
710
  }
701
711
  const selectedService = service;
702
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Using service:', selectedService.uuid);
712
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] service selected', {
713
+ deviceId: peripheral.id,
714
+ serviceUuid: selectedService.uuid,
715
+ });
703
716
  const characteristics = yield new Promise((resolve, reject) => {
704
717
  selectedService.discoverCharacteristics([], (error, chars) => {
705
718
  if (error) {
@@ -711,30 +724,26 @@ function discoverServicesAndCharacteristics(peripheral) {
711
724
  }
712
725
  });
713
726
  });
714
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discovered characteristics:', {
715
- count: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.length) || 0,
716
- uuids: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.map(c => c.uuid)) || [],
717
- });
718
727
  let writeCharacteristic = null;
719
728
  let notifyCharacteristic = null;
720
729
  for (const characteristic of characteristics) {
721
- const uuid = characteristic.uuid.replace(/-/g, '').toLowerCase();
722
- const uuidKey = uuid.length >= 8 ? uuid.substring(4, 8) : uuid;
723
- if (uuidKey === NORMALIZED_WRITE_UUID) {
730
+ if (hdShared.matchesKnownBleUuid(characteristic.uuid, ONEKEY_WRITE_UUID_ALIASES)) {
724
731
  writeCharacteristic = characteristic;
725
732
  }
726
- else if (uuidKey === NORMALIZED_NOTIFY_UUID) {
733
+ else if (hdShared.matchesKnownBleUuid(characteristic.uuid, ONEKEY_NOTIFY_UUID_ALIASES)) {
727
734
  notifyCharacteristic = characteristic;
728
735
  }
729
736
  }
730
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Characteristic discovery result:', {
731
- writeFound: !!writeCharacteristic,
732
- notifyFound: !!notifyCharacteristic,
733
- });
734
737
  if (!writeCharacteristic || !notifyCharacteristic) {
735
738
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Missing characteristics - write:', !!writeCharacteristic, 'notify:', !!notifyCharacteristic);
736
739
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, 'Required characteristics not found');
737
740
  }
741
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] characteristics selected', {
742
+ deviceId: peripheral.id,
743
+ serviceUuid: selectedService.uuid,
744
+ writeUuid: writeCharacteristic.uuid,
745
+ notifyUuid: notifyCharacteristic.uuid,
746
+ });
738
747
  return { write: writeCharacteristic, notify: notifyCharacteristic };
739
748
  }))();
740
749
  try {
@@ -755,27 +764,17 @@ function forceReconnectPeripheral(peripheral, deviceId) {
755
764
  reason: 'force-reconnect',
756
765
  });
757
766
  if (peripheral.state === 'connected') {
758
- peripheral.removeAllListeners('disconnect');
759
- yield new Promise(resolve => {
760
- peripheral.disconnect(() => {
761
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force disconnect completed');
762
- resolve();
763
- });
764
- });
767
+ yield runBleCallbackOperation(callback => peripheral.disconnect(() => {
768
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force disconnect completed');
769
+ callback();
770
+ }), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
765
771
  }
766
- yield new Promise((resolve, reject) => {
767
- peripheral.connect((error) => {
768
- if (error) {
769
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Force reconnect failed:', error);
770
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, error.message));
771
- }
772
- else {
773
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
774
- connectedDevices.set(deviceId, peripheral);
775
- resolve();
776
- }
777
- });
772
+ yield runBleCallbackOperation(callback => peripheral.connect(callback), {
773
+ timeoutMs: CONNECTION_TIMEOUT,
774
+ timeoutBehavior: 'reject',
778
775
  });
776
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
777
+ connectedDevices.set(deviceId, peripheral);
779
778
  yield hdShared.wait(500);
780
779
  });
781
780
  }
@@ -852,13 +851,23 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
852
851
  }
853
852
  function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
854
853
  return index.__awaiter(this, void 0, void 0, function* () {
854
+ setupDisconnectListener(peripheral, deviceId, webContents);
855
+ try {
856
+ return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
857
+ }
858
+ catch (initialError) {
859
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Direct service discovery failed, retrying after reconnect', {
860
+ deviceId,
861
+ error: initialError,
862
+ });
863
+ }
855
864
  yield forceReconnectPeripheral(peripheral, deviceId);
856
865
  setupDisconnectListener(peripheral, deviceId, webContents);
857
866
  try {
858
867
  return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
859
868
  }
860
- catch (error) {
861
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed, attempting fresh scan...', error);
869
+ catch (reconnectError) {
870
+ logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed after reconnect, attempting fresh scan...', reconnectError);
862
871
  return freshScanAndDiscover(deviceId, webContents);
863
872
  }
864
873
  });
@@ -966,17 +975,20 @@ function disconnectDevice(deviceId) {
966
975
  if (!peripheral) {
967
976
  return;
968
977
  }
969
- return new Promise(resolve => {
970
- peripheral.removeAllListeners('disconnect');
971
- peripheral.disconnect(() => {
972
- cleanupDevice(deviceId, undefined, {
973
- cleanupConnection: true,
974
- sendDisconnectEvent: false,
975
- cancelOperations: true,
976
- reason: 'manual-disconnect',
977
- });
978
- resolve();
979
- });
978
+ const disconnectEntry = deviceDisconnectListeners.get(deviceId);
979
+ if (disconnectEntry) {
980
+ disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
981
+ deviceDisconnectListeners.delete(deviceId);
982
+ }
983
+ yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
984
+ timeoutMs: BLE_CLEANUP_TIMEOUT,
985
+ timeoutBehavior: 'resolve',
986
+ });
987
+ cleanupDevice(deviceId, undefined, {
988
+ cleanupConnection: true,
989
+ sendDisconnectEvent: false,
990
+ cancelOperations: true,
991
+ reason: 'manual-disconnect',
980
992
  });
981
993
  });
982
994
  }
@@ -991,18 +1003,11 @@ function unsubscribeNotifications(deviceId) {
991
1003
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Unsubscribing from notifications for device:', deviceId);
992
1004
  subscriptionOperations.set(deviceId, 'unsubscribing');
993
1005
  try {
994
- yield new Promise((resolve, reject) => {
995
- notifyCharacteristic.unsubscribe((error) => {
996
- if (error) {
997
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Notification unsubscription failed:', error);
998
- reject(error);
999
- }
1000
- else {
1001
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription successful');
1002
- resolve();
1003
- }
1004
- });
1006
+ yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
1007
+ timeoutMs: BLE_CLEANUP_TIMEOUT,
1008
+ timeoutBehavior: 'resolve',
1005
1009
  });
1010
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription completed');
1006
1011
  notifyCharacteristic.removeAllListeners('data');
1007
1012
  notificationCallbacks.delete(deviceId);
1008
1013
  subscribedDevices.delete(deviceId);
@@ -1054,19 +1059,13 @@ function subscribeNotifications(deviceId, callback) {
1054
1059
  notificationCallbacks.set(deviceId, callback);
1055
1060
  function rebuildAppSubscription(deviceId, notifyCharacteristic) {
1056
1061
  return index.__awaiter(this, void 0, void 0, function* () {
1057
- yield new Promise(resolve => {
1058
- notifyCharacteristic.unsubscribe(() => {
1059
- resolve();
1060
- });
1062
+ yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
1063
+ timeoutMs: BLE_CLEANUP_TIMEOUT,
1064
+ timeoutBehavior: 'resolve',
1061
1065
  });
1062
- yield new Promise((resolve, reject) => {
1063
- notifyCharacteristic.subscribe((error) => {
1064
- if (error) {
1065
- reject(error);
1066
- return;
1067
- }
1068
- resolve();
1069
- });
1066
+ yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
1067
+ timeoutMs: CONNECTION_TIMEOUT,
1068
+ timeoutBehavior: 'reject',
1070
1069
  });
1071
1070
  notifyCharacteristic.on('data', (data) => {
1072
1071
  if (!pairedDevices.has(deviceId)) {
@@ -1087,19 +1086,17 @@ function subscribeNotifications(deviceId, callback) {
1087
1086
  });
1088
1087
  }
1089
1088
  function setupNobleBleHandlers(webContents) {
1090
- console.log('[NobleBLE] Attempting to set up Noble BLE handlers.');
1091
1089
  try {
1092
- console.log('[NobleBLE] NOBLE_VERSION_771');
1093
1090
  logger = require('electron-log');
1094
- console.log('[NobleBLE] electron-log loaded successfully.');
1095
1091
  const { ipcMain } = require('electron');
1096
- console.log('[NobleBLE] electron.ipcMain loaded successfully.');
1097
1092
  safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
1098
- console.log(`[NobleBLE] Registering handler for: ${hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE}`);
1099
1093
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
1100
1094
  try {
1101
1095
  const devices = yield enumerateDevices();
1102
- safeLog(logger, 'info', 'Enumeration completed, devices:', devices);
1096
+ safeLog(logger, 'debug', 'Enumeration completed', {
1097
+ count: devices.length,
1098
+ devices: devices.map(device => ({ id: device.id, name: device.name })),
1099
+ });
1103
1100
  return devices;
1104
1101
  }
1105
1102
  catch (error) {
@@ -1124,7 +1121,6 @@ function setupNobleBleHandlers(webContents) {
1124
1121
  yield disconnectDevice(deviceId);
1125
1122
  }));
1126
1123
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, (_event, deviceId, hexData) => index.__awaiter(this, void 0, void 0, function* () {
1127
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] IPC WRITE', { deviceId, len: hexData.length });
1128
1124
  yield transmitHexDataToDevice(deviceId, hexData);
1129
1125
  }));
1130
1126
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_SUBSCRIBE, (_event, deviceId) => index.__awaiter(this, void 0, void 0, function* () {
@@ -1169,23 +1165,23 @@ function setupNobleBleHandlers(webContents) {
1169
1165
  }));
1170
1166
  webContents.on('destroyed', () => {
1171
1167
  safeLog(logger, 'info', 'Cleaning up Noble BLE handlers');
1172
- const deviceIds = Array.from(connectedDevices.keys());
1173
- deviceIds.forEach(deviceId => {
1174
- cleanupDevice(deviceId, undefined, {
1175
- cleanupConnection: true,
1176
- sendDisconnectEvent: false,
1177
- cancelOperations: true,
1178
- reason: 'app-quit',
1179
- });
1168
+ (() => index.__awaiter(this, void 0, void 0, function* () {
1169
+ const deviceIds = Array.from(connectedDevices.keys());
1170
+ for (const deviceId of deviceIds) {
1171
+ yield unsubscribeNotifications(deviceId).catch(() => undefined);
1172
+ yield disconnectDevice(deviceId).catch(() => undefined);
1173
+ }
1174
+ yield stopScanning().catch(() => undefined);
1175
+ if (noble && persistentStateListener) {
1176
+ noble.removeListener('stateChange', persistentStateListener);
1177
+ persistentStateListener = null;
1178
+ }
1179
+ cleanupNobleListeners();
1180
+ discoveredDevices.clear();
1181
+ safeLog(logger, 'info', 'Noble BLE cleanup completed');
1182
+ }))().catch(error => {
1183
+ safeLog(logger, 'error', 'Noble BLE cleanup failed', error);
1180
1184
  });
1181
- stopScanning();
1182
- if (noble && persistentStateListener) {
1183
- noble.removeListener('stateChange', persistentStateListener);
1184
- persistentStateListener = null;
1185
- }
1186
- cleanupNobleListeners();
1187
- discoveredDevices.clear();
1188
- safeLog(logger, 'info', 'Noble BLE cleanup completed');
1189
1185
  });
1190
1186
  safeLog(logger, 'info', 'Noble BLE IPC handlers setup completed');
1191
1187
  }
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AAy9ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAsKpE"}
1
+ {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AA46ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAyJpE"}