@onekeyfe/hd-transport-electron 1.2.0-alpha.154 → 1.2.0-alpha.156
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-40be8e99.js → index-fe6d3919.js} +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-26159b70.js → noble-ble-handler-c88e98df.js} +9 -18
- package/dist/noble-ble-handler.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 +10 -48
- 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-c88e98df.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.d.ts
CHANGED
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-fe6d3919.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -116,8 +116,7 @@ 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
|
|
120
|
-
const BLE_IDLE_DISCONNECT_MS = 20000;
|
|
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;
|
|
123
122
|
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
@@ -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,14 +336,7 @@ 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,
|
|
@@ -415,7 +407,6 @@ function handleDeviceDisconnect(deviceId, webContents) {
|
|
|
415
407
|
});
|
|
416
408
|
cleanupDevice(deviceId, webContents, {
|
|
417
409
|
cleanupConnection: true,
|
|
418
|
-
cleanupDiscoveredCache: true,
|
|
419
410
|
sendDisconnectEvent: true,
|
|
420
411
|
cancelOperations: true,
|
|
421
412
|
reason: 'auto-disconnect',
|
|
@@ -1183,15 +1174,11 @@ function disconnectDevice(deviceId) {
|
|
|
1183
1174
|
deviceDisconnectListeners.delete(deviceId);
|
|
1184
1175
|
}
|
|
1185
1176
|
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1186
|
-
timeoutMs:
|
|
1177
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1187
1178
|
timeoutBehavior: 'resolve',
|
|
1188
1179
|
});
|
|
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
1180
|
cleanupDevice(deviceId, undefined, {
|
|
1193
1181
|
cleanupConnection: true,
|
|
1194
|
-
cleanupDiscoveredCache: true,
|
|
1195
1182
|
sendDisconnectEvent: false,
|
|
1196
1183
|
cancelOperations: true,
|
|
1197
1184
|
reason: 'manual-disconnect',
|
|
@@ -1402,6 +1389,10 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1402
1389
|
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1403
1390
|
}
|
|
1404
1391
|
yield stopScanning().catch(() => undefined);
|
|
1392
|
+
if (noble && persistentStateListener) {
|
|
1393
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1394
|
+
persistentStateListener = null;
|
|
1395
|
+
}
|
|
1405
1396
|
cleanupNobleListeners();
|
|
1406
1397
|
discoveredDevices.clear();
|
|
1407
1398
|
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":"AA8BA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AA8BA,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;AA8lDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAgMpE"}
|
|
@@ -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.156",
|
|
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.156",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.156",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.156",
|
|
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": "8fc23f1c3861bfc13c47d235fd155a93525f18c8"
|
|
40
40
|
}
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -89,18 +89,8 @@ const DEVICE_SCAN_TIMEOUT = 5000; // 5 seconds for device scanning
|
|
|
89
89
|
const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks
|
|
90
90
|
const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
|
|
91
91
|
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
92
|
// Renderer release is logical only; this timer physically frees the device.
|
|
97
|
-
|
|
98
|
-
// after sitting idle for minutes (field logs 2026-08-19: every deaf window
|
|
99
|
-
// followed a 3-minute-idle disconnect, while disconnects right after traffic
|
|
100
|
-
// have never produced one across 6.5.0's per-call teardown history). A hot
|
|
101
|
-
// disconnect ~20s after the last operation stays inside the proven-safe
|
|
102
|
-
// pattern and also shrinks the window in which phones cannot see the device.
|
|
103
|
-
const BLE_IDLE_DISCONNECT_MS = 20_000;
|
|
93
|
+
const BLE_IDLE_DISCONNECT_MS = 3 * 60_000;
|
|
104
94
|
// Ceiling while a call is in flight: no outstanding write, but not forever.
|
|
105
95
|
const BLE_BUSY_BACKSTOP_MS = 10 * 60_000;
|
|
106
96
|
|
|
@@ -266,11 +256,6 @@ async function initializeNoble(): Promise<void> {
|
|
|
266
256
|
noble = require('@stoprocent/noble') as NobleModule;
|
|
267
257
|
logger?.info('[NobleBLE] Noble library loaded');
|
|
268
258
|
|
|
269
|
-
// Register the process-lifetime state listener before any early return:
|
|
270
|
-
// the poweredOn fast path below would otherwise skip it for the whole
|
|
271
|
-
// session, leaving poweredOff cache/state reconciliation dead.
|
|
272
|
-
setupPersistentStateListener();
|
|
273
|
-
|
|
274
259
|
// Wait for Bluetooth to be ready
|
|
275
260
|
await new Promise<void>((resolve, reject) => {
|
|
276
261
|
if (!noble) {
|
|
@@ -283,6 +268,9 @@ async function initializeNoble(): Promise<void> {
|
|
|
283
268
|
return;
|
|
284
269
|
}
|
|
285
270
|
|
|
271
|
+
// Setup persistent state listener before initialization
|
|
272
|
+
setupPersistentStateListener();
|
|
273
|
+
|
|
286
274
|
const timeout = setTimeout(() => {
|
|
287
275
|
reject(
|
|
288
276
|
ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout')
|
|
@@ -403,21 +391,7 @@ function armIdleDisconnect(
|
|
|
403
391
|
logger?.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
404
392
|
const peripheral = connectedDevices.get(deviceId);
|
|
405
393
|
const deviceName = peripheral?.advertisement?.localName || 'Unknown Device';
|
|
406
|
-
|
|
407
|
-
// teardown path: the 1S leaves its notify session half-open when the
|
|
408
|
-
// link drops without an unsubscribe and then ignores application
|
|
409
|
-
// protocol traffic on NEW links for tens of minutes (field log
|
|
410
|
-
// 2026-08-19: the lone unsubscribe-skipping idle teardown caused a
|
|
411
|
-
// 6-attempt reconnect loop; unsubscribe-first teardowns reconnected
|
|
412
|
-
// instantly).
|
|
413
|
-
const pending = unsubscribeNotifications(deviceId)
|
|
414
|
-
.catch(error => {
|
|
415
|
-
logger?.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
416
|
-
deviceId,
|
|
417
|
-
error: error instanceof Error ? error.message : String(error),
|
|
418
|
-
});
|
|
419
|
-
})
|
|
420
|
-
.then(() => disconnectDevice(deviceId))
|
|
394
|
+
const pending = disconnectDevice(deviceId)
|
|
421
395
|
.then(() => {
|
|
422
396
|
// A call is still in flight here; it must reject, not hang.
|
|
423
397
|
broadcastToAllWebContents(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
@@ -520,9 +494,6 @@ function handleDeviceDisconnect(deviceId: string, webContents: WebContents): voi
|
|
|
520
494
|
|
|
521
495
|
cleanupDevice(deviceId, webContents, {
|
|
522
496
|
cleanupConnection: true,
|
|
523
|
-
// Same stale-object hazard as manual disconnect: an externally dropped
|
|
524
|
-
// link invalidates the cached peripheral for the next reconnect.
|
|
525
|
-
cleanupDiscoveredCache: true,
|
|
526
497
|
sendDisconnectEvent: true,
|
|
527
498
|
cancelOperations: true,
|
|
528
499
|
reason: 'auto-disconnect',
|
|
@@ -1612,18 +1583,11 @@ async function disconnectDevice(deviceId: string): Promise<void> {
|
|
|
1612
1583
|
}
|
|
1613
1584
|
|
|
1614
1585
|
await runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1615
|
-
timeoutMs:
|
|
1586
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1616
1587
|
timeoutBehavior: 'resolve',
|
|
1617
1588
|
});
|
|
1618
|
-
if (peripheral.state === 'connected') {
|
|
1619
|
-
logger?.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1620
|
-
}
|
|
1621
1589
|
cleanupDevice(deviceId, undefined, {
|
|
1622
1590
|
cleanupConnection: true,
|
|
1623
|
-
// macOS returns zero GATT services when a previously-disconnected
|
|
1624
|
-
// peripheral object is reconnected; drop the discovery cache so the next
|
|
1625
|
-
// connect resolves a fresh peripheral (direct connect by id, or scan).
|
|
1626
|
-
cleanupDiscoveredCache: true,
|
|
1627
1591
|
sendDisconnectEvent: false,
|
|
1628
1592
|
cancelOperations: true,
|
|
1629
1593
|
reason: 'manual-disconnect',
|
|
@@ -1949,12 +1913,10 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
|
|
|
1949
1913
|
}
|
|
1950
1914
|
|
|
1951
1915
|
await stopScanning().catch(() => undefined);
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
// initializeNoble early-returns once noble is loaded). The null-guard
|
|
1957
|
-
// in setupPersistentStateListener keeps it deduped to one instance.
|
|
1916
|
+
if (noble && persistentStateListener) {
|
|
1917
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1918
|
+
persistentStateListener = null;
|
|
1919
|
+
}
|
|
1958
1920
|
cleanupNobleListeners();
|
|
1959
1921
|
discoveredDevices.clear();
|
|
1960
1922
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|