@onekeyfe/hd-transport-electron 1.2.0-alpha.163 → 1.2.0-alpha.165

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-8b4037fe.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-255383f1.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-b18020df.js');
5
+ var index = require('./index-5478256a.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-b18020df.js');
3
+ var index = require('./index-5478256a.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
5
  var pRetry = require('p-retry');
6
6
 
@@ -599,18 +599,36 @@ function transmitHexDataToDevice(deviceId, hexData, options) {
599
599
  }
600
600
  });
601
601
  }
602
+ const BLE_COLD_CONNECT_SCAN_TIMEOUT_MS = 1500;
603
+ const bleNamesById = new Map();
604
+ function rememberBleName(deviceId, name) {
605
+ const trimmed = name === null || name === void 0 ? void 0 : name.trim();
606
+ if (trimmed) {
607
+ bleNamesById.set(deviceId, trimmed);
608
+ }
609
+ }
610
+ function resolveBleName(deviceId) {
611
+ var _a, _b, _c, _d, _e, _f;
612
+ const live = ((_c = (_b = (_a = connectedDevices.get(deviceId)) === null || _a === void 0 ? void 0 : _a.advertisement) === null || _b === void 0 ? void 0 : _b.localName) === null || _c === void 0 ? void 0 : _c.trim()) ||
613
+ ((_f = (_e = (_d = discoveredDevices.get(deviceId)) === null || _d === void 0 ? void 0 : _d.advertisement) === null || _e === void 0 ? void 0 : _e.localName) === null || _f === void 0 ? void 0 : _f.trim());
614
+ return live || bleNamesById.get(deviceId);
615
+ }
616
+ function shouldConnectByIdFirst(deviceId) {
617
+ return hdShared.isPro2FamilyBleName(resolveBleName(deviceId));
618
+ }
602
619
  function handleDeviceDiscovered(peripheral) {
603
- var _a, _b;
620
+ var _a, _b, _c;
604
621
  if (!isOneKeyPeripheral(peripheral)) {
605
622
  return;
606
623
  }
607
624
  const isNewDevice = !discoveredDevices.has(peripheral.id);
608
625
  discoveredDevices.set(peripheral.id, peripheral);
626
+ rememberBleName(peripheral.id, (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName);
609
627
  if (isNewDevice) {
610
628
  logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] OneKey BLE device discovered', {
611
629
  deviceId: peripheral.id,
612
- name: ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device',
613
- serviceUUIDs: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [],
630
+ name: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName) || 'Unknown Device',
631
+ serviceUUIDs: ((_c = peripheral.advertisement) === null || _c === void 0 ? void 0 : _c.serviceUuids) || [],
614
632
  });
615
633
  }
616
634
  }
@@ -636,7 +654,7 @@ function waitForNobleScanStop(nobleInstance) {
636
654
  });
637
655
  });
638
656
  }
