@onekeyfe/hd-transport-electron 1.2.0-alpha.153 → 1.2.0-alpha.155
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/{index-c28cc24a.js → index-b37d926c.js} +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-78adadea.js → noble-ble-handler-e8b87173.js} +11 -18
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/types/desktop-api.d.ts +2 -0
- package/dist/types/desktop-api.d.ts.map +1 -1
- package/dist/types/noble-extended.d.ts +0 -1
- package/dist/types/noble-extended.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/noble-ble-handler.ts +23 -41
- package/src/types/desktop-api.ts +11 -1
- package/src/types/noble-extended.ts +0 -1
|
@@ -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-e8b87173.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebContents } from 'electron';
|
|
2
2
|
import { Characteristic, Peripheral } from '@stoprocent/noble';
|
|
3
3
|
import { OneKeyDeviceInfoBase } from '@onekeyfe/hd-transport';
|
|
4
|
+
import { EBleDisconnectReason } from '@onekeyfe/hd-shared';
|
|
4
5
|
|
|
5
6
|
interface DeviceInfo extends OneKeyDeviceInfoBase {
|
|
6
7
|
id: string;
|
|
@@ -24,7 +25,6 @@ interface NobleModule {
|
|
|
24
25
|
interface Logger {
|
|
25
26
|
info(message: string, ...args: any[]): void;
|
|
26
27
|
debug(message: string, ...args: any[]): void;
|
|
27
|
-
warn(message: string, ...args: any[]): void;
|
|
28
28
|
error(message: string, ...args: any[]): void;
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -32,6 +32,7 @@ interface Logger {
|
|
|
32
32
|
* Desktop API types for Electron preload script
|
|
33
33
|
* These types define the core interface for Noble BLE communication
|
|
34
34
|
*/
|
|
35
|
+
|
|
35
36
|
interface NobleBleWriteOptions {
|
|
36
37
|
pacingDelayMs?: number;
|
|
37
38
|
}
|
|
@@ -56,9 +57,16 @@ interface NobleBleAPI {
|
|
|
56
57
|
id: string;
|
|
57
58
|
mtu: number;
|
|
58
59
|
}) => void) => () => void;
|
|
60
|
+
/**
|
|
61
|
+
* Fires whenever a BLE link drops. `reason` distinguishes a real peripheral
|
|
62
|
+
* drop from the main process freeing an idle link on its keep-alive timer;
|
|
63
|
+
* it is optional so an older host bridge that omits it still type-checks
|
|
64
|
+
* (absent is treated as a real drop by consumers).
|
|
65
|
+
*/
|
|
59
66
|
onDeviceDisconnected: (callback: (device: {
|
|
60
67
|
id: string;
|
|
61
68
|
name: string;
|
|
69
|
+
reason?: EBleDisconnectReason;
|
|
62
70
|
}) => void) => () => void;
|
|
63
71
|
checkAvailability: () => Promise<{
|
|
64
72
|
available: boolean;
|
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-b37d926c.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -116,7 +116,6 @@ const DEVICE_SCAN_TIMEOUT = 5000;
|
|
|
116
116
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
117
117
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
118
118
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
119
|
-
const BLE_DISCONNECT_CONFIRM_TIMEOUT_MS = 3000;
|
|
120
119
|
const BLE_IDLE_DISCONNECT_MS = 3 * 60000;
|
|
121
120
|
const BLE_BUSY_BACKSTOP_MS = 10 * 60000;
|
|
122
121
|
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
@@ -243,7 +242,6 @@ function initializeNoble() {
|
|
|
243
242
|
try {
|
|
244
243
|
noble = require('@stoprocent/noble');
|
|
245
244
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble library loaded');
|
|
246
|
-
setupPersistentStateListener();
|
|
247
245
|
yield new Promise((resolve, reject) => {
|
|
248
246
|
if (!noble) {
|
|
249
247
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not initialized'));
|
|
@@ -253,6 +251,7 @@ function initializeNoble() {
|
|
|
253
251
|
resolve();
|
|
254
252
|
return;
|
|
255
253
|
}
|
|
254
|
+
setupPersistentStateListener();
|
|
256
255
|
const timeout = setTimeout(() => {
|
|
257
256
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout'));
|
|
258
257
|
}, BLUETOOTH_INIT_TIMEOUT);
|
|
@@ -337,18 +336,12 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
|
|
|
337
336
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
338
337
|
const peripheral = connectedDevices.get(deviceId);
|
|
339
338
|
const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
340
|
-
const pending =
|
|
341
|
-
.catch(error => {
|
|
342
|
-
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
343
|
-
deviceId,
|
|
344
|
-
error: error instanceof Error ? error.message : String(error),
|
|
345
|
-
});
|
|
346
|
-
})
|
|
347
|
-
.then(() => disconnectDevice(deviceId))
|
|
339
|
+
const pending = disconnectDevice(deviceId)
|
|
348
340
|
.then(() => {
|
|
349
341
|
broadcastToAllWebContents(hdShared.EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
350
342
|
id: deviceId,
|
|
351
343
|
name: deviceName,
|
|
344
|
+
reason: hdShared.EBleDisconnectReason.IdleKeepAlive,
|
|
352
345
|
});
|
|
353
346
|
})
|
|
354
347
|
.catch(error => {
|
|
@@ -364,7 +357,7 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
|
|
|
364
357
|
}
|
|
365
358
|
function cleanupDevice(deviceId, webContents, options = {}) {
|
|
366
359
|
var _a;
|
|
367
|
-
const { cleanupConnection = true, cleanupDiscoveredCache = false, sendDisconnectEvent = false, cancelOperations = true, reason = 'unknown', } = options;
|
|
360
|
+
const { cleanupConnection = true, cleanupDiscoveredCache = false, sendDisconnectEvent = false, cancelOperations = true, reason = 'unknown', disconnectReason = hdShared.EBleDisconnectReason.DeviceDisconnected, } = options;
|
|
368
361
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting device cleanup', {
|
|
369
362
|
deviceId,
|
|
370
363
|
reason,
|
|
@@ -401,6 +394,7 @@ function cleanupDevice(deviceId, webContents, options = {}) {
|
|
|
401
394
|
broadcastToAllWebContents(hdShared.EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
402
395
|
id: deviceId,
|
|
403
396
|
name: deviceName,
|
|
397
|
+
reason: disconnectReason,
|
|
404
398
|
});
|
|
405
399
|
}
|
|
406
400
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device cleanup completed', { deviceId, reason });
|
|
@@ -415,7 +409,6 @@ function handleDeviceDisconnect(deviceId, webContents) {
|
|
|
415
409
|
});
|
|
416
410
|
cleanupDevice(deviceId, webContents, {
|
|
417
411
|
cleanupConnection: true,
|
|
418
|
-
cleanupDiscoveredCache: true,
|
|
419
412
|
sendDisconnectEvent: true,
|
|
420
413
|
cancelOperations: true,
|
|
421
414
|
reason: 'auto-disconnect',
|
|
@@ -1183,15 +1176,11 @@ function disconnectDevice(deviceId) {
|
|
|
1183
1176
|
deviceDisconnectListeners.delete(deviceId);
|
|
1184
1177
|
}
|
|
1185
1178
|
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1186
|
-
timeoutMs:
|
|
1179
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1187
1180
|
timeoutBehavior: 'resolve',
|
|
1188
1181
|
});
|
|
1189
|
-
if (peripheral.state === 'connected') {
|
|
1190
|
-
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1191
|
-
}
|
|
1192
1182
|
cleanupDevice(deviceId, undefined, {
|
|
1193
1183
|
cleanupConnection: true,
|
|
1194
|
-
cleanupDiscoveredCache: true,
|
|
1195
1184
|
sendDisconnectEvent: false,
|
|
1196
1185
|
cancelOperations: true,
|
|
1197
1186
|
reason: 'manual-disconnect',
|
|
@@ -1402,6 +1391,10 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1402
1391
|
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1403
1392
|
}
|
|
1404
1393
|
yield stopScanning().catch(() => undefined);
|
|
1394
|
+
if (noble && persistentStateListener) {
|
|
1395
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1396
|
+
persistentStateListener = null;
|
|
1397
|
+
}
|
|
1405
1398
|
cleanupNobleListeners();
|
|
1406
1399
|
discoveredDevices.clear();
|
|
1407
1400
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
|
@@ -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":"AA+BA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AA0EhE,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AA2mDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAgMpE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EBleDisconnectReason } from '@onekeyfe/hd-shared';
|
|
1
2
|
export interface NobleBleWriteOptions {
|
|
2
3
|
pacingDelayMs?: number;
|
|
3
4
|
}
|
|
@@ -25,6 +26,7 @@ export interface NobleBleAPI {
|
|
|
25
26
|
onDeviceDisconnected: (callback: (device: {
|
|
26
27
|
id: string;
|
|
27
28
|
name: string;
|
|
29
|
+
reason?: EBleDisconnectReason;
|
|
28
30
|
}) => void) => () => void;
|
|
29
31
|
checkAvailability: () => Promise<{
|
|
30
32
|
available: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desktop-api.d.ts","sourceRoot":"","sources":["../../src/types/desktop-api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"desktop-api.d.ts","sourceRoot":"","sources":["../../src/types/desktop-api.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;IACzD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACxF,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGzC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACnF,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAOvF,oBAAoB,EAAE,CACpB,QAAQ,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,oBAAoB,CAAA;KAAE,KAAK,IAAI,KACpF,MAAM,IAAI,CAAC;IAChB,iBAAiB,EAAE,MAAM,OAAO,CAAC;QAC/B,SAAS,EAAE,OAAO,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC,CAAC;CACJ;AAGD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB"}
|
|
@@ -22,7 +22,6 @@ export interface NobleModule {
|
|
|
22
22
|
export interface Logger {
|
|
23
23
|
info(message: string, ...args: any[]): void;
|
|
24
24
|
debug(message: string, ...args: any[]): void;
|
|
25
|
-
warn(message: string, ...args: any[]): void;
|
|
26
25
|
error(message: string, ...args: any[]): void;
|
|
27
26
|
}
|
|
28
27
|
export declare function safeLog(logger: Logger | null, level: 'info' | 'debug' | 'error', message: string, ...args: any[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,
|
|
1
|
+
{"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9C;AAGD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,IAAI,CAMN"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-electron",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.155",
|
|
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.
|
|
29
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
30
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.155",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.155",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.155",
|
|
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": "
|
|
39
|
+
"gitHead": "922cb4e29b2d89511c9b67c25840294335cb8005"
|
|
40
40
|
}
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-var-requires, import/no-extraneous-dependencies */
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
+
EBleDisconnectReason,
|
|
9
10
|
EOneKeyBleMessageKeys,
|
|
10
11
|
ERRORS,
|
|
11
12
|
HardwareErrorCode,
|
|
@@ -89,10 +90,6 @@ const DEVICE_SCAN_TIMEOUT = 5000; // 5 seconds for device scanning
|
|
|
89
90
|
const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks
|
|
90
91
|
const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
|
|
91
92
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
92
|
-
// A physical teardown must actually reach the OS before the device can return
|
|
93
|
-
// to a clean state; 250ms routinely declared success while CoreBluetooth was
|
|
94
|
-
// still disconnecting, leaving no trace when the teardown never completed.
|
|
95
|
-
const BLE_DISCONNECT_CONFIRM_TIMEOUT_MS = 3000;
|
|
96
93
|
// Renderer release is logical only; this timer physically frees the device.
|
|
97
94
|
const BLE_IDLE_DISCONNECT_MS = 3 * 60_000;
|
|
98
95
|
// Ceiling while a call is in flight: no outstanding write, but not forever.
|
|
@@ -260,11 +257,6 @@ async function initializeNoble(): Promise<void> {
|
|
|
260
257
|
noble = require('@stoprocent/noble') as NobleModule;
|
|
261
258
|
logger?.info('[NobleBLE] Noble library loaded');
|
|
262
259
|
|
|
263
|
-
// Register the process-lifetime state listener before any early return:
|
|
264
|
-
// the poweredOn fast path below would otherwise skip it for the whole
|
|
265
|
-
// session, leaving poweredOff cache/state reconciliation dead.
|
|
266
|
-
setupPersistentStateListener();
|
|
267
|
-
|
|
268
260
|
// Wait for Bluetooth to be ready
|
|
269
261
|
await new Promise<void>((resolve, reject) => {
|
|
270
262
|
if (!noble) {
|
|
@@ -277,6 +269,9 @@ async function initializeNoble(): Promise<void> {
|
|
|
277
269
|
return;
|
|
278
270
|
}
|
|
279
271
|
|
|
272
|
+
// Setup persistent state listener before initialization
|
|
273
|
+
setupPersistentStateListener();
|
|
274
|
+
|
|
280
275
|
const timeout = setTimeout(() => {
|
|
281
276
|
reject(
|
|
282
277
|
ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout')
|
|
@@ -342,6 +337,12 @@ interface DeviceCleanupOptions {
|
|
|
342
337
|
cleanupDiscoveredCache?: boolean;
|
|
343
338
|
/** Whether to send disconnect event */
|
|
344
339
|
sendDisconnectEvent?: boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Why the link went down, forwarded to renderers on BLE_DEVICE_DISCONNECTED.
|
|
342
|
+
* Defaults to a real peripheral drop; the keep-alive path overrides it so
|
|
343
|
+
* consumers can tell an internal idle release from a device that left.
|
|
344
|
+
*/
|
|
345
|
+
disconnectReason?: EBleDisconnectReason;
|
|
345
346
|
/** Whether to cancel ongoing operations */
|
|
346
347
|
cancelOperations?: boolean;
|
|
347
348
|
/** Cleanup reason (for logging) */
|
|
@@ -397,26 +398,17 @@ function armIdleDisconnect(
|
|
|
397
398
|
logger?.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
398
399
|
const peripheral = connectedDevices.get(deviceId);
|
|
399
400
|
const deviceName = peripheral?.advertisement?.localName || 'Unknown Device';
|
|
400
|
-
|
|
401
|
-
// teardown path: the 1S leaves its notify session half-open when the
|
|
402
|
-
// link drops without an unsubscribe and then ignores application
|
|
403
|
-
// protocol traffic on NEW links for tens of minutes (field log
|
|
404
|
-
// 2026-08-19: the lone unsubscribe-skipping idle teardown caused a
|
|
405
|
-
// 6-attempt reconnect loop; unsubscribe-first teardowns reconnected
|
|
406
|
-
// instantly).
|
|
407
|
-
const pending = unsubscribeNotifications(deviceId)
|
|
408
|
-
.catch(error => {
|
|
409
|
-
logger?.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
410
|
-
deviceId,
|
|
411
|
-
error: error instanceof Error ? error.message : String(error),
|
|
412
|
-
});
|
|
413
|
-
})
|
|
414
|
-
.then(() => disconnectDevice(deviceId))
|
|
401
|
+
const pending = disconnectDevice(deviceId)
|
|
415
402
|
.then(() => {
|
|
416
403
|
// A call is still in flight here; it must reject, not hang.
|
|
404
|
+
// Both 'idle' and 'busy-backstop' report IdleKeepAlive on purpose:
|
|
405
|
+
// we reclaimed the link ourselves and have no evidence the device
|
|
406
|
+
// left, so consumers must not mark it disconnected. The in-flight
|
|
407
|
+
// call still fails, via the renderer dropping its device state.
|
|
417
408
|
broadcastToAllWebContents(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
418
409
|
id: deviceId,
|
|
419
410
|
name: deviceName,
|
|
411
|
+
reason: EBleDisconnectReason.IdleKeepAlive,
|
|
420
412
|
});
|
|
421
413
|
})
|
|
422
414
|
.catch(error => {
|
|
@@ -446,6 +438,7 @@ function cleanupDevice(
|
|
|
446
438
|
sendDisconnectEvent = false,
|
|
447
439
|
cancelOperations = true,
|
|
448
440
|
reason = 'unknown',
|
|
441
|
+
disconnectReason = EBleDisconnectReason.DeviceDisconnected,
|
|
449
442
|
} = options;
|
|
450
443
|
|
|
451
444
|
logger?.info('[NobleBLE] Starting device cleanup', {
|
|
@@ -495,6 +488,7 @@ function cleanupDevice(
|
|
|
495
488
|
broadcastToAllWebContents(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
496
489
|
id: deviceId,
|
|
497
490
|
name: deviceName,
|
|
491
|
+
reason: disconnectReason,
|
|
498
492
|
});
|
|
499
493
|
}
|
|
500
494
|
|
|
@@ -514,9 +508,6 @@ function handleDeviceDisconnect(deviceId: string, webContents: WebContents): voi
|
|
|
514
508
|
|
|
515
509
|
cleanupDevice(deviceId, webContents, {
|
|
516
510
|
cleanupConnection: true,
|
|
517
|
-
// Same stale-object hazard as manual disconnect: an externally dropped
|
|
518
|
-
// link invalidates the cached peripheral for the next reconnect.
|
|
519
|
-
cleanupDiscoveredCache: true,
|
|
520
511
|
sendDisconnectEvent: true,
|
|
521
512
|
cancelOperations: true,
|
|
522
513
|
reason: 'auto-disconnect',
|
|
@@ -1606,18 +1597,11 @@ async function disconnectDevice(deviceId: string): Promise<void> {
|
|
|
1606
1597
|
}
|
|
1607
1598
|
|
|
1608
1599
|
await runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1609
|
-
timeoutMs:
|
|
1600
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1610
1601
|
timeoutBehavior: 'resolve',
|
|
1611
1602
|
});
|
|
1612
|
-
if (peripheral.state === 'connected') {
|
|
1613
|
-
logger?.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1614
|
-
}
|
|
1615
1603
|
cleanupDevice(deviceId, undefined, {
|
|
1616
1604
|
cleanupConnection: true,
|
|
1617
|
-
// macOS returns zero GATT services when a previously-disconnected
|
|
1618
|
-
// peripheral object is reconnected; drop the discovery cache so the next
|
|
1619
|
-
// connect resolves a fresh peripheral (direct connect by id, or scan).
|
|
1620
|
-
cleanupDiscoveredCache: true,
|
|
1621
1605
|
sendDisconnectEvent: false,
|
|
1622
1606
|
cancelOperations: true,
|
|
1623
1607
|
reason: 'manual-disconnect',
|
|
@@ -1943,12 +1927,10 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
|
|
|
1943
1927
|
}
|
|
1944
1928
|
|
|
1945
1929
|
await stopScanning().catch(() => undefined);
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
// initializeNoble early-returns once noble is loaded). The null-guard
|
|
1951
|
-
// in setupPersistentStateListener keeps it deduped to one instance.
|
|
1930
|
+
if (noble && persistentStateListener) {
|
|
1931
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1932
|
+
persistentStateListener = null;
|
|
1933
|
+
}
|
|
1952
1934
|
cleanupNobleListeners();
|
|
1953
1935
|
discoveredDevices.clear();
|
|
1954
1936
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
package/src/types/desktop-api.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* These types define the core interface for Noble BLE communication
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { EBleDisconnectReason } from '@onekeyfe/hd-shared';
|
|
7
|
+
|
|
6
8
|
// Noble BLE API interface - core BLE functionality
|
|
7
9
|
export interface NobleBleWriteOptions {
|
|
8
10
|
pacingDelayMs?: number;
|
|
@@ -21,7 +23,15 @@ export interface NobleBleAPI {
|
|
|
21
23
|
write: (uuid: string, data: string, options?: NobleBleWriteOptions) => Promise<void>;
|
|
22
24
|
onNotification: (callback: (deviceId: string, data: string) => void) => () => void;
|
|
23
25
|
onMtuChanged?: (callback: (device: { id: string; mtu: number }) => void) => () => void;
|
|
24
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Fires whenever a BLE link drops. `reason` distinguishes a real peripheral
|
|
28
|
+
* drop from the main process freeing an idle link on its keep-alive timer;
|
|
29
|
+
* it is optional so an older host bridge that omits it still type-checks
|
|
30
|
+
* (absent is treated as a real drop by consumers).
|
|
31
|
+
*/
|
|
32
|
+
onDeviceDisconnected: (
|
|
33
|
+
callback: (device: { id: string; name: string; reason?: EBleDisconnectReason }) => void
|
|
34
|
+
) => () => void;
|
|
25
35
|
checkAvailability: () => Promise<{
|
|
26
36
|
available: boolean;
|
|
27
37
|
state: string;
|