@onekeyfe/hd-transport-electron 1.1.34-alpha.1 → 1.1.34-alpha.3

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
@@ -7,12 +7,7 @@ export interface SoftRefreshParams {
7
7
  subscriptionOperations: Map<string, 'subscribing' | 'unsubscribing' | 'idle'>;
8
8
  subscribedDevices: Map<string, boolean>;
9
9
  pairedDevices: Set<string>;
10
- notificationCallbacks: Map<string, (hex: string) => void>;
11
- processNotificationData: (deviceId: string, data: Buffer) => {
12
- isComplete: boolean;
13
- completePacket?: string;
14
- error?: string;
15
- };
10
+ onNotificationData: (deviceId: string, data: Buffer) => void;
16
11
  logger: Logger | null;
17
12
  }
18
13
  export declare function softRefreshSubscription(params: SoftRefreshParams): Promise<void>;
@@ -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,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;IAC1D,uBAAuB,EAAE,CACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,KACT;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDtF"}
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"}
@@ -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-2e41f27c.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-16791965.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-de36348d.js');
5
+ var index = require('./index-55699e30.js');
6
6
 
7
7
 
8
8
 
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-de36348d.js');
3
+ var index = require('./index-55699e30.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
- var hdTransport = require('@onekeyfe/hd-transport');
6
5
  var pRetry = require('p-retry');
7
6
 
8
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -20,7 +19,7 @@ function safeLog(logger, level, message, ...args) {
20
19
 
21
20
  function softRefreshSubscription(params) {
22
21
  return index.__awaiter(this, void 0, void 0, function* () {
23
- const { deviceId, notifyCharacteristic, subscriptionOperations, subscribedDevices, pairedDevices, notificationCallbacks, processNotificationData, logger, } = params;
22
+ const { deviceId, notifyCharacteristic, subscriptionOperations, subscribedDevices, pairedDevices, onNotificationData, logger, } = params;
24
23
  if (!notifyCharacteristic) {
25
24
  throw new Error(`Notify characteristic not available for device ${deviceId}`);
26
25
  }
@@ -44,16 +43,7 @@ function softRefreshSubscription(params) {
44
43
  pairedDevices.add(deviceId);
45
44
  logger === null || logger === void 0 ? void 0 : logger.info('[BLE-OPS] Device paired successfully', { deviceId });
46
45
  }
47
- const result = processNotificationData(deviceId, data);
48
- if (result.error) {
49
- logger === null || logger === void 0 ? void 0 : logger.error('[BLE-OPS] Packet processing error:', result.error);
50
- return;
51
- }
52
- if (result.isComplete && result.completePacket) {
53
- const appCb = notificationCallbacks.get(deviceId);
54
- if (appCb)
55
- appCb(result.completePacket);
56
- }
46
+ onNotificationData(deviceId, data);
57
47
  });
58
48
  subscribedDevices.set(deviceId, true);
59
49
  subscriptionOperations.set(deviceId, 'idle');
@@ -76,15 +66,15 @@ const deviceCharacteristics = new Map();
76
66
  const notificationCallbacks = new Map();
77
67
  const subscribedDevices = new Map();
78
68
  const subscriptionOperations = new Map();
79
- const devicePacketStates = new Map();
80
69
  const ONEKEY_SERVICE_UUIDS = [hdShared.ONEKEY_SERVICE_UUID];
70
+ const PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS = new Set(['fffd']);
81
71
  const NORMALIZED_WRITE_UUID = '0002';
82
72
  const NORMALIZED_NOTIFY_UUID = '0003';
83
73
  const BLUETOOTH_INIT_TIMEOUT = 10000;
84
- const DEVICE_SCAN_TIMEOUT = 5000;
85
- const FAST_SCAN_TIMEOUT = 1500;
74
+ const DEVICE_SCAN_TIMEOUT = 8000;
75
+ const FAST_SCAN_TIMEOUT = 8000;
86
76
  const DEVICE_CHECK_INTERVAL = 500;
87
- const CONNECTION_TIMEOUT = 3000;
77
+ const CONNECTION_TIMEOUT = 8000;
88
78
  const SERVICE_DISCOVERY_TIMEOUT = 10000;
89
79
  const BLE_PACKET_SIZE = 192;
90
80
  const UNIFIED_WRITE_DELAY = 5;
@@ -93,70 +83,35 @@ const IS_WINDOWS = process.platform === 'win32';
93
83
  const ABORTABLE_WRITE_ERROR_PATTERNS = [
94
84
  /status:\s*3/i,
95
85
  ];
96
- const MIN_HEADER_LENGTH = 9;
97
- function processNotificationData(deviceId, data) {
98
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification', {
99
- deviceId,
100
- dataLength: data.length,
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));
101
104
  });