639
- function performTargetedScan(targetDeviceId) {
657
+ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS) {
640
658
  return index.__awaiter(this, void 0, void 0, function* () {
641
659
  if (!noble) {
642
660
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
@@ -676,7 +694,7 @@ function performTargetedScan(targetDeviceId) {
676
694
  const timeoutId = setTimeout(() => {
677
695
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
678
696
  finish(null).catch(reject);
679
- }, NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS);
697
+ }, timeoutMs);
680
698
  nobleInstance.on('discover', onDiscover);
681
699
  nobleInstance.startScanning([], true, (error) => {
682
700
  if (error) {
@@ -1046,7 +1064,7 @@ function tryDirectConnectById(deviceId) {
1046
1064
  });
1047
1065
  }
1048
1066
  function connectDevice(deviceId, webContents) {
1049
- var _a, _b;
1067
+ var _a, _b, _c;
1050
1068
  return index.__awaiter(this, void 0, void 0, function* () {
1051
1069
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connect device request:', {
1052
1070
  deviceId,
@@ -1064,27 +1082,41 @@ function connectDevice(deviceId, webContents) {
1064
1082
  if (!noble) {
1065
1083
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
1066
1084
  }
1067
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device not cached, scanning for:', deviceId);
1068
- try {
1069
- peripheral = (_b = (yield performTargetedScan(deviceId))) !== null && _b !== void 0 ? _b : undefined;
1070
- }
1071
- catch (scanError) {
1072
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan failed, falling back to direct connect', {
1073
- deviceId,
1074
- error: scanError instanceof Error ? scanError.message : String(scanError),
1075
- });
1076
- }
1077
- if (!peripheral) {
1078
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device not advertising, attempting direct connect by id:', deviceId);
1079
- peripheral = yield tryDirectConnectById(deviceId);
1080
- if (peripheral) {
1081
- discoveredDevices.set(deviceId, peripheral);
1085
+ const byIdFirst = shouldConnectByIdFirst(deviceId);
1086
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Resolving device for cold connect', {
1087
+ deviceId,
1088
+ name: (_b = resolveBleName(deviceId)) !== null && _b !== void 0 ? _b : 'unknown',
1089
+ strategy: byIdFirst ? 'connect-by-id-first' : 'scan-first',
1090
+ });
1091
+ const scanForPeripheral = () => index.__awaiter(this, void 0, void 0, function* () {
1092
+ var _d;
1093
+ try {
1094
+ return (_d = (yield performTargetedScan(deviceId, BLE_COLD_CONNECT_SCAN_TIMEOUT_MS))) !== null && _d !== void 0 ? _d : undefined;
1082
1095
  }
1096
+ catch (scanError) {
1097
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan failed', {
1098
+ deviceId,
1099
+ error: scanError instanceof Error ? scanError.message : String(scanError),
1100
+ });
1101
+ return undefined;
1102
+ }
1103
+ });
1104
+ const connectById = () => index.__awaiter(this, void 0, void 0, function* () {
1105
+ const found = yield tryDirectConnectById(deviceId);
1106
+ if (found) {
1107
+ discoveredDevices.set(deviceId, found);
1108
+ }
1109
+ return found;
1110
+ });
1111
+ peripheral = byIdFirst ? yield connectById() : yield scanForPeripheral();
1112
+ if (!peripheral) {
1113
+ peripheral = byIdFirst ? yield scanForPeripheral() : yield connectById();
1083
1114
  }
1084
1115
  }
1085
1116
  if (!peripheral) {
1086
1117
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${deviceId} not found`);
1087
1118
  }
1119
+ rememberBleName(deviceId, (_c = peripheral.advertisement) === null || _c === void 0 ? void 0 : _c.localName);
1088
1120
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connecting to device:', deviceId);
1089
1121
  if (peripheral.state === 'connected') {
1090
1122
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device already connected, skipping connection step');
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AA+BA,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;AAwoDD,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":"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;AAksDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkMpE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-electron",
3
- "version": "1.2.0-alpha.163",
3
+ "version": "1.2.0-alpha.165",
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.0-alpha.163",
29
- "@onekeyfe/hd-shared": "1.2.0-alpha.163",
30
- "@onekeyfe/hd-transport": "1.2.0-alpha.163",
28
+ "@onekeyfe/hd-core": "1.2.0-alpha.165",
29
+ "@onekeyfe/hd-shared": "1.2.0-alpha.165",
30
+ "@onekeyfe/hd-transport": "1.2.0-alpha.165",
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": "afed1c82345fc277cadf49677ab8371e6c6f3f9a"
39
+ "gitHead": "dc82ee336f9dc638352195bebd22ee606fa3ef5c"
40
40
  }
@@ -16,6 +16,7 @@ import {
16
16
  createKnownBleUuidAliases,
17
17
  hasOnekeyCommunicationService,
18
18
  isOnekeyBluetoothDevice,
19
+ isPro2FamilyBleName,
19
20
  matchesKnownBleUuid,
20
21
  wait,
21
22
  } from '@onekeyfe/hd-shared';
@@ -790,6 +791,41 @@ async function transmitHexDataToDevice(
790
791
  }
791
792
 
792
793
  // Handle discovered device (for general enumeration only)
794
+ // A scan that finds nothing costs this much before the direct-connect
795
+ // fallback runs. Every advertisement in the 6.5.0 control logs arrived within
796
+ // 631ms, so this leaves ~2x headroom while keeping a miss cheap.
797
+ const BLE_COLD_CONNECT_SCAN_TIMEOUT_MS = 1500;
798
+
799
+ // Advertised names, kept for the life of the process: device caches are purged
800
+ // on every disconnect, but the family a device belongs to never changes and
801
+ // decides which connection strategy is safe for it.
802
+ const bleNamesById = new Map<string, string>();
803
+
804
+ function rememberBleName(deviceId: string, name?: string | null): void {
805
+ const trimmed = name?.trim();
806
+ if (trimmed) {
807
+ bleNamesById.set(deviceId, trimmed);
808
+ }
809
+ }
810
+
811
+ function resolveBleName(deviceId: string): string | undefined {
812
+ const live =
813
+ connectedDevices.get(deviceId)?.advertisement?.localName?.trim() ||
814
+ discoveredDevices.get(deviceId)?.advertisement?.localName?.trim();
815
+ return live || bleNamesById.get(deviceId);
816
+ }
817
+
818
+ /**
819
+ * Pro2/Neo connect by id first: they are unaffected by the stale-session
820
+ * problem and advertise under Find My names a OneKey-filtered scan cannot
821
+ * match. Everything else — Classic family, and any device whose name is not
822
+ * known yet — scans first, because connecting by id can resolve a session the
823
+ * device no longer serves (see setupConnectionAndDiscoverServices).
824
+ */
825
+ function shouldConnectByIdFirst(deviceId: string): boolean {
826
+ return isPro2FamilyBleName(resolveBleName(deviceId));
827
+ }
828
+
793
829
  function handleDeviceDiscovered(peripheral: Peripheral): void {
794
830
  // Only process OneKey candidates for general discovery. Avoid logging every
795
831
  // ambient BLE peripheral; it makes Pro2 debugging hard to read.
@@ -799,6 +835,7 @@ function handleDeviceDiscovered(peripheral: Peripheral): void {
799
835
 
800
836
  const isNewDevice = !discoveredDevices.has(peripheral.id);
801
837
  discoveredDevices.set(peripheral.id, peripheral);
838
+ rememberBleName(peripheral.id, peripheral.advertisement?.localName);
802
839
  if (isNewDevice) {
803
840
  logger?.debug('[NobleBLE] OneKey BLE device discovered', {
804
841
  deviceId: peripheral.id,
@@ -833,7 +870,10 @@ async function waitForNobleScanStop(nobleInstance: NobleModule): Promise<void> {
833
870
 
834
871
  // Perform targeted scan for a specific device ID
835
872
  // Uses self-contained local listener pattern - no global state needed
836
- async function performTargetedScan(targetDeviceId: string): Promise<Peripheral | null> {
873
+ async function performTargetedScan(
874
+ targetDeviceId: string,
875
+ timeoutMs: number = NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS
876
+ ): Promise<Peripheral | null> {
837
877
  if (!noble) {
838
878
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Noble not available');
839
879
  }
@@ -878,7 +918,7 @@ async function performTargetedScan(targetDeviceId: string): Promise<Peripheral |
878
918
  const timeoutId = setTimeout(() => {
879
919
  logger?.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
880
920
  finish(null).catch(reject);
881
- }, NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS);
921
+ }, timeoutMs);
882
922
 
883
923
  // Add local listener for this scan
884
924
  nobleInstance.on('discover', onDiscover);
@@ -1454,31 +1494,46 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1454
1494
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Noble not available');
1455
1495
  }
1456
1496
 
1457
- // Scan before connecting by id. A live advertisement proves the device
1458
- // holds no link and will open a fresh session, and it is how 6.5.0 reached
1459
- // every cold connect (control logs: found in ~52ms, 16/16 sessions
1460
- // answered within ~1s). Connecting by id resolves through the OS cache
1461
- // instead: on a Classic 1S that can hand back a session the device no
1462
- // longer serves, where the link comes up and GATT resolves from cache but
1463
- // the device answers no protocol traffic at all.
1464
- logger?.info('[NobleBLE] Device not cached, scanning for:', deviceId);
1465
- try {
1466
- peripheral = (await performTargetedScan(deviceId)) ?? undefined;
1467
- } catch (scanError) {
1468
- logger?.info('[NobleBLE] Targeted scan failed, falling back to direct connect', {
1469
- deviceId,
1470
- error: scanError instanceof Error ? scanError.message : String(scanError),
1471
- });
1472
- }
1497
+ // A live advertisement proves the device holds no link and will open a
1498
+ // fresh session; connecting by id resolves through the OS cache instead
1499
+ // and can hand back a session the device no longer serves (see
1500
+ // setupConnectionAndDiscoverServices). Scanning is also the faster of the
1501
+ // two when the device does advertise: ~96ms median against ~784ms for
1502
+ // connect-by-id across the field logs. Pro2/Neo keep connect-by-id first
1503
+ // because they are unaffected and may advertise under an unmatchable Find
1504
+ // My name.
1505
+ const byIdFirst = shouldConnectByIdFirst(deviceId);
1506
+ logger?.info('[NobleBLE] Resolving device for cold connect', {
1507
+ deviceId,
1508
+ name: resolveBleName(deviceId) ?? 'unknown',
1509
+ strategy: byIdFirst ? 'connect-by-id-first' : 'scan-first',
1510
+ });
1473
1511
 
1474
- if (!peripheral) {
1475
- // Not advertising: held by another host, or bonded and silent. Connect
1476
- // by id is then the only way in.
1477
- logger?.info('[NobleBLE] Device not advertising, attempting direct connect by id:', deviceId);
1478
- peripheral = await tryDirectConnectById(deviceId);
1479
- if (peripheral) {
1480
- discoveredDevices.set(deviceId, peripheral);
1512
+ const scanForPeripheral = async () => {
1513
+ try {
1514
+ return (await performTargetedScan(deviceId, BLE_COLD_CONNECT_SCAN_TIMEOUT_MS)) ?? undefined;
1515
+ } catch (scanError) {
1516
+ logger?.info('[NobleBLE] Targeted scan failed', {
1517
+ deviceId,
1518
+ error: scanError instanceof Error ? scanError.message : String(scanError),
1519
+ });
1520
+ return undefined;
1481
1521
  }
1522
+ };
1523
+
1524
+ const connectById = async () => {
1525
+ const found = await tryDirectConnectById(deviceId);
1526
+ if (found) {
1527
+ discoveredDevices.set(deviceId, found);
1528
+ }
1529
+ return found;
1530
+ };
1531
+
1532
+ peripheral = byIdFirst ? await connectById() : await scanForPeripheral();
1533
+ if (!peripheral) {
1534
+ // The preferred route came up empty: not advertising (held elsewhere, or
1535
+ // silent), or not reachable by id. Try the other one before giving up.
1536
+ peripheral = byIdFirst ? await scanForPeripheral() : await connectById();
1482
1537
  }
1483
1538
  }
1484
1539
 
@@ -1487,6 +1542,10 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
1487
1542
  throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device ${deviceId} not found`);
1488
1543
  }
1489
1544
 
1545
+ // Also covers the connect-by-id route, whose simulated discovery carries no
1546
+ // service UUIDs and therefore never reaches handleDeviceDiscovered.
1547
+ rememberBleName(deviceId, peripheral.advertisement?.localName);
1548
+
1490
1549
  logger?.info('[NobleBLE] Connecting to device:', deviceId);
1491
1550
 
1492
1551
  // Check if device is already connected