@onekeyfe/hd-transport-electron 1.2.2-alpha.100 → 1.2.2-alpha.101
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-packet-capacity.d.ts +2 -0
- package/dist/ble-packet-capacity.d.ts.map +1 -1
- package/dist/{index-b37d926c.js → index-d51c7da6.js} +1 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-e8b87173.js → noble-ble-handler-0b455c4f.js} +176 -82
- package/dist/noble-ble-handler.d.ts +8 -1
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/noble-ble-timeouts.d.ts +1 -1
- package/dist/noble-ble-timeouts.d.ts.map +1 -1
- package/dist/types/desktop-api.d.ts +11 -0
- package/dist/types/desktop-api.d.ts.map +1 -1
- package/dist/types/noble-extended.d.ts +1 -0
- package/dist/types/noble-extended.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/ble-packet-capacity.test.ts +8 -1
- package/src/__tests__/noble-ble-handler.test.ts +120 -70
- package/src/ble-packet-capacity.ts +14 -0
- package/src/index.ts +7 -1
- package/src/noble-ble-handler.ts +307 -105
- package/src/noble-ble-timeouts.ts +1 -1
- package/src/types/desktop-api.ts +13 -0
- package/src/types/noble-extended.ts +1 -0
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare function resolveNobleAttMtu(reportedMtu: number | null | undefined, platform?: NodeJS.Platform): number | undefined;
|
|
1
3
|
export declare function resolveBlePacketCapacity(mtu: number | null | undefined, maximumPacketCapacity: number, fallbackPacketCapacity: number): number;
|
|
2
4
|
//# sourceMappingURL=ble-packet-capacity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ble-packet-capacity.d.ts","sourceRoot":"","sources":["../src/ble-packet-capacity.ts"],"names":[],"mappings":"AAEA,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,qBAAqB,EAAE,MAAM,EAC7B,sBAAsB,EAAE,MAAM,GAC7B,MAAM,CAMR"}
|
|
1
|
+
{"version":3,"file":"ble-packet-capacity.d.ts","sourceRoot":"","sources":["../src/ble-packet-capacity.ts"],"names":[],"mappings":";AAEA,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,GAAG,SAAS,CASpB;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,qBAAqB,EAAE,MAAM,EAC7B,sBAAsB,EAAE,MAAM,GAC7B,MAAM,CAMR"}
|
|
@@ -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-
|
|
35
|
+
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-0b455c4f.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ interface NobleModule {
|
|
|
25
25
|
interface Logger {
|
|
26
26
|
info(message: string, ...args: any[]): void;
|
|
27
27
|
debug(message: string, ...args: any[]): void;
|
|
28
|
+
warn(message: string, ...args: any[]): void;
|
|
28
29
|
error(message: string, ...args: any[]): void;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -36,6 +37,17 @@ interface Logger {
|
|
|
36
37
|
interface NobleBleWriteOptions {
|
|
37
38
|
pacingDelayMs?: number;
|
|
38
39
|
}
|
|
40
|
+
type NobleBleIpcErrorPayload = {
|
|
41
|
+
name: string;
|
|
42
|
+
message: string;
|
|
43
|
+
errorCode: number;
|
|
44
|
+
params?: unknown;
|
|
45
|
+
};
|
|
46
|
+
type NobleBleIpcErrorResponse = {
|
|
47
|
+
type: 'NobleBleIpcError';
|
|
48
|
+
success: false;
|
|
49
|
+
error: NobleBleIpcErrorPayload;
|
|
50
|
+
};
|
|
39
51
|
interface NobleBleAPI {
|
|
40
52
|
enumerate: () => Promise<{
|
|
41
53
|
id: string;
|
|
@@ -81,4 +93,4 @@ interface DesktopAPI {
|
|
|
81
93
|
|
|
82
94
|
declare function initNobleBleSupport(webContents: WebContents): Promise<void>;
|
|
83
95
|
|
|
84
|
-
export { CharacteristicPair, DesktopAPI, DeviceInfo, Logger, NobleBleAPI, NobleBleWriteOptions, NobleModule, initNobleBleSupport };
|
|
96
|
+
export { CharacteristicPair, DesktopAPI, DeviceInfo, Logger, NobleBleAPI, NobleBleIpcErrorPayload, NobleBleIpcErrorResponse, NobleBleWriteOptions, NobleModule, initNobleBleSupport };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,cAAc,SAAS,CAAC;AAGxB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,cAAc,SAAS,CAAC;AAGxB,YAAY,EACV,UAAU,EACV,WAAW,EACX,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,WAAW,iBAGjE"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-d51c7da6.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -9,6 +9,15 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
9
|
var pRetry__default = /*#__PURE__*/_interopDefaultLegacy(pRetry);
|
|
10
10
|
|
|
11
11
|
const BLE_ATT_HEADER_BYTES = 3;
|
|
12
|
+
function resolveNobleAttMtu(reportedMtu, platform = process.platform) {
|
|
13
|
+
if (typeof reportedMtu !== 'number' || !Number.isFinite(reportedMtu) || reportedMtu <= 0) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const normalizedMtu = Math.floor(reportedMtu);
|
|
17
|
+
return platform === 'darwin' || platform === 'win32'
|
|
18
|
+
? normalizedMtu + BLE_ATT_HEADER_BYTES
|
|
19
|
+
: normalizedMtu;
|
|
20
|
+
}
|
|
12
21
|
function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapacity) {
|
|
13
22
|
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
14
23
|
return fallbackPacketCapacity;
|
|
@@ -87,10 +96,44 @@ function softRefreshSubscription(params) {
|
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
|
|
90
|
-
const
|
|
99
|
+
const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10000;
|
|
91
100
|
|
|
92
101
|
let noble = null;
|
|
93
102
|
let logger = null;
|
|
103
|
+
function createNobleBleConnectionError(error, messagePrefix = '') {
|
|
104
|
+
const errorMessage = error.message;
|
|
105
|
+
const isInvalidMacOsBond = error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain';
|
|
106
|
+
if (isInvalidMacOsBond) {
|
|
107
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
108
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
|
|
109
|
+
nativeErrorMessage,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
113
|
+
}
|
|
114
|
+
function createNobleBleIpcErrorResponse(error) {
|
|
115
|
+
const candidate = error;
|
|
116
|
+
const errorCode = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.errorCode) === 'number' ? candidate.errorCode : hdShared.HardwareErrorCode.UnknownError;
|
|
117
|
+
const message = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.message) === 'string' ? candidate.message : String(error !== null && error !== void 0 ? error : 'Unknown error');
|
|
118
|
+
const name = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.name) === 'string' ? candidate.name : 'Error';
|
|
119
|
+
let params;
|
|
120
|
+
if ((candidate === null || candidate === void 0 ? void 0 : candidate.params) !== undefined) {
|
|
121
|
+
try {
|
|
122
|
+
const serializedParams = JSON.stringify(candidate.params);
|
|
123
|
+
params = serializedParams === undefined ? undefined : JSON.parse(serializedParams);
|
|
124
|
+
}
|
|
125
|
+
catch (_a) {
|
|
126
|
+
params = undefined;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
type: 'NobleBleIpcError',
|
|
131
|
+
success: false,
|
|
132
|
+
error: Object.assign({ name,
|
|
133
|
+
message,
|
|
134
|
+
errorCode }, (params !== undefined ? { params } : {})),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
94
137
|
const bluetoothState = {
|
|
95
138
|
available: false,
|
|
96
139
|
unsupported: false,
|
|
@@ -116,7 +159,8 @@ const DEVICE_SCAN_TIMEOUT = 5000;
|
|
|
116
159
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
117
160
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
118
161
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
119
|
-
const
|
|
162
|
+
const BLE_DISCONNECT_CONFIRM_TIMEOUT_MS = 3000;
|
|
163
|
+
const BLE_IDLE_DISCONNECT_MS = 20000;
|
|
120
164
|
const BLE_BUSY_BACKSTOP_MS = 10 * 60000;
|
|
121
165
|
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
122
166
|
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
@@ -242,6 +286,7 @@ function initializeNoble() {
|
|
|
242
286
|
try {
|
|
243
287
|
noble = require('@stoprocent/noble');
|
|
244
288
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble library loaded');
|
|
289
|
+
setupPersistentStateListener();
|
|
245
290
|
yield new Promise((resolve, reject) => {
|
|
246
291
|
if (!noble) {
|
|
247
292
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not initialized'));
|
|
@@ -251,7 +296,6 @@ function initializeNoble() {
|
|
|
251
296
|
resolve();
|
|
252
297
|
return;
|
|
253
298
|
}
|
|
254
|
-
setupPersistentStateListener();
|
|
255
299
|
const timeout = setTimeout(() => {
|
|
256
300
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout'));
|
|
257
301
|
}, BLUETOOTH_INIT_TIMEOUT);
|
|
@@ -336,7 +380,14 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
|
|
|
336
380
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
337
381
|
const peripheral = connectedDevices.get(deviceId);
|
|
338
382
|
const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
339
|
-
const pending =
|
|
383
|
+
const pending = unsubscribeNotifications(deviceId)
|
|
384
|
+
.catch(error => {
|
|
385
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
386
|
+
deviceId,
|
|
387
|
+
error: error instanceof Error ? error.message : String(error),
|
|
388
|
+
});
|
|
389
|
+
})
|
|
390
|
+
.then(() => disconnectDevice(deviceId))
|
|
340
391
|
.then(() => {
|
|
341
392
|
broadcastToAllWebContents(hdShared.EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
342
393
|
id: deviceId,
|
|
@@ -409,6 +460,7 @@ function handleDeviceDisconnect(deviceId, webContents) {
|
|
|
409
460
|
});
|
|
410
461
|
cleanupDevice(deviceId, webContents, {
|
|
411
462
|
cleanupConnection: true,
|
|
463
|
+
cleanupDiscoveredCache: true,
|
|
412
464
|
sendDisconnectEvent: true,
|
|
413
465
|
cancelOperations: true,
|
|
414
466
|
reason: 'auto-disconnect',
|
|
@@ -432,13 +484,14 @@ function setupMtuListener(peripheral, deviceId, webContents) {
|
|
|
432
484
|
existing.peripheral.removeListener('mtu', existing.listener);
|
|
433
485
|
}
|
|
434
486
|
const listener = (mtu) => {
|
|
435
|
-
|
|
487
|
+
const normalizedMtu = resolveNobleAttMtu(mtu);
|
|
488
|
+
if (normalizedMtu === undefined)
|
|
436
489
|
return;
|
|
437
490
|
if (webContents.isDestroyed())
|
|
438
491
|
return;
|
|
439
492
|
webContents.send(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_MTU_CHANGED, {
|
|
440
493
|
id: deviceId,
|
|
441
|
-
mtu,
|
|
494
|
+
mtu: normalizedMtu,
|
|
442
495
|
});
|
|
443
496
|
};
|
|
444
497
|
deviceMtuListeners.set(deviceId, { peripheral, listener });
|
|
@@ -545,7 +598,7 @@ function transmitHexDataToDevice(deviceId, hexData, options) {
|
|
|
545
598
|
armIdleDisconnect(deviceId, BLE_BUSY_BACKSTOP_MS, 'busy-backstop');
|
|
546
599
|
const toBuffer = Buffer.from(hexData, 'hex');
|
|
547
600
|
const doGetWriteCharacteristic = () => { var _a; return (_a = deviceCharacteristics.get(deviceId)) === null || _a === void 0 ? void 0 : _a.write; };
|
|
548
|
-
const packetCapacity = resolveBlePacketCapacity(peripheral.mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
601
|
+
const packetCapacity = resolveBlePacketCapacity(resolveNobleAttMtu(peripheral.mtu), BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
549
602
|
const pacingDelayMs = resolveNobleBleWritePacingDelay(options);
|
|
550
603
|
if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
|
|
551
604
|
const writeCharacteristic = doGetWriteCharacteristic();
|
|
@@ -590,18 +643,37 @@ function transmitHexDataToDevice(deviceId, hexData, options) {
|
|
|
590
643
|
}
|
|
591
644
|
});
|
|
592
645
|
}
|
|
646
|
+
const BLE_COLD_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
647
|
+
const SERVICE_DISCOVERY_MAX_ATTEMPTS = 2;
|
|
648
|
+
const bleNamesById = new Map();
|
|
649
|
+
function rememberBleName(deviceId, name) {
|
|
650
|
+
const trimmed = name === null || name === void 0 ? void 0 : name.trim();
|
|
651
|
+
if (trimmed) {
|
|
652
|
+
bleNamesById.set(deviceId, trimmed);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function resolveBleName(deviceId) {
|
|
656
|
+
var _a, _b, _c, _d, _e, _f;
|
|
657
|
+
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()) ||
|
|
658
|
+
((_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());
|
|
659
|
+
return live || bleNamesById.get(deviceId);
|
|
660
|
+
}
|
|
661
|
+
function shouldConnectByIdFirst(deviceId) {
|
|
662
|
+
return hdShared.isPro2FamilyBleName(resolveBleName(deviceId));
|
|
663
|
+
}
|
|
593
664
|
function handleDeviceDiscovered(peripheral) {
|
|
594
|
-
var _a, _b;
|
|
665
|
+
var _a, _b, _c;
|
|
595
666
|
if (!isOneKeyPeripheral(peripheral)) {
|
|
596
667
|
return;
|
|
597
668
|
}
|
|
598
669
|
const isNewDevice = !discoveredDevices.has(peripheral.id);
|
|
599
670
|
discoveredDevices.set(peripheral.id, peripheral);
|
|
671
|
+
rememberBleName(peripheral.id, (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName);
|
|
600
672
|
if (isNewDevice) {
|
|
601
673
|
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] OneKey BLE device discovered', {
|
|
602
674
|
deviceId: peripheral.id,
|
|
603
|
-
name: ((
|
|
604
|
-
serviceUUIDs: ((
|
|
675
|
+
name: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName) || 'Unknown Device',
|
|
676
|
+
serviceUUIDs: ((_c = peripheral.advertisement) === null || _c === void 0 ? void 0 : _c.serviceUuids) || [],
|
|
605
677
|
});
|
|
606
678
|
}
|
|
607
679
|
}
|
|
@@ -627,7 +699,7 @@ function waitForNobleScanStop(nobleInstance) {
|
|
|
627
699
|
});
|
|
628
700
|
});
|
|
629
701
|
}
|
|
630
|
-
function performTargetedScan(targetDeviceId) {
|
|
702
|
+
function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS) {
|
|
631
703
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
632
704
|
if (!noble) {
|
|
633
705
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
|
|
@@ -667,7 +739,7 @@ function performTargetedScan(targetDeviceId) {
|
|
|
667
739
|
const timeoutId = setTimeout(() => {
|
|
668
740
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
|
|
669
741
|
finish(null).catch(reject);
|
|
670
|
-
},
|
|
742
|
+
}, timeoutMs);
|
|
671
743
|
nobleInstance.on('discover', onDiscover);
|
|
672
744
|
nobleInstance.startScanning([], true, (error) => {
|
|
673
745
|
if (error) {
|
|
@@ -763,12 +835,14 @@ function getDevice(deviceId) {
|
|
|
763
835
|
const peripheral = discoveredDevices.get(deviceId);
|
|
764
836
|
if (peripheral) {
|
|
765
837
|
const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
766
|
-
|
|
838
|
+
const mtu = resolveNobleAttMtu(peripheral.mtu);
|
|
839
|
+
return Object.assign({ commType: 'electron-ble', id: peripheral.id, name: deviceName, state: peripheral.state || 'disconnected' }, (mtu === undefined ? {} : { mtu }));
|
|
767
840
|
}
|
|
768
841
|
const connectedPeripheral = connectedDevices.get(deviceId);
|
|
769
842
|
if (connectedPeripheral) {
|
|
770
843
|
const deviceName = ((_b = connectedPeripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName) || 'Unknown Device';
|
|
771
|
-
|
|
844
|
+
const mtu = resolveNobleAttMtu(connectedPeripheral.mtu);
|
|
845
|
+
return Object.assign({ commType: 'electron-ble', id: connectedPeripheral.id, name: deviceName, state: connectedPeripheral.state || 'connected' }, (mtu === undefined ? {} : { mtu }));
|
|
772
846
|
}
|
|
773
847
|
return {
|
|
774
848
|
commType: 'electron-ble',
|
|
@@ -802,7 +876,7 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
802
876
|
});
|
|
803
877
|
const discoveryPromise = (() => index.__awaiter(this, void 0, void 0, function* () {
|
|
804
878
|
const services = yield new Promise((resolve, reject) => {
|
|
805
|
-
peripheral.discoverServices(
|
|
879
|
+
peripheral.discoverServices(ONEKEY_SERVICE_UUIDS, (error, svc) => {
|
|
806
880
|
if (error) {
|
|
807
881
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed:', error);
|
|
808
882
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, error.message));
|
|
@@ -813,7 +887,7 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
813
887
|
});
|
|
814
888
|
});
|
|
815
889
|
if (!services || services.length === 0) {
|
|
816
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No services found');
|
|
890
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No OneKey services found');
|
|
817
891
|
}
|
|
818
892
|
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] services discovered', {
|
|
819
893
|
deviceId: peripheral.id,
|
|
@@ -884,9 +958,14 @@ function forceReconnectPeripheral(peripheral, deviceId) {
|
|
|
884
958
|
callback();
|
|
885
959
|
}), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
|
|
886
960
|
}
|
|
887
|
-
yield
|
|
888
|
-
|
|
889
|
-
|
|
961
|
+
yield new Promise((resolve, reject) => {
|
|
962
|
+
peripheral.connect(error => {
|
|
963
|
+
if (error) {
|
|
964
|
+
reject(createNobleBleConnectionError(error));
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
resolve();
|
|
968
|
+
});
|
|
890
969
|
});
|
|
891
970
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
892
971
|
connectedDevices.set(deviceId, peripheral);
|
|
@@ -909,7 +988,7 @@ function freshScanAndDiscover(deviceId, webContents) {
|
|
|
909
988
|
yield new Promise((resolve, reject) => {
|
|
910
989
|
freshPeripheral.connect((error) => {
|
|
911
990
|
if (error) {
|
|
912
|
-
reject(
|
|
991
|
+
reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
|
|
913
992
|
}
|
|
914
993
|
else {
|
|
915
994
|
connectedDevices.set(deviceId, freshPeripheral);
|
|
@@ -930,11 +1009,11 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
930
1009
|
deviceId,
|
|
931
1010
|
peripheralState: peripheral.state,
|
|
932
1011
|
attempt: attemptNumber,
|
|
933
|
-
maxRetries:
|
|
1012
|
+
maxRetries: SERVICE_DISCOVERY_MAX_ATTEMPTS,
|
|
934
1013
|
targetUUIDs: ONEKEY_SERVICE_UUIDS,
|
|
935
1014
|
});
|
|
936
1015
|
if (attemptNumber > 1) {
|
|
937
|
-
logger === null || logger === void 0 ? void 0 : logger.info(`[NobleBLE] Service discovery retry attempt ${attemptNumber}
|
|
1016
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`[NobleBLE] Service discovery retry attempt ${attemptNumber}/${SERVICE_DISCOVERY_MAX_ATTEMPTS}`);
|
|
938
1017
|
}
|
|
939
1018
|
if (peripheral.state !== 'connected') {
|
|
940
1019
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Device not connected: ${peripheral.state}`);
|
|
@@ -943,16 +1022,16 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
943
1022
|
return yield discoverServicesAndCharacteristics(peripheral);
|
|
944
1023
|
}
|
|
945
1024
|
catch (error) {
|
|
946
|
-
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] No services found (attempt ${attemptNumber}
|
|
947
|
-
if (attemptNumber <
|
|
948
|
-
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] Will retry service discovery (attempt ${attemptNumber + 1}
|
|
1025
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] No services found (attempt ${attemptNumber}/${SERVICE_DISCOVERY_MAX_ATTEMPTS})`);
|
|
1026
|
+
if (attemptNumber < SERVICE_DISCOVERY_MAX_ATTEMPTS) {
|
|
1027
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] Will retry service discovery (attempt ${attemptNumber + 1}/${SERVICE_DISCOVERY_MAX_ATTEMPTS})`);
|
|
949
1028
|
}
|
|
950
1029
|
throw error;
|
|
951
1030
|
}
|
|
952
1031
|
}), {
|
|
953
|
-
retries:
|
|
1032
|
+
retries: SERVICE_DISCOVERY_MAX_ATTEMPTS - 1,
|
|
954
1033
|
factor: 1.5,
|
|
955
|
-
minTimeout:
|
|
1034
|
+
minTimeout: 500,
|
|
956
1035
|
maxTimeout: 3000,
|
|
957
1036
|
onFailedAttempt: error => {
|
|
958
1037
|
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] Service discovery attempt ${error.attemptNumber} failed:`, {
|
|
@@ -966,23 +1045,27 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
966
1045
|
}
|
|
967
1046
|
function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
968
1047
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
969
|
-
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
970
1048
|
try {
|
|
971
|
-
|
|
1049
|
+
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
972
1050
|
}
|
|
973
|
-
catch (
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1051
|
+
catch (resetError) {
|
|
1052
|
+
if (hdShared.isBleStaleBondHardwareError(resetError)) {
|
|
1053
|
+
throw resetError;
|
|
1054
|
+
}
|
|
1055
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
|
|
978
1056
|
}
|
|
979
|
-
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
980
1057
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
981
1058
|
try {
|
|
982
1059
|
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
983
1060
|
}
|
|
984
|
-
catch (
|
|
985
|
-
|
|
1061
|
+
catch (discoveryError) {
|
|
1062
|
+
if (peripheral.state === 'connected') {
|
|
1063
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed on a live link, dropping it before the fresh scan', discoveryError);
|
|
1064
|
+
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1065
|
+
}
|
|
1066
|
+
else {
|
|
1067
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed, attempting fresh scan...', discoveryError);
|
|
1068
|
+
}
|
|
986
1069
|
return freshScanAndDiscover(deviceId, webContents);
|
|
987
1070
|
}
|
|
988
1071
|
});
|
|
@@ -1042,7 +1125,7 @@ function tryDirectConnectById(deviceId) {
|
|
|
1042
1125
|
});
|
|
1043
1126
|
}
|
|
1044
1127
|
function connectDevice(deviceId, webContents) {
|
|
1045
|
-
var _a;
|
|
1128
|
+
var _a, _b, _c;
|
|
1046
1129
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
1047
1130
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connect device request:', {
|
|
1048
1131
|
deviceId,
|
|
@@ -1054,34 +1137,47 @@ function connectDevice(deviceId, webContents) {
|
|
|
1054
1137
|
});
|
|
1055
1138
|
let peripheral = (_a = discoveredDevices.get(deviceId)) !== null && _a !== void 0 ? _a : connectedDevices.get(deviceId);
|
|
1056
1139
|
if (!peripheral) {
|
|
1057
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device not discovered, attempting targeted scan for:', deviceId);
|
|
1058
1140
|
if (!noble) {
|
|
1059
1141
|
yield initializeNoble();
|
|
1060
1142
|
}
|
|
1061
1143
|
if (!noble) {
|
|
1062
1144
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
|
|
1063
1145
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1146
|
+
const byIdFirst = shouldConnectByIdFirst(deviceId);
|
|
1147
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Resolving device for cold connect', {
|
|
1148
|
+
deviceId,
|
|
1149
|
+
name: (_b = resolveBleName(deviceId)) !== null && _b !== void 0 ? _b : 'unknown',
|
|
1150
|
+
strategy: byIdFirst ? 'connect-by-id-first' : 'scan-first',
|
|
1151
|
+
});
|
|
1152
|
+
const scanForPeripheral = () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1153
|
+
var _d;
|
|
1154
|
+
try {
|
|
1155
|
+
return (_d = (yield performTargetedScan(deviceId, BLE_COLD_CONNECT_SCAN_TIMEOUT_MS))) !== null && _d !== void 0 ? _d : undefined;
|
|
1074
1156
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1157
|
+
catch (scanError) {
|
|
1158
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan failed', {
|
|
1159
|
+
deviceId,
|
|
1160
|
+
error: scanError instanceof Error ? scanError.message : String(scanError),
|
|
1161
|
+
});
|
|
1162
|
+
return undefined;
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
const connectById = () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1166
|
+
const found = yield tryDirectConnectById(deviceId);
|
|
1167
|
+
if (found) {
|
|
1168
|
+
discoveredDevices.set(deviceId, found);
|
|
1169
|
+
}
|
|
1170
|
+
return found;
|
|
1171
|
+
});
|
|
1172
|
+
peripheral = byIdFirst ? yield connectById() : yield scanForPeripheral();
|
|
1173
|
+
if (!peripheral) {
|
|
1174
|
+
peripheral = byIdFirst ? yield scanForPeripheral() : yield connectById();
|
|
1080
1175
|
}
|
|
1081
1176
|
}
|
|
1082
1177
|
if (!peripheral) {
|
|
1083
1178
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${deviceId} not found`);
|
|
1084
1179
|
}
|
|
1180
|
+
rememberBleName(deviceId, (_c = peripheral.advertisement) === null || _c === void 0 ? void 0 : _c.localName);
|
|
1085
1181
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connecting to device:', deviceId);
|
|
1086
1182
|
if (peripheral.state === 'connected') {
|
|
1087
1183
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device already connected, skipping connection step');
|
|
@@ -1123,27 +1219,11 @@ function connectDevice(deviceId, webContents) {
|
|
|
1123
1219
|
return;
|
|
1124
1220
|
}
|
|
1125
1221
|
return new Promise((resolve, reject) => {
|
|
1126
|
-
let connectionTimedOut = false;
|
|
1127
|
-
const timeout = setTimeout(() => {
|
|
1128
|
-
connectionTimedOut = true;
|
|
1129
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
1130
|
-
}, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
1131
1222
|
const connectedPeripheral = peripheral;
|
|
1132
1223
|
connectedPeripheral.connect((error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1133
|
-
clearTimeout(timeout);
|
|
1134
|
-
if (connectionTimedOut) {
|
|
1135
|
-
if (!error) {
|
|
1136
|
-
try {
|
|
1137
|
-
connectedPeripheral.disconnect(() => undefined);
|
|
1138
|
-
}
|
|
1139
|
-
catch (_a) {
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
return;
|
|
1143
|
-
}
|
|
1144
1224
|
if (error) {
|
|
1145
1225
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
|
|
1146
|
-
reject(
|
|
1226
|
+
reject(createNobleBleConnectionError(error));
|
|
1147
1227
|
return;
|
|
1148
1228
|
}
|
|
1149
1229
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connected to device:', deviceId);
|
|
@@ -1156,9 +1236,9 @@ function connectDevice(deviceId, webContents) {
|
|
|
1156
1236
|
}
|
|
1157
1237
|
catch (setupError) {
|
|
1158
1238
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection setup failed:', setupError);
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1239
|
+
disconnectDevice(deviceId)
|
|
1240
|
+
.catch(() => undefined)
|
|
1241
|
+
.then(() => reject(setupError));
|
|
1162
1242
|
}
|
|
1163
1243
|
}));
|
|
1164
1244
|
});
|
|
@@ -1176,11 +1256,15 @@ function disconnectDevice(deviceId) {
|
|
|
1176
1256
|
deviceDisconnectListeners.delete(deviceId);
|
|
1177
1257
|
}
|
|
1178
1258
|
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1179
|
-
timeoutMs:
|
|
1259
|
+
timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
|
|
1180
1260
|
timeoutBehavior: 'resolve',
|
|
1181
1261
|
});
|
|
1262
|
+
if (peripheral.state === 'connected') {
|
|
1263
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1264
|
+
}
|
|
1182
1265
|
cleanupDevice(deviceId, undefined, {
|
|
1183
1266
|
cleanupConnection: true,
|
|
1267
|
+
cleanupDiscoveredCache: true,
|
|
1184
1268
|
sendDisconnectEvent: false,
|
|
1185
1269
|
cancelOperations: true,
|
|
1186
1270
|
reason: 'manual-disconnect',
|
|
@@ -1259,7 +1343,7 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1259
1343
|
timeoutBehavior: 'resolve',
|
|
1260
1344
|
});
|
|
1261
1345
|
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1262
|
-
timeoutMs:
|
|
1346
|
+
timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
1263
1347
|
timeoutBehavior: 'reject',
|
|
1264
1348
|
});
|
|
1265
1349
|
notifyCharacteristic.on('data', (data) => {
|
|
@@ -1271,9 +1355,14 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1271
1355
|
});
|
|
1272
1356
|
});
|
|
1273
1357
|
}
|
|
1358
|
+
const subscribeStartedAt = Date.now();
|
|
1274
1359
|
try {
|
|
1275
1360
|
yield rebuildAppSubscription(deviceId, notifyCharacteristic);
|
|
1276
1361
|
subscribedDevices.set(deviceId, true);
|
|
1362
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification subscription active', {
|
|
1363
|
+
deviceId,
|
|
1364
|
+
ms: Date.now() - subscribeStartedAt,
|
|
1365
|
+
});
|
|
1277
1366
|
}
|
|
1278
1367
|
finally {
|
|
1279
1368
|
subscriptionOperations.set(deviceId, 'idle');
|
|
@@ -1286,7 +1375,14 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1286
1375
|
const { ipcMain } = require('electron');
|
|
1287
1376
|
const handle = (channel, listener) => {
|
|
1288
1377
|
ipcMain.removeHandler(channel);
|
|
1289
|
-
ipcMain.handle(channel,
|
|
1378
|
+
ipcMain.handle(channel, (...args) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1379
|
+
try {
|
|
1380
|
+
return yield Promise.resolve(listener(...args));
|
|
1381
|
+
}
|
|
1382
|
+
catch (error) {
|
|
1383
|
+
return createNobleBleIpcErrorResponse(error);
|
|
1384
|
+
}
|
|
1385
|
+
}));
|
|
1290
1386
|
};
|
|
1291
1387
|
safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
|
|
1292
1388
|
handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1391,10 +1487,6 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1391
1487
|
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1392
1488
|
}
|
|
1393
1489
|
yield stopScanning().catch(() => undefined);
|
|
1394
|
-
if (noble && persistentStateListener) {
|
|
1395
|
-
noble.removeListener('stateChange', persistentStateListener);
|
|
1396
|
-
persistentStateListener = null;
|
|
1397
|
-
}
|
|
1398
1490
|
cleanupNobleListeners();
|
|
1399
1491
|
discoveredDevices.clear();
|
|
1400
1492
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
|
@@ -1410,5 +1502,7 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1410
1502
|
}
|
|
1411
1503
|
}
|
|
1412
1504
|
|
|
1505
|
+
exports.createNobleBleConnectionError = createNobleBleConnectionError;
|
|
1506
|
+
exports.createNobleBleIpcErrorResponse = createNobleBleIpcErrorResponse;
|
|
1413
1507
|
exports.resolveNobleBleWritePacingDelay = resolveNobleBleWritePacingDelay;
|
|
1414
1508
|
exports.setupNobleBleHandlers = setupNobleBleHandlers;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { WebContents } from 'electron';
|
|
2
|
-
import type { NobleBleWriteOptions } from './types/desktop-api';
|
|
2
|
+
import type { NobleBleIpcErrorResponse, NobleBleWriteOptions } from './types/desktop-api';
|
|
3
|
+
type NobleBleNativeError = Error & {
|
|
4
|
+
nativeErrorCode?: number;
|
|
5
|
+
nativeErrorDomain?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function createNobleBleConnectionError(error: NobleBleNativeError, messagePrefix?: string): import("@onekeyfe/hd-shared").HardwareError;
|
|
8
|
+
export declare function createNobleBleIpcErrorResponse(error: unknown): NobleBleIpcErrorResponse;
|
|
3
9
|
export declare function resolveNobleBleWritePacingDelay(options?: NobleBleWriteOptions): number;
|
|
4
10
|
export declare function setupNobleBleHandlers(webContents: WebContents): void;
|
|
11
|
+
export {};
|
|
5
12
|
//# sourceMappingURL=noble-ble-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAO1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAgB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+ED,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAuuDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAwMpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM
|
|
1
|
+
{"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,8BAA8B,QAAS,CAAC"}
|
|
@@ -2,6 +2,17 @@ import type { EBleDisconnectReason } from '@onekeyfe/hd-shared';
|
|
|
2
2
|
export interface NobleBleWriteOptions {
|
|
3
3
|
pacingDelayMs?: number;
|
|
4
4
|
}
|
|
5
|
+
export type NobleBleIpcErrorPayload = {
|
|
6
|
+
name: string;
|
|
7
|
+
message: string;
|
|
8
|
+
errorCode: number;
|
|
9
|
+
params?: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type NobleBleIpcErrorResponse = {
|
|
12
|
+
type: 'NobleBleIpcError';
|
|
13
|
+
success: false;
|
|
14
|
+
error: NobleBleIpcErrorPayload;
|
|
15
|
+
};
|
|
5
16
|
export interface NobleBleAPI {
|
|
6
17
|
enumerate: () => Promise<{
|
|
7
18
|
id: string;
|