102
- let packetState = devicePacketStates.get(deviceId);
103
- if (!packetState) {
104
- packetState = { bufferLength: 0, buffer: [], packetCount: 0 };
105
- devicePacketStates.set(deviceId, packetState);
106
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Initialized new packet state for device:', deviceId);
107
- }
108
- try {
109
- if (hdShared.isHeaderChunk(data)) {
110
- if (data.length < MIN_HEADER_LENGTH) {
111
- return { isComplete: false, error: 'Invalid header chunk: too short' };
112
- }
113
- const messageId = `${deviceId}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
114
- packetState.bufferLength = data.readInt32BE(5);
115
- packetState.buffer = [...data.subarray(3)];
116
- packetState.packetCount = 1;
117
- packetState.messageId = messageId;
118
- if (packetState.bufferLength < 0) {
119
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Invalid negative packet length detected:', {
120
- length: packetState.bufferLength,
121
- dataLength: data.length,
122
- rawHeader: data.subarray(0, Math.min(16, data.length)).toString('hex'),
123
- lengthBytes: data.subarray(5, 9).toString('hex'),
124
- });
125
- resetPacketState(packetState);
126
- return { isComplete: false, error: 'Invalid packet length in header' };
127
- }
128
- }
129
- else {
130
- if (packetState.bufferLength === 0) {
131
- return { isComplete: false, error: 'Received data chunk without header' };
132
- }
133
- packetState.packetCount += 1;
134
- packetState.buffer = packetState.buffer.concat([...data]);
135
- }
136
- if (packetState.buffer.length - hdTransport.COMMON_HEADER_SIZE >= packetState.bufferLength) {
137
- const completeBuffer = Buffer.from(packetState.buffer);
138
- const hexString = completeBuffer.toString('hex');
139
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Packet assembled', {
140
- deviceId,
141
- totalPackets: packetState.packetCount,
142
- expectedLength: packetState.bufferLength,
143
- actualLength: packetState.buffer.length - hdTransport.COMMON_HEADER_SIZE,
144
- });
145
- resetPacketState(packetState);
146
- return { isComplete: true, completePacket: hexString };
147
- }
148
- return { isComplete: false };
149
- }
150
- catch (error) {
151
- resetPacketState(packetState);
152
- return { isComplete: false, error: `Packet processing error: ${error}` };
153
- }
154
105
  }
155
- function resetPacketState(packetState) {
156
- packetState.bufferLength = 0;
157
- packetState.buffer = [];
158
- packetState.packetCount = 0;
159
- packetState.messageId = undefined;
106
+ 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);
110
+ }
111
+ function emitRawNotification(deviceId, data) {
112
+ const appCb = notificationCallbacks.get(deviceId);
113
+ if (appCb)
114
+ appCb(data.toString('hex'));
160
115
  }
161
116
  function checkBluetoothAvailability() {
162
117
  return index.__awaiter(this, void 0, void 0, function* () {
@@ -201,7 +156,6 @@ function setupPersistentStateListener() {
201
156
  deviceCharacteristics.clear();
202
157
  subscribedDevices.clear();
203
158
  notificationCallbacks.clear();
204
- devicePacketStates.clear();
205
159
  subscriptionOperations.clear();
206
160
  pairedDevices.clear();
207
161
  if (noble) {
@@ -321,7 +275,6 @@ function cleanupDevice(deviceId, webContents, options = {}) {
321
275
  connectedDevices.delete(deviceId);
322
276
  deviceCharacteristics.delete(deviceId);
323
277
  notificationCallbacks.delete(deviceId);
324
- devicePacketStates.delete(deviceId);
325
278
  subscribedDevices.delete(deviceId);
326
279
  subscriptionOperations.delete(deviceId);
327
280
  pairedDevices.delete(deviceId);
@@ -436,8 +389,7 @@ function attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, payl
436
389
  subscriptionOperations,
437
390
  subscribedDevices,
438
391
  pairedDevices,
439
- notificationCallbacks,
440
- processNotificationData,
392
+ onNotificationData: emitRawNotification,
441
393
  logger,
442
394
  });
443
395
  logger === null || logger === void 0 ? void 0 : logger.info('[BLE-Write] Subscription refresh completed', { deviceId });
@@ -458,11 +410,6 @@ function transmitHexDataToDevice(deviceId, hexData) {
458
410
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, `Device ${deviceId} not connected or characteristics not available`);
459
411
  }
460
412
  const toBuffer = Buffer.from(hexData, 'hex');
461
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Writing data:', {
462
- deviceId,
463
- dataLength: toBuffer.length,
464
- firstBytes: toBuffer.subarray(0, 8).toString('hex'),
465
- });
466
413
  const doGetWriteCharacteristic = () => { var _a; return (_a = deviceCharacteristics.get(deviceId)) === null || _a === void 0 ? void 0 : _a.write; };
467
414
  if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
468
415
  const writeCharacteristic = doGetWriteCharacteristic();
@@ -506,13 +453,19 @@ function transmitHexDataToDevice(deviceId, hexData) {
506
453
  });
507
454
  }
508
455
  function handleDeviceDiscovered(peripheral) {
509
- var _a;
510
- const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
511
- if (!hdShared.isOnekeyDevice(deviceName)) {
456
+ var _a, _b;
457
+ if (!isOneKeyPeripheral(peripheral)) {
512
458
  return;
513
459
  }
514
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discovered OneKey device:', deviceName);
460
+ const isNewDevice = !discoveredDevices.has(peripheral.id);
515
461
  discoveredDevices.set(peripheral.id, peripheral);
462
+ if (isNewDevice) {
463
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] OneKey BLE device discovered', {
464
+ deviceId: peripheral.id,
465
+ name: ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device',
466
+ serviceUUIDs: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [],
467
+ });
468
+ }
516
469
  }
517
470
  function ensureDiscoverListener() {
518
471
  if (!noble)
@@ -557,7 +510,7 @@ function performTargetedScan(targetDeviceId) {
557
510
  resolve(null);
558
511
  }, FAST_SCAN_TIMEOUT);
559
512
  nobleInstance.on('discover', onDiscover);
560
- nobleInstance.startScanning(ONEKEY_SERVICE_UUIDS, false, (error) => {
513
+ nobleInstance.startScanning([], false, (error) => {
561
514
  if (error) {
562
515
  clearTimeout(timeoutId);
563
516
  nobleInstance.removeListener('discover', onDiscover);
@@ -607,11 +560,13 @@ function enumerateDevices() {
607
560
  });
608
561
  };
609
562
  const timeoutId = setTimeout(() => {
563
+ checkDevices();
610
564
  cleanup();
611
565
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scan completed, found devices:', devices.length);
612
566
  resolve(devices);
613
567
  }, DEVICE_SCAN_TIMEOUT);
614
- nobleInstance.startScanning(ONEKEY_SERVICE_UUIDS, false, (error) => {
568
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning for OneKey BLE devices');
569
+ nobleInstance.startScanning([], false, (error) => {
615
570
  if (error) {
616
571
  cleanup();
617
572
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start scanning:', error);
@@ -706,7 +661,7 @@ function discoverServicesAndCharacteristics(peripheral) {
706
661
  });
707
662
  const discoveryPromise = (() => index.__awaiter(this, void 0, void 0, function* () {
708
663
  const services = yield new Promise((resolve, reject) => {
709
- peripheral.discoverServices(ONEKEY_SERVICE_UUIDS, (error, svc) => {
664
+ peripheral.discoverServices([], (error, svc) => {
710
665
  if (error) {
711
666
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed:', error);
712
667
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, error.message));
@@ -717,12 +672,30 @@ function discoverServicesAndCharacteristics(peripheral) {
717
672
  });
718
673
  });
719
674
  if (!services || services.length === 0) {
720
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No OneKey services found');
675
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No services found');
676
+ }
677
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] services discovered', {
678
+ deviceId: peripheral.id,
679
+ serviceUUIDs: services.map(service => service.uuid),
680
+ });
681
+ let service = services.find(s => NORMALIZED_ONEKEY_SERVICE_UUIDS.has(getBleUuidKey(s.uuid)));
682
+ if (!service) {
683
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Known OneKey service UUID not found, trying first vendor service');
684
+ service =
685
+ services.find(s => PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(getBleUuidKey(s.uuid))) ||
686
+ services.find(s => !isGenericBleService(s.uuid)) ||
687
+ services[0];
721
688
  }
722
- const service = services[0];
723
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Found service:', service.uuid);
689
+ if (!service) {
690
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
691
+ }
692
+ const selectedService = service;
693
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] service selected', {
694
+ deviceId: peripheral.id,
695
+ serviceUuid: selectedService.uuid,
696
+ });
724
697
  const characteristics = yield new Promise((resolve, reject) => {
725
- service.discoverCharacteristics([hdShared.ONEKEY_WRITE_CHARACTERISTIC_UUID, hdShared.ONEKEY_NOTIFY_CHARACTERISTIC_UUID], (error, chars) => {
698
+ selectedService.discoverCharacteristics([], (error, chars) => {
726
699
  if (error) {
727
700
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Characteristic discovery failed:', error);
728
701
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, error.message));
@@ -732,10 +705,6 @@ function discoverServicesAndCharacteristics(peripheral) {
732
705
  }
733
706
  });
734
707
  });
735
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discovered characteristics:', {
736
- count: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.length) || 0,
737
- uuids: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.map(c => c.uuid)) || [],
738
- });
739
708
  let writeCharacteristic = null;
740
709
  let notifyCharacteristic = null;
741
710
  for (const characteristic of characteristics) {
@@ -748,14 +717,16 @@ function discoverServicesAndCharacteristics(peripheral) {
748
717
  notifyCharacteristic = characteristic;
749
718
  }
750
719
  }
751
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Characteristic discovery result:', {
752
- writeFound: !!writeCharacteristic,
753
- notifyFound: !!notifyCharacteristic,
754
- });
755
720
  if (!writeCharacteristic || !notifyCharacteristic) {
756
721
  logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Missing characteristics - write:', !!writeCharacteristic, 'notify:', !!notifyCharacteristic);
757
722
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, 'Required characteristics not found');
758
723
  }
724
+ logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] characteristics selected', {
725
+ deviceId: peripheral.id,
726
+ serviceUuid: selectedService.uuid,
727
+ writeUuid: writeCharacteristic.uuid,
728
+ notifyUuid: notifyCharacteristic.uuid,
729
+ });
759
730
  return { write: writeCharacteristic, notify: notifyCharacteristic };
760
731
  }))();
761
732
  try {
@@ -944,7 +915,6 @@ function connectDevice(deviceId, webContents) {
944
915
  existingCharacteristics.notify.removeAllListeners('data');
945
916
  }
946
917
  notificationCallbacks.delete(deviceId);
947
- devicePacketStates.delete(deviceId);
948
918
  subscribedDevices.delete(deviceId);
949
919
  }
950
920
  const characteristics = yield setupConnectionAndDiscoverServices(peripheral, deviceId, webContents);
@@ -1027,7 +997,6 @@ function unsubscribeNotifications(deviceId) {
1027
997
  });
1028
998
  notifyCharacteristic.removeAllListeners('data');
1029
999
  notificationCallbacks.delete(deviceId);
1030
- devicePacketStates.delete(deviceId);
1031
1000
  subscribedDevices.delete(deviceId);
1032
1001
  }
1033
1002
  finally {
@@ -1067,12 +1036,6 @@ function subscribeNotifications(deviceId, callback) {
1067
1036
  if (subscribedDevices.get(deviceId)) {
1068
1037
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device already subscribed to characteristic, updating callback only');
1069
1038
  notificationCallbacks.set(deviceId, callback);
1070
- devicePacketStates.set(deviceId, {
1071
- bufferLength: 0,
1072
- buffer: [],
1073
- packetCount: 0,
1074
- messageId: undefined,
1075
- });
1076
1039
  subscriptionOperations.set(deviceId, 'idle');
1077
1040
  return Promise.resolve();
1078
1041
  }
@@ -1081,12 +1044,6 @@ function subscribeNotifications(deviceId, callback) {
1081
1044
  }
1082
1045
  notifyCharacteristic.removeAllListeners('data');
1083
1046
  notificationCallbacks.set(deviceId, callback);
1084
- devicePacketStates.set(deviceId, {
1085
- bufferLength: 0,
1086
- buffer: [],
1087
- packetCount: 0,
1088
- messageId: undefined,
1089
- });
1090
1047
  function rebuildAppSubscription(deviceId, notifyCharacteristic) {
1091
1048
  return index.__awaiter(this, void 0, void 0, function* () {
1092
1049
  yield new Promise(resolve => {
@@ -1108,16 +1065,7 @@ function subscribeNotifications(deviceId, callback) {
1108
1065
  pairedDevices.add(deviceId);
1109
1066
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device paired successfully', { deviceId });
1110
1067
  }
1111
- const result = processNotificationData(deviceId, data);
1112
- if (result.error) {
1113
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Packet processing error:', result.error);
1114
- return;
1115
- }
1116
- if (result.isComplete && result.completePacket) {
1117
- const appCb = notificationCallbacks.get(deviceId);
1118
- if (appCb)
1119
- appCb(result.completePacket);
1120
- }
1068
+ emitRawNotification(deviceId, data);
1121
1069
  });
1122
1070
  });
1123
1071
  }
@@ -1131,19 +1079,17 @@ function subscribeNotifications(deviceId, callback) {
1131
1079
  });
1132
1080
  }
1133
1081
  function setupNobleBleHandlers(webContents) {
1134
- console.log('[NobleBLE] Attempting to set up Noble BLE handlers.');
1135
1082
  try {
1136
- console.log('[NobleBLE] NOBLE_VERSION_771');
1137
1083
  logger = require('electron-log');
1138
- console.log('[NobleBLE] electron-log loaded successfully.');
1139
1084
  const { ipcMain } = require('electron');
1140
- console.log('[NobleBLE] electron.ipcMain loaded successfully.');
1141
1085
  safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
1142
- console.log(`[NobleBLE] Registering handler for: ${hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE}`);
1143
1086
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
1144
1087
  try {
1145
1088
  const devices = yield enumerateDevices();
1146
- safeLog(logger, 'info', 'Enumeration completed, devices:', devices);
1089
+ safeLog(logger, 'debug', 'Enumeration completed', {
1090
+ count: devices.length,
1091
+ devices: devices.map(device => ({ id: device.id, name: device.name })),
1092
+ });
1147
1093
  return devices;
1148
1094
  }
1149
1095
  catch (error) {
@@ -1168,7 +1114,6 @@ function setupNobleBleHandlers(webContents) {
1168
1114
  yield disconnectDevice(deviceId);
1169
1115
  }));
1170
1116
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, (_event, deviceId, hexData) => index.__awaiter(this, void 0, void 0, function* () {
1171
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] IPC WRITE', { deviceId, len: hexData.length });
1172
1117
  yield transmitHexDataToDevice(deviceId, hexData);
1173
1118
  }));
1174
1119
  ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_SUBSCRIBE, (_event, deviceId) => index.__awaiter(this, void 0, void 0, function* () {
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AAshDhE,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":"AAoBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AAw8ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAiKpE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-electron",
3
- "version": "1.1.34-alpha.1",
3
+ "version": "1.1.34-alpha.3",
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.1.34-alpha.1",
29
- "@onekeyfe/hd-shared": "1.1.34-alpha.1",
30
- "@onekeyfe/hd-transport": "1.1.34-alpha.1",
28
+ "@onekeyfe/hd-core": "1.1.34-alpha.3",
29
+ "@onekeyfe/hd-shared": "1.1.34-alpha.3",
30
+ "@onekeyfe/hd-transport": "1.1.34-alpha.3",
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": "e017f56235eae6eab82f1c687699a4204f3173f9"
39
+ "gitHead": "3688bc8495eeb2ffd5616270d13fa29e8967623a"
40
40
  }
package/src/ble-ops.ts CHANGED
@@ -7,15 +7,7 @@ export interface SoftRefreshParams {
7
7
  subscriptionOperations: Map<string, 'subscribing' | 'unsubscribing' | 'idle'>;
8
8
  subscribedDevices: Map<string, boolean>;
9
9
  pairedDevices: Set<string>;
10
- notificationCallbacks: Map<string, (hex: string) => void>;
11
- processNotificationData: (
12
- deviceId: string,
13
- data: Buffer
14
- ) => {
15
- isComplete: boolean;
16
- completePacket?: string;
17
- error?: string;
18
- };
10
+ onNotificationData: (deviceId: string, data: Buffer) => void;
19
11
  logger: Logger | null;
20
12
  }
21
13
 
@@ -26,8 +18,7 @@ export async function softRefreshSubscription(params: SoftRefreshParams): Promis
26
18
  subscriptionOperations,
27
19
  subscribedDevices,
28
20
  pairedDevices,
29
- notificationCallbacks,
30
- processNotificationData,
21
+ onNotificationData,
31
22
  logger,
32
23
  } = params;
33
24
 
@@ -60,15 +51,7 @@ export async function softRefreshSubscription(params: SoftRefreshParams): Promis
60
51
  logger?.info('[BLE-OPS] Device paired successfully', { deviceId });
61
52
  }
62
53
 
63
- const result = processNotificationData(deviceId, data);
64
- if (result.error) {
65
- logger?.error('[BLE-OPS] Packet processing error:', result.error);
66
- return;
67
- }
68
- if (result.isComplete && result.completePacket) {
69
- const appCb = notificationCallbacks.get(deviceId);
70
- if (appCb) appCb(result.completePacket);
71
- }
54
+ onNotificationData(deviceId, data);
72
55
  });
73
56
 
74
57
  subscribedDevices.set(deviceId, true);
@@ -9,14 +9,10 @@ import {
9
9
  EOneKeyBleMessageKeys,
10
10
  ERRORS,
11
11
  HardwareErrorCode,
12
- ONEKEY_NOTIFY_CHARACTERISTIC_UUID,
13
12
  ONEKEY_SERVICE_UUID,
14
- ONEKEY_WRITE_CHARACTERISTIC_UUID,
15
- isHeaderChunk,
16
13
  isOnekeyDevice,
17
14
  wait,
18
15
  } from '@onekeyfe/hd-shared';
19
- import { COMMON_HEADER_SIZE } from '@onekeyfe/hd-transport';
20
16
  import pRetry from 'p-retry';
21
17
 
22
18
  import { safeLog } from './types/noble-extended';
@@ -55,15 +51,6 @@ const subscribedDevices = new Map<string, boolean>(); // Track subscription stat
55
51
  // 🔒 Subscription operation state tracking to prevent race conditions
56
52
  const subscriptionOperations = new Map<string, 'subscribing' | 'unsubscribing' | 'idle'>();
57
53
 
58
- // Packet reassembly state for each device
59
- interface PacketAssemblyState {
60
- bufferLength: number;
61
- buffer: number[];
62
- packetCount: number;
63
- messageId?: string; // Add message ID to track concurrent requests
64
- }
65
- const devicePacketStates = new Map<string, PacketAssemblyState>();
66
-
67
54
  // Windows-only response watchdog state moved to utils/windows-ble-recovery
68
55
 
69
56
  // Pairing-related state removed
@@ -72,6 +59,7 @@ const devicePacketStates = new Map<string, PacketAssemblyState>();
72
59
 
73
60
  // Service UUIDs to scan for - using constants from hd-shared
74
61
  const ONEKEY_SERVICE_UUIDS = [ONEKEY_SERVICE_UUID];
62
+ const PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS = new Set(['fffd']);
75
63
 
76
64
  // Pre-normalized characteristic identifiers for fast comparison
77
65
  const NORMALIZED_WRITE_UUID = '0002';
@@ -79,10 +67,10 @@ const NORMALIZED_NOTIFY_UUID = '0003';
79
67
 
80
68
  // Timeout and interval constants
81
69
  const BLUETOOTH_INIT_TIMEOUT = 10000; // 10 seconds for Bluetooth initialization
82
- const DEVICE_SCAN_TIMEOUT = 5000; // 5 seconds for device scanning
83
- const FAST_SCAN_TIMEOUT = 1500; // 1.5 seconds for fast targeted scanning
70
+ const DEVICE_SCAN_TIMEOUT = 8000; // 8 seconds for device scanning (Pro2 has longer advertising interval)
71
+ const FAST_SCAN_TIMEOUT = 8000; // 8 seconds for targeted scanning (Pro2 has longer advertising interval)
84
72
  const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks
85
- const CONNECTION_TIMEOUT = 3000; // 3 seconds for device connection
73
+ const CONNECTION_TIMEOUT = 8000; // 8 seconds for device connection (BLE reconnect after release can be slow)
86
74
  const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
87
75
 
88
76
  // Write-related constants
@@ -94,101 +82,43 @@ const ABORTABLE_WRITE_ERROR_PATTERNS = [
94
82
  /status:\s*3/i, // Windows pairing cancelled / GATT write failed
95
83
  ];
96
84
 
97
- // Validation limits
98
- const MIN_HEADER_LENGTH = 9; // Minimum header chunk length
99
-
100
- // Packet processing result types
101
- interface PacketProcessResult {
102
- isComplete: boolean;
103
- completePacket?: string;
104
- error?: string;
85
+ function getBleUuidKey(uuid?: string | null) {
86
+ const normalized = (uuid ?? '').replace(/-/g, '').toLowerCase();
87
+ return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
105
88
  }
106
89
 
107
- // Process incoming BLE notification data with proper packet reassembly
108
- function processNotificationData(deviceId: string, data: Buffer): PacketProcessResult {
109
- // notification telemetry
110
- logger?.info('[NobleBLE] Notification', {
111
- deviceId,
112
- dataLength: data.length,
113
- });
114
-
115
- // Get or initialize packet state for this device
116
- let packetState = devicePacketStates.get(deviceId);
117
- if (!packetState) {
118
- packetState = { bufferLength: 0, buffer: [], packetCount: 0 };
119
- devicePacketStates.set(deviceId, packetState);
120
- logger?.info('[NobleBLE] Initialized new packet state for device:', deviceId);
121
- }
90
+ const NORMALIZED_ONEKEY_SERVICE_UUIDS = new Set([
91
+ ...ONEKEY_SERVICE_UUIDS.map(uuid => getBleUuidKey(uuid)),
92
+ '0001',
93
+ ]);
122
94
 
123
- try {
124
- if (isHeaderChunk(data)) {
125
- // Validate header chunk
126
- if (data.length < MIN_HEADER_LENGTH) {
127
- return { isComplete: false, error: 'Invalid header chunk: too short' };
128
- }
129
-
130
- // Generate message ID for this packet sequence
131
- const messageId = `${deviceId}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
132
-
133
- // Reset packet state for new message
134
- packetState.bufferLength = data.readInt32BE(5);
135
- packetState.buffer = [...data.subarray(3)];
136
- packetState.packetCount = 1;
137
- packetState.messageId = messageId;
138
-
139
- // Only validate for negative lengths (which would be invalid)
140
- if (packetState.bufferLength < 0) {
141
- logger?.error('[NobleBLE] Invalid negative packet length detected:', {
142
- length: packetState.bufferLength,
143
- dataLength: data.length,
144
- rawHeader: data.subarray(0, Math.min(16, data.length)).toString('hex'),
145
- lengthBytes: data.subarray(5, 9).toString('hex'),
146
- });
147
- resetPacketState(packetState);
148
- return { isComplete: false, error: 'Invalid packet length in header' };
149
- }
150
- } else {
151
- // Validate we have an active packet session
152
- if (packetState.bufferLength === 0) {
153
- return { isComplete: false, error: 'Received data chunk without header' };
154
- }
155
-
156
- // Increment packet counter and append data
157
- packetState.packetCount += 1;
158
- packetState.buffer = packetState.buffer.concat([...data]);
159
- }
160
-
161
- // Check if packet is complete
162
- if (packetState.buffer.length - COMMON_HEADER_SIZE >= packetState.bufferLength) {
163
- const completeBuffer = Buffer.from(packetState.buffer);
164
- const hexString = completeBuffer.toString('hex');
165
-
166
- logger?.info('[NobleBLE] Packet assembled', {
167
- deviceId,
168
- totalPackets: packetState.packetCount,
169
- expectedLength: packetState.bufferLength,
170
- actualLength: packetState.buffer.length - COMMON_HEADER_SIZE,
171
- });
172
-
173
- // Reset packet state for next message
174
- resetPacketState(packetState);
95
+ function isGenericBleService(uuid?: string | null) {
96
+ return ['1800', '1801', '180a', '180f'].includes(getBleUuidKey(uuid));
97
+ }
175
98
 
176
- return { isComplete: true, completePacket: hexString };
177
- }
99
+ function hasOneKeyAdvertisementService(peripheral: Peripheral) {
100
+ const serviceUuids = peripheral.advertisement?.serviceUuids ?? [];
101
+ return serviceUuids.some(uuid => {
102
+ const uuidKey = getBleUuidKey(uuid);
103
+ return (
104
+ NORMALIZED_ONEKEY_SERVICE_UUIDS.has(uuidKey) ||
105
+ PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(uuidKey)
106
+ );
107
+ });
108
+ }
178
109
 
179
- return { isComplete: false };
180
- } catch (error) {
181
- resetPacketState(packetState);
182
- return { isComplete: false, error: `Packet processing error: ${error}` };
183
- }
110
+ function isOneKeyPeripheral(peripheral: Peripheral) {
111
+ const deviceName = peripheral.advertisement?.localName || null;
112
+ return isOnekeyDevice(deviceName, peripheral.id) || hasOneKeyAdvertisementService(peripheral);
184
113
  }
