@onekeyfe/hd-transport-electron 1.2.0-alpha.152 → 1.2.0-alpha.154

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-c88e98df.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-26159b70.js'); });
36
36
  setupNobleBleHandlers(webContents);
37
37
  });
38
38
  }
package/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@ interface NobleModule {
24
24
  interface Logger {
25
25
  info(message: string, ...args: any[]): void;
26
26
  debug(message: string, ...args: any[]): void;
27
+ warn(message: string, ...args: any[]): void;
27
28
  error(message: string, ...args: any[]): void;
28
29
  }
29
30
 
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-fe6d3919.js');
5
+ var index = require('./index-40be8e99.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-fe6d3919.js');
3
+ var index = require('./index-40be8e99.js');
4
4
  var hdShared = require('@onekeyfe/hd-shared');
5
5
  var pRetry = require('p-retry');
6
6
 
@@ -116,7 +116,8 @@ 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_IDLE_DISCONNECT_MS = 3 * 60000;
119
+ const BLE_DISCONNECT_CONFIRM_TIMEOUT_MS = 3000;
120
+ const BLE_IDLE_DISCONNECT_MS = 20000;
120
121
  const BLE_BUSY_BACKSTOP_MS = 10 * 60000;
121
122
  const BLE_PACKET_SIZE_FALLBACK = 192;
122
123
  const BLE_PACKET_SIZE_MAXIMUM = 244;
@@ -242,6 +243,7 @@ function initializeNoble() {
242
243
  try {
243
244
  noble = require('@stoprocent/noble');
244
245
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble library loaded');
246
+ setupPersistentStateListener();
245
247
  yield new Promise((resolve, reject) => {
246
248
  if (!noble) {
247
249
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not initialized'));
@@ -251,7 +253,6 @@ function initializeNoble() {
251
253
  resolve();
252
254
  return;
253
255
  }
254
- setupPersistentStateListener();
255
256
  const timeout = setTimeout(() => {
256
257
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout'));
257
258
  }, BLUETOOTH_INIT_TIMEOUT);
@@ -336,7 +337,14 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
336
337
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
337
338
  const peripheral = connectedDevices.get(deviceId);
338
339
  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 = disconnectDevice(deviceId)
340
+ const pending = unsubscribeNotifications(deviceId)
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))
340
348
  .then(() => {
341
349
  broadcastToAllWebContents(hdShared.EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
342
350
  id: deviceId,
@@ -407,6 +415,7 @@ function handleDeviceDisconnect(deviceId, webContents) {
407
415
  });
408
416
  cleanupDevice(deviceId, webContents, {
409
417
  cleanupConnection: true,
418
+ cleanupDiscoveredCache: true,
410
419
  sendDisconnectEvent: true,
411
420
  cancelOperations: true,
412
421
  reason: 'auto-disconnect',
@@ -1174,11 +1183,15 @@ function disconnectDevice(deviceId) {
1174
1183
  deviceDisconnectListeners.delete(deviceId);
1175
1184
  }
1176
1185
  yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
1177
- timeoutMs: BLE_CLEANUP_TIMEOUT,
1186
+ timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
1178
1187
  timeoutBehavior: 'resolve',
1179
1188
  });
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
+ }
1180
1192
  cleanupDevice(deviceId, undefined, {
1181
1193
  cleanupConnection: true,
1194
+ cleanupDiscoveredCache: true,
1182
1195
  sendDisconnectEvent: false,
1183
1196
  cancelOperations: true,
1184
1197
  reason: 'manual-disconnect',
@@ -1389,10 +1402,6 @@ function setupNobleBleHandlers(webContents) {
1389
1402
  yield disconnectDevice(deviceId).catch(() => undefined);
1390
1403
  }
1391
1404
  yield stopScanning().catch(() => undefined);
1392
- if (noble && persistentStateListener) {
1393
- noble.removeListener('stateChange', persistentStateListener);
1394
- persistentStateListener = null;
1395
- }
1396
1405
  cleanupNobleListeners();
1397
1406
  discoveredDevices.clear();
1398
1407
  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;AA0EhE,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AA8lDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAgMpE"}
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;AAoFhE,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAwnDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkMpE"}
@@ -22,6 +22,7 @@ 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;
25
26
  error(message: string, ...args: any[]): void;
26
27
  }
27
28
  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,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"}
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,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;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.152",
3
+ "version": "1.2.0-alpha.154",
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.152",
29
- "@onekeyfe/hd-shared": "1.2.0-alpha.152",
30
- "@onekeyfe/hd-transport": "1.2.0-alpha.152",
28
+ "@onekeyfe/hd-core": "1.2.0-alpha.154",
29
+ "@onekeyfe/hd-shared": "1.2.0-alpha.154",
30
+ "@onekeyfe/hd-transport": "1.2.0-alpha.154",
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": "cbd3c7de0d95f910c98165467da53035f16e9d40"
39
+ "gitHead": "0b81bf264b2b33e00550b1008264c02e0a049b68"
40
40
  }
@@ -89,8 +89,18 @@ 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;
92
96
  // Renderer release is logical only; this timer physically frees the device.
93
- const BLE_IDLE_DISCONNECT_MS = 3 * 60_000;
97
+ // Keep it SHORT: the Classic 1S goes protocol-deaf when a link is dropped
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;
94
104
  // Ceiling while a call is in flight: no outstanding write, but not forever.
95
105
  const BLE_BUSY_BACKSTOP_MS = 10 * 60_000;
96
106
 
@@ -256,6 +266,11 @@ async function initializeNoble(): Promise<void> {
256
266
  noble = require('@stoprocent/noble') as NobleModule;
257
267
  logger?.info('[NobleBLE] Noble library loaded');
258
268
 
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
+
259
274
  // Wait for Bluetooth to be ready
260
275
  await new Promise<void>((resolve, reject) => {
261
276
  if (!noble) {
@@ -268,9 +283,6 @@ async function initializeNoble(): Promise<void> {
268
283
  return;
269
284
  }
270
285
 
271
- // Setup persistent state listener before initialization
272
- setupPersistentStateListener();
273
-
274
286
  const timeout = setTimeout(() => {
275
287
  reject(
276
288
  ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout')
@@ -391,7 +403,21 @@ function armIdleDisconnect(
391
403
  logger?.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
392
404
  const peripheral = connectedDevices.get(deviceId);
393
405
  const deviceName = peripheral?.advertisement?.localName || 'Unknown Device';
394
- const pending = disconnectDevice(deviceId)
406
+ // Unsubscribe CCCD before dropping the link, matching every other
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))
395
421
  .then(() => {
396
422
  // A call is still in flight here; it must reject, not hang.
397
423
  broadcastToAllWebContents(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
@@ -494,6 +520,9 @@ function handleDeviceDisconnect(deviceId: string, webContents: WebContents): voi
494
520
 
495
521
  cleanupDevice(deviceId, webContents, {
496
522
  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,
497
526
  sendDisconnectEvent: true,
498
527
  cancelOperations: true,
499
528
  reason: 'auto-disconnect',
@@ -1583,11 +1612,18 @@ async function disconnectDevice(deviceId: string): Promise<void> {
1583
1612
  }
1584
1613
 
1585
1614
  await runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
1586
- timeoutMs: BLE_CLEANUP_TIMEOUT,
1615
+ timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
1587
1616
  timeoutBehavior: 'resolve',
1588
1617
  });
1618
+ if (peripheral.state === 'connected') {
1619
+ logger?.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
1620
+ }
1589
1621
  cleanupDevice(deviceId, undefined, {
1590
1622
  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,
1591
1627
  sendDisconnectEvent: false,
1592
1628
  cancelOperations: true,
1593
1629
  reason: 'manual-disconnect',
@@ -1913,10 +1949,12 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
1913
1949
  }
1914
1950
 
1915
1951
  await stopScanning().catch(() => undefined);
1916
- if (noble && persistentStateListener) {
1917
- noble.removeListener('stateChange', persistentStateListener);
1918
- persistentStateListener = null;
1919
- }
1952
+ // persistentStateListener is process-lifetime, NOT per-window: this
1953
+ // destroy handler also fires on a renderer soft restart, and removing
1954
+ // the listener here permanently killed poweredOff/poweredOn
1955
+ // reconciliation for the rest of the process (nothing re-registers it:
1956
+ // initializeNoble early-returns once noble is loaded). The null-guard
1957
+ // in setupPersistentStateListener keeps it deduped to one instance.
1920
1958
  cleanupNobleListeners();
1921
1959
  discoveredDevices.clear();
1922
1960
  safeLog(logger, 'info', 'Noble BLE cleanup completed');
@@ -39,6 +39,7 @@ export interface NobleModule {
39
39
  export interface Logger {
40
40
  info(message: string, ...args: any[]): void;
41
41
  debug(message: string, ...args: any[]): void;
42
+ warn(message: string, ...args: any[]): void;
42
43
  error(message: string, ...args: any[]): void;
43
44
  }
44
45