185
114
 
186
- // Reset packet state to clean state
187
- function resetPacketState(packetState: PacketAssemblyState): void {
188
- packetState.bufferLength = 0;
189
- packetState.buffer = [];
190
- packetState.packetCount = 0;
191
- packetState.messageId = undefined;
115
+ /**
116
+ * Forward a single BLE notification chunk (not an assembled packet) to the
117
+ * renderer-side transport. Packet reassembly is handled by ElectronBleTransport.
118
+ */
119
+ function emitRawNotification(deviceId: string, data: Buffer): void {
120
+ const appCb = notificationCallbacks.get(deviceId);
121
+ if (appCb) appCb(data.toString('hex'));
192
122
  }
193
123
 
194
124
  // Check Bluetooth availability - returns detailed state
@@ -250,7 +180,6 @@ function setupPersistentStateListener(): void {
250
180
  deviceCharacteristics.clear();
251
181
  subscribedDevices.clear();
252
182
  notificationCallbacks.clear();
253
- devicePacketStates.clear();
254
183
  subscriptionOperations.clear();
255
184
  pairedDevices.clear();
256
185
 
@@ -428,7 +357,6 @@ function cleanupDevice(
428
357
  connectedDevices.delete(deviceId);
429
358
  deviceCharacteristics.delete(deviceId);
430
359
  notificationCallbacks.delete(deviceId);
431
- devicePacketStates.delete(deviceId);
432
360
  subscribedDevices.delete(deviceId);
433
361
  subscriptionOperations.delete(deviceId);
434
362
  pairedDevices.delete(deviceId);
@@ -590,8 +518,7 @@ async function attemptWindowsWriteUntilPaired(
590
518
  subscriptionOperations,
591
519
  subscribedDevices,
592
520
  pairedDevices,
593
- notificationCallbacks,
594
- processNotificationData,
521
+ onNotificationData: emitRawNotification,
595
522
  logger,
596
523
  });
597
524
  logger?.info('[BLE-Write] Subscription refresh completed', { deviceId });
@@ -618,12 +545,6 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
618
545
  }
619
546
 
620
547
  const toBuffer = Buffer.from(hexData, 'hex');
621
- logger?.info('[NobleBLE] Writing data:', {
622
- deviceId,
623
- dataLength: toBuffer.length,
624
- firstBytes: toBuffer.subarray(0, 8).toString('hex'),
625
- });
626
-
627
548
  const doGetWriteCharacteristic = () => deviceCharacteristics.get(deviceId)?.write;
628
549
 
629
550
  if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
@@ -685,15 +606,21 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
685
606
 
686
607
  // Handle discovered device (for general enumeration only)
687
608
  function handleDeviceDiscovered(peripheral: Peripheral): void {
688
- const deviceName = peripheral.advertisement?.localName || 'Unknown Device';
689
-
690
- // Only process OneKey devices for general discovery
691
- if (!isOnekeyDevice(deviceName)) {
609
+ // Only process OneKey candidates for general discovery. Avoid logging every
610
+ // ambient BLE peripheral; it makes Pro2 debugging hard to read.
611
+ if (!isOneKeyPeripheral(peripheral)) {
692
612
  return;
693
613
  }
694
614
 
695
- logger?.info('[NobleBLE] Discovered OneKey device:', deviceName);
615
+ const isNewDevice = !discoveredDevices.has(peripheral.id);
696
616
  discoveredDevices.set(peripheral.id, peripheral);
617
+ if (isNewDevice) {
618
+ logger?.debug('[NobleBLE] OneKey BLE device discovered', {
619
+ deviceId: peripheral.id,
620
+ name: peripheral.advertisement?.localName || 'Unknown Device',
621
+ serviceUUIDs: peripheral.advertisement?.serviceUuids || [],
622
+ });
623
+ }
697
624
  }
698
625
 
699
626
  // Ensure discover listener is properly set up
@@ -753,8 +680,8 @@ async function performTargetedScan(targetDeviceId: string): Promise<Peripheral |
753
680
  // Add local listener for this scan
754
681
  nobleInstance.on('discover', onDiscover);
755
682
 
756
- // Start scanning
757
- nobleInstance.startScanning(ONEKEY_SERVICE_UUIDS, false, (error?: Error) => {
683
+ // Start scanning — no service UUID filter (Pro2 may use different service UUID)
684
+ nobleInstance.startScanning([], false, (error?: Error) => {
758
685
  if (error) {
759
686
  clearTimeout(timeoutId);
760
687
  nobleInstance.removeListener('discover', onDiscover);
@@ -816,15 +743,19 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
816
743
  });
817
744
  };
818
745
 
819
- // Set timeout for scanning
746
+ // Set timeout for scanning — use longer timeout to catch slow-advertising devices like Pro2
820
747
  const timeoutId = setTimeout(() => {
748
+ // Final collection before resolving — catches devices discovered near the deadline
749
+ checkDevices();
821
750
  cleanup();
822
751
  logger?.info('[NobleBLE] Scan completed, found devices:', devices.length);
823
752
  resolve(devices);
824
753
  }, DEVICE_SCAN_TIMEOUT);
825
754
 
826
- // Start scanning for OneKey service UUIDs
827
- nobleInstance.startScanning(ONEKEY_SERVICE_UUIDS, false, (error?: Error) => {
755
+ // Start scanning without a service UUID filter so Pro2 advertisements with
756
+ // short vendor UUIDs can be found, but only OneKey candidates are logged/returned.
757
+ logger?.info('[NobleBLE] Scanning for OneKey BLE devices');
758
+ nobleInstance.startScanning([], false, (error?: Error) => {
828
759
  if (error) {
829
760
  cleanup();
830
761
  logger?.error('[NobleBLE] Failed to start scanning:', error);
@@ -952,9 +883,9 @@ async function discoverServicesAndCharacteristics(
952
883
 
953
884
  // Main discovery logic as async function
954
885
  const discoveryPromise = (async (): Promise<CharacteristicPair> => {
955
- // Step 1: Discover services (promisified)
886
+ // Step 1: Discover ALL services (no filter — Pro2 may use different service UUID)
956
887
  const services = await new Promise<Service[]>((resolve, reject) => {
957
- peripheral.discoverServices(ONEKEY_SERVICE_UUIDS, (error, svc) => {
888
+ peripheral.discoverServices([], (error, svc) => {
958
889
  if (error) {
959
890
  logger?.error('[NobleBLE] Service discovery failed:', error);
960
891
  reject(ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, error.message));
@@ -965,33 +896,44 @@ async function discoverServicesAndCharacteristics(
965
896
  });
966
897
 
967
898
  if (!services || services.length === 0) {
968
- throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, 'No OneKey services found');
899
+ throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, 'No services found');
969
900
  }
970
901
 
971
- const service = services[0];
972
- logger?.info('[NobleBLE] Found service:', service.uuid);
902
+ logger?.debug('[NobleBLE] services discovered', {
903
+ deviceId: peripheral.id,
904
+ serviceUUIDs: services.map(service => service.uuid),
905
+ });
973
906
 
974
- // Step 2: Discover characteristics (promisified)
907
+ // Find OneKey service — Noble may expose 128-bit UUIDs as short UUID keys.
908
+ let service = services.find(s => NORMALIZED_ONEKEY_SERVICE_UUIDS.has(getBleUuidKey(s.uuid)));
909
+ if (!service) {
910
+ logger?.info('[NobleBLE] Known OneKey service UUID not found, trying first vendor service');
911
+ service =
912
+ services.find(s => PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(getBleUuidKey(s.uuid))) ||
913
+ services.find(s => !isGenericBleService(s.uuid)) ||
914
+ services[0];
915
+ }
916
+ if (!service) {
917
+ throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
918
+ }
919
+ const selectedService = service;
920
+ logger?.debug('[NobleBLE] service selected', {
921
+ deviceId: peripheral.id,
922
+ serviceUuid: selectedService.uuid,
923
+ });
924
+ // Step 2: Discover ALL characteristics (no filter)
975
925
  const characteristics = await new Promise<Characteristic[]>((resolve, reject) => {
976
- service.discoverCharacteristics(
977
- [ONEKEY_WRITE_CHARACTERISTIC_UUID, ONEKEY_NOTIFY_CHARACTERISTIC_UUID],
978
- (error, chars) => {
979
- if (error) {
980
- logger?.error('[NobleBLE] Characteristic discovery failed:', error);
981
- reject(ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound, error.message));
982
- } else {
983
- resolve(chars);
984
- }
926
+ selectedService.discoverCharacteristics([], (error, chars) => {
927
+ if (error) {
928
+ logger?.error('[NobleBLE] Characteristic discovery failed:', error);
929
+ reject(ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound, error.message));
930
+ } else {
931
+ resolve(chars);
985
932
  }
986
- );
933
+ });
987
934
  });
988
935
 
989
936
  // Step 3: Find required characteristics
990
- logger?.info('[NobleBLE] Discovered characteristics:', {
991
- count: characteristics?.length || 0,
992
- uuids: characteristics?.map(c => c.uuid) || [],
993
- });
994
-
995
937
  let writeCharacteristic: Characteristic | null = null;
996
938
  let notifyCharacteristic: Characteristic | null = null;
997
939
 
@@ -1006,11 +948,6 @@ async function discoverServicesAndCharacteristics(
1006
948
  }
1007
949
  }
1008
950
 
1009
- logger?.info('[NobleBLE] Characteristic discovery result:', {
1010
- writeFound: !!writeCharacteristic,
1011
- notifyFound: !!notifyCharacteristic,
1012
- });
1013
-
1014
951
  if (!writeCharacteristic || !notifyCharacteristic) {
1015
952
  logger?.error(
1016
953
  '[NobleBLE] Missing characteristics - write:',
@@ -1024,6 +961,13 @@ async function discoverServicesAndCharacteristics(
1024
961
  );
1025
962
  }
1026
963
 
964
+ logger?.debug('[NobleBLE] characteristics selected', {
965
+ deviceId: peripheral.id,
966
+ serviceUuid: selectedService.uuid,
967
+ writeUuid: writeCharacteristic.uuid,
968
+ notifyUuid: notifyCharacteristic.uuid,
969
+ });
970
+
1027
971
  return { write: writeCharacteristic, notify: notifyCharacteristic };
1028
972
  })();
1029
973
 
@@ -1320,7 +1264,6 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1320
1264
  existingCharacteristics.notify.removeAllListeners('data');
1321
1265
  }
1322
1266
  notificationCallbacks.delete(deviceId);
1323
- devicePacketStates.delete(deviceId);
1324
1267
  subscribedDevices.delete(deviceId);
1325
1268
  // Continue to re-setup the connection properly
1326
1269
  }
@@ -1431,7 +1374,6 @@ async function unsubscribeNotifications(deviceId: string): Promise<void> {
1431
1374
  // Remove all listeners and clear subscription status
1432
1375
  notifyCharacteristic.removeAllListeners('data');
1433
1376
  notificationCallbacks.delete(deviceId);
1434
- devicePacketStates.delete(deviceId);
1435
1377
  subscribedDevices.delete(deviceId);
1436
1378
  } finally {
1437
1379
  // 🔒 CRITICAL: Always clear operation state (even on error)
@@ -1498,14 +1440,6 @@ async function subscribeNotifications(
1498
1440
  // Just update the callback without re-subscribing
1499
1441
  notificationCallbacks.set(deviceId, callback);
1500
1442
 
1501
- // Reset packet state for new session
1502
- devicePacketStates.set(deviceId, {
1503
- bufferLength: 0,
1504
- buffer: [],
1505
- packetCount: 0,
1506
- messageId: undefined,
1507
- });
1508
-
1509
1443
  // 🔒 Clear operation state
1510
1444
  subscriptionOperations.set(deviceId, 'idle');
1511
1445
  return Promise.resolve();
@@ -1522,14 +1456,6 @@ async function subscribeNotifications(
1522
1456
  // Store callback for this device
1523
1457
  notificationCallbacks.set(deviceId, callback);
1524
1458
 
1525
- // Reset packet state for new subscription session
1526
- devicePacketStates.set(deviceId, {
1527
- bufferLength: 0,
1528
- buffer: [],
1529
- packetCount: 0,
1530
- messageId: undefined,
1531
- });
1532
-
1533
1459
  // Helper: rebuild a clean application-layer subscription
1534
1460
  async function rebuildAppSubscription(
1535
1461
  deviceId: string,
@@ -1558,15 +1484,7 @@ async function subscribeNotifications(
1558
1484
  logger?.info('[NobleBLE] Device paired successfully', { deviceId });
1559
1485
  }
1560
1486
 
1561
- const result = processNotificationData(deviceId, data);
1562
- if (result.error) {
1563
- logger?.error('[NobleBLE] Packet processing error:', result.error);
1564
- return;
1565
- }
1566
- if (result.isComplete && result.completePacket) {
1567
- const appCb = notificationCallbacks.get(deviceId);
1568
- if (appCb) appCb(result.completePacket);
1569
- }
1487
+ emitRawNotification(deviceId, data);
1570
1488
  });
1571
1489
  }
1572
1490
 
@@ -1581,29 +1499,25 @@ async function subscribeNotifications(
1581
1499
 
1582
1500
  // Setup IPC handlers
1583
1501
  export function setupNobleBleHandlers(webContents: WebContents): void {
1584
- // Use console.log for initial logging as electron-log might not be available yet.
1585
- console.log('[NobleBLE] Attempting to set up Noble BLE handlers.');
1586
1502
  try {
1587
- console.log('[NobleBLE] NOBLE_VERSION_771');
1588
-
1589
1503
  // @ts-ignore – electron-log is only available at runtime
1590
1504
  // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
1591
1505
  logger = require('electron-log') as Logger;
1592
- console.log('[NobleBLE] electron-log loaded successfully.');
1593
1506
 
1594
1507
  // @ts-ignore – electron is only available at runtime
1595
1508
  // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
1596
1509
  const { ipcMain } = require('electron');
1597
- console.log('[NobleBLE] electron.ipcMain loaded successfully.');
1598
1510
 
1599
1511
  safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
1600
1512
 
1601
1513
  // Handle enumerate request
1602
- console.log(`[NobleBLE] Registering handler for: ${EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE}`);
1603
1514
  ipcMain.handle(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, async () => {
1604
1515
  try {
1605
1516
  const devices = await enumerateDevices();
1606
- safeLog(logger, 'info', 'Enumeration completed, devices:', devices);
1517
+ safeLog(logger, 'debug', 'Enumeration completed', {
1518
+ count: devices.length,
1519
+ devices: devices.map(device => ({ id: device.id, name: device.name })),
1520
+ });
1607
1521
  return devices;
1608
1522
  } catch (error) {
1609
1523
  safeLog(logger, 'error', 'Enumeration failed:', error);
@@ -1648,7 +1562,6 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
1648
1562
  ipcMain.handle(
1649
1563
  EOneKeyBleMessageKeys.NOBLE_BLE_WRITE,
1650
1564
  async (_event: IpcMainInvokeEvent, deviceId: string, hexData: string) => {
1651
- logger?.info('[NobleBLE] IPC WRITE', { deviceId, len: hexData.length });
1652
1565
  await transmitHexDataToDevice(deviceId, hexData);
1653
1566
  }
1654
1567
  );