@onekeyfe/hd-transport-web-device 1.2.0-alpha.155 → 1.2.0-alpha.157

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.
@@ -1,5 +1,5 @@
1
1
  import transport, { PROTOCOL_V2_CHANNEL_BLE_UART, bytesToHex } from '@onekeyfe/hd-transport';
2
- import { EBleDisconnectReason, HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
2
+ import { HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
3
3
  import EventEmitter from 'events';
4
4
 
5
5
  import ElectronBleTransport from '../src/electron-ble-transport';
@@ -134,30 +134,6 @@ const configureTransport = (
134
134
  return transport;
135
135
  };
136
136
 
137
- /**
138
- * Wire the mock so acquire()'s Protocol V2 probe gets an answer. Without it
139
- * detectProtocol throws and the test never reaches the disconnect behaviour.
140
- */
141
- const echoProtocolV2 = (nobleBle: ReturnType<typeof createNobleBle>, deviceId: string) => {
142
- let notificationHandler: ((id: string, data: string) => void) | undefined;
143
- nobleBle.onNotification.mockImplementation(handler => {
144
- notificationHandler = handler;
145
- return jest.fn();
146
- });
147
- let responseSeq = 0;
148
- nobleBle.write.mockImplementation(() => {
149
- responseSeq += 1;
150
- const response = ProtocolV2.encodeFrame(
151
- schemas,
152
- 'Success',
153
- { message: 'ok' },
154
- { router: PROTOCOL_V2_CHANNEL_BLE_UART, seq: responseSeq }
155
- );
156
- setTimeout(() => notificationHandler?.(deviceId, bytesToHex(response)), 0);
157
- return Promise.resolve();
158
- });
159
- };
160
-
161
137
  describe('ElectronBleTransport protocol detection', () => {
162
138
  afterEach(() => {
163
139
  delete (global as any).window;
@@ -648,19 +624,21 @@ describe('ElectronBleTransport protocol detection', () => {
648
624
  }
649
625
  });
650
626
 
651
- test('subscribes to host disconnects once for the transport lifetime', async () => {
652
- // The previous design registered a listener inside every acquire() and
653
- // overwrote the cleanup entry without disposing the old one, so each
654
- // acquire leaked a live handler and a delayed event from a superseded
655
- // connection could tear down the current one. One transport-lifetime
656
- // subscription removes that whole class of bug.
657
- const device = { id: 'single-subscription-pro2-id', name: 'OneKey Pro 2' };
627
+ test('ignores a delayed disconnect event from the previous BLE connection', async () => {
628
+ const device = { id: 'delayed-disconnect-pro2-id', name: 'OneKey Pro 2' };
658
629
  const nobleBle = createNobleBle(device);
659
630
  let notificationHandler: ((deviceId: string, data: string) => void) | undefined;
631
+ const disconnectHandlers: Array<
632
+ (disconnectedDevice: { id: string; name: string | null }) => void
633
+ > = [];
660
634
  nobleBle.onNotification.mockImplementation(handler => {
661
635
  notificationHandler = handler;
662
636
  return jest.fn();
663
637
  });
638
+ nobleBle.onDeviceDisconnected.mockImplementation(handler => {
639
+ disconnectHandlers.push(handler);
640
+ return jest.fn();
641
+ });
664
642
  let responseSeq = 0;
665
643
  nobleBle.write.mockImplementation(() => {
666
644
  responseSeq += 1;
@@ -676,15 +654,14 @@ describe('ElectronBleTransport protocol detection', () => {
676
654
  const bleTransport = configureTransport(nobleBle);
677
655
 
678
656
  try {
679
- expect(nobleBle.onDeviceDisconnected).toHaveBeenCalledTimes(1);
680
-
681
657
  await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
682
658
  await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
683
659
 
684
- expect(nobleBle.onDeviceDisconnected).toHaveBeenCalledTimes(1);
660
+ disconnectHandlers[0]?.(device);
661
+
685
662
  expect(bleTransport.getProtocolType(device.id)).toBe('V2');
686
663
  await expect(
687
- bleTransport.call(device.id, 'Ping', { message: 'after-reacquire' })
664
+ bleTransport.call(device.id, 'Ping', { message: 'after-stale-disconnect' })
688
665
  ).resolves.toEqual({
689
666
  type: 'Success',
690
667
  message: { message: 'ok' },
@@ -694,95 +671,6 @@ describe('ElectronBleTransport protocol detection', () => {
694
671
  }
695
672
  });
696
673
 
697
- test('reports a device that drops after a logical release (OK-60486)', async () => {
698
- // A logical release keeps the native link alive for the keep-alive window.
699
- // A drop during that window must still reach consumers, or the UI keeps
700
- // showing the device as connected forever.
701
- const device = { id: 'idle-drop-pro2-id', name: 'OneKey Pro 2' };
702
- const nobleBle = createNobleBle(device);
703
- const emitter = new EventEmitter();
704
- let disconnectHandler:
705
- | ((d: { id: string; name: string; reason?: EBleDisconnectReason }) => void)
706
- | undefined;
707
- nobleBle.onDeviceDisconnected.mockImplementation(handler => {
708
- disconnectHandler = handler;
709
- return jest.fn();
710
- });
711
- echoProtocolV2(nobleBle, device.id);
712
- const transportDisconnect = jest.fn();
713
- emitter.on('transport-device-disconnect', transportDisconnect);
714
- const bleTransport = configureTransport(nobleBle, emitter);
715
-
716
- await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
717
- await bleTransport.release(device.id);
718
-
719
- disconnectHandler?.({ ...device, reason: EBleDisconnectReason.DeviceDisconnected });
720
-
721
- expect(transportDisconnect).toHaveBeenCalledWith({
722
- id: device.id,
723
- connectId: device.id,
724
- name: device.name,
725
- });
726
- });
727
-
728
- test('reports an idle keep-alive release as a device disconnect', async () => {
729
- // The main process reclaims idle links on its own timer. That is still a
730
- // closed link, and consumers track link liveness, so it is reported like
731
- // any other drop. Nothing reconnects on its own, so the state settles once
732
- // until the user acts.
733
- const device = { id: 'keep-alive-pro2-id', name: 'OneKey Pro 2' };
734
- const nobleBle = createNobleBle(device);
735
- const emitter = new EventEmitter();
736
- let disconnectHandler:
737
- | ((d: { id: string; name: string; reason?: EBleDisconnectReason }) => void)
738
- | undefined;
739
- nobleBle.onDeviceDisconnected.mockImplementation(handler => {
740
- disconnectHandler = handler;
741
- return jest.fn();
742
- });
743
- echoProtocolV2(nobleBle, device.id);
744
- const transportDisconnect = jest.fn();
745
- emitter.on('transport-device-disconnect', transportDisconnect);
746
- const bleTransport = configureTransport(nobleBle, emitter);
747
-
748
- await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
749
- disconnectHandler?.({ ...device, reason: EBleDisconnectReason.IdleKeepAlive });
750
-
751
- expect(transportDisconnect).toHaveBeenCalledWith({
752
- id: device.id,
753
- connectId: device.id,
754
- name: device.name,
755
- });
756
- // The link really is gone, so cached link state must be dropped too.
757
- expect(bleTransport.getProtocolType(device.id)).toBeUndefined();
758
- });
759
-
760
- test('treats a disconnect with no reason as a real device drop', async () => {
761
- // An older host bridge does not send `reason`; defaulting to "device left"
762
- // preserves the pre-existing behaviour rather than silently ignoring it.
763
- const device = { id: 'legacy-host-pro2-id', name: 'OneKey Pro 2' };
764
- const nobleBle = createNobleBle(device);
765
- const emitter = new EventEmitter();
766
- let disconnectHandler: ((d: { id: string; name: string }) => void) | undefined;
767
- nobleBle.onDeviceDisconnected.mockImplementation(handler => {
768
- disconnectHandler = handler;
769
- return jest.fn();
770
- });
771
- echoProtocolV2(nobleBle, device.id);
772
- const transportDisconnect = jest.fn();
773
- emitter.on('transport-device-disconnect', transportDisconnect);
774
- const bleTransport = configureTransport(nobleBle, emitter);
775
-
776
- await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
777
- disconnectHandler?.(device);
778
-
779
- expect(transportDisconnect).toHaveBeenCalledWith({
780
- id: device.id,
781
- connectId: device.id,
782
- name: device.name,
783
- });
784
- });
785
-
786
674
  test('preserves the active Protocol V2 link when the same schema is configured again', async () => {
787
675
  const device = { id: 'stable-schema-pro2-id', name: 'OneKey Pro 2' };
788
676
  const nobleBle = createNobleBle(device);
@@ -38,13 +38,12 @@ export default class ElectronBleTransport {
38
38
  private warnedMissingRelease;
39
39
  private notificationCleanups;
40
40
  private mtuCleanups;
41
- private hostDisconnectCleanup?;
41
+ private disconnectCleanups;
42
42
  private notificationTokens;
43
43
  private nextNotificationToken;
44
44
  private handleBluetoothError;
45
45
  private cleanupDeviceState;
46
46
  init(logger: any, emitter?: EventEmitter): void;
47
- private subscribeHostDisconnects;
48
47
  configure(signedData: any): void;
49
48
  configureProtocolV2(signedData: any): void;
50
49
  listen(): Promise<OneKeyDeviceInfo[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as _onekeyfe_hd_transport from '@onekeyfe/hd-transport';
2
2
  import _onekeyfe_hd_transport__default, { ProtocolV2UsbTransportBase, AcquireInput, TransportCallOptions, ProtocolV2Schemas, ProtocolV2CallContext, ProtocolType, OneKeyDeviceInfoBase, OneKeyDeviceInfo } from '@onekeyfe/hd-transport';
3
- import EventEmitter from 'events';
4
3
  import { Deferred } from '@onekeyfe/hd-shared';
5
4
  import { DesktopAPI } from '@onekeyfe/hd-transport-electron';
5
+ import EventEmitter from 'events';
6
6
 
7
7
  /**
8
8
  * Device information with path and WebUSB device instance
@@ -42,7 +42,6 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
42
42
  configured: boolean;
43
43
  Log?: any;
44
44
  usb?: USB;
45
- emitter?: EventEmitter;
46
45
  /**
47
46
  * Cached list of connected devices
48
47
  * This is essential for maintaining device references between operations
@@ -55,12 +54,7 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
55
54
  /**
56
55
  * Initialize WebUSB transport
57
56
  */
58
- init(logger: any, emitter?: EventEmitter): void;
59
- /**
60
- * Announce that a USB device left. Called from the module-scoped disconnect
61
- * listener, which is why it is public rather than inlined.
62
- */
63
- emitDeviceDisconnect(path: string, device?: USBDevice): void;
57
+ init(logger: any): void;
64
58
  /**
65
59
  * Protocol type is a property of the physical device keyed by USB serial number.
66
60
  * It can only change across a device reboot (e.g. normal ↔ bootloader mode), and
@@ -229,26 +223,12 @@ declare class ElectronBleTransport {
229
223
  private warnedMissingRelease;
230
224
  private notificationCleanups;
231
225
  private mtuCleanups;
232
- /**
233
- * Transport-lifetime subscription to host BLE disconnects.
234
- *
235
- * This must NOT be scoped to acquire()/release(): a logical release keeps the
236
- * native link alive for the keep-alive window, so a device that drops while
237
- * idle would otherwise go unobserved and consumers would never learn it left
238
- * (OK-60486).
239
- */
240
- private hostDisconnectCleanup?;
226
+ private disconnectCleanups;
241
227
  private notificationTokens;
242
228
  private nextNotificationToken;
243
229
  private handleBluetoothError;
244
230
  private cleanupDeviceState;
245
231
  init(logger: any, emitter?: EventEmitter): void;
246
- /**
247
- * One host subscription for the whole transport lifetime. init() can run
248
- * again after an SDK reset, so drop the previous listener first rather than
249
- * stacking duplicates.
250
- */
251
- private subscribeHostDisconnects;
252
232
  configure(signedData: any): void;
253
233
  configureProtocolV2(signedData: any): void;
254
234
  listen(): Promise<OneKeyDeviceInfo[]>;
package/dist/index.js CHANGED
@@ -68,7 +68,6 @@ function registerActiveWebUsbTransport(instance, usb) {
68
68
  if (!path)
69
69
  return;
70
70
  activeWebUsbTransport === null || activeWebUsbTransport === void 0 ? void 0 : activeWebUsbTransport.markProtocolStale(path);
71
- activeWebUsbTransport === null || activeWebUsbTransport === void 0 ? void 0 : activeWebUsbTransport.emitDeviceDisconnect(path, event.device);
72
71
  });
73
72
  }
74
73
  class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
@@ -92,9 +91,8 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
92
91
  this.endpointId = ENDPOINT_ID;
93
92
  this.interfaceId = INTERFACE_ID;
94
93
  }
95
- init(logger, emitter) {
94
+ init(logger) {
96
95
  this.Log = logger;
97
- this.emitter = emitter;
98
96
  const { usb } = navigator;
99
97
  if (!usb) {
100
98
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'WebUSB is not supported by current browsers');
@@ -102,14 +100,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
102
100
  this.usb = usb;
103
101
  registerActiveWebUsbTransport(this, usb);
104
102
  }
105
- emitDeviceDisconnect(path, device) {
106
- var _a, _b;
107
- (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
108
- name: (_b = device === null || device === void 0 ? void 0 : device.productName) !== null && _b !== void 0 ? _b : '',
109
- id: path,
110
- connectId: path,
111
- });
112
- }
113
103
  markProtocolStale(path) {
114
104
  this.staleProtocolPaths.add(path);
115
105
  this.probedDeviceObjects.delete(path);
@@ -849,6 +839,7 @@ class ElectronBleTransport {
849
839
  this.warnedMissingRelease = false;
850
840
  this.notificationCleanups = new Map();
851
841
  this.mtuCleanups = new Map();
842
+ this.disconnectCleanups = new Map();
852
843
  this.notificationTokens = new Map();
853
844
  this.nextNotificationToken = 1;
854
845
  }
@@ -908,6 +899,11 @@ class ElectronBleTransport {
908
899
  mtuCleanup();
909
900
  this.mtuCleanups.delete(deviceId);
910
901
  }
902
+ const disconnectCleanup = this.disconnectCleanups.get(deviceId);
903
+ if (disconnectCleanup) {
904
+ disconnectCleanup();
905
+ this.disconnectCleanups.delete(deviceId);
906
+ }
911
907
  }
912
908
  init(logger, emitter) {
913
909
  var _a, _b;
@@ -916,26 +912,8 @@ class ElectronBleTransport {
916
912
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
917
913
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble BLE API is not available. Please ensure you are running in Electron with Noble support.');
918
914
  }
919
- this.subscribeHostDisconnects();
920
915
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Transport initialized');
921
916
  }
922
- subscribeHostDisconnects() {
923
- var _a, _b, _c;
924
- (_a = this.hostDisconnectCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
925
- this.hostDisconnectCleanup = (_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.onDeviceDisconnected((disconnectedDevice) => {
926
- var _a, _b, _c;
927
- const uuid = disconnectedDevice === null || disconnectedDevice === void 0 ? void 0 : disconnectedDevice.id;
928
- if (!uuid)
929
- return;
930
- this.cleanupDeviceState(uuid);
931
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Device link dropped:', uuid, (_b = disconnectedDevice.reason) !== null && _b !== void 0 ? _b : hdShared.EBleDisconnectReason.DeviceDisconnected);
932
- (_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
933
- name: disconnectedDevice.name,
934
- id: uuid,
935
- connectId: uuid,
936
- });
937
- });
938
- }
939
917
  configure(signedData) {
940
918
  this._messages = parseConfigure(signedData);
941
919
  this.configured = true;
@@ -1026,6 +1004,7 @@ class ElectronBleTransport {
1026
1004
  yield this.refreshBlePacketCapacity(uuid);
1027
1005
  const cleanup = this.createNotificationSubscription(uuid);
1028
1006
  this.notificationCleanups.set(uuid, cleanup);
1007
+ const connectionToken = this.notificationTokens.get(uuid);
1029
1008
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
1030
1009
  if (protocolType === 'V2') {
1031
1010
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[Electron BLE] Protocol V2 write configured', {
@@ -1034,6 +1013,19 @@ class ElectronBleTransport {
1034
1013
  packetCapacity: (_d = this.devicePacketCapacities.get(uuid)) !== null && _d !== void 0 ? _d : BLE_PACKET_SIZE_FALLBACK,
1035
1014
  });
1036
1015
  }
1016
+ const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
1017
+ var _a;
1018
+ if (disconnectedDevice.id === uuid &&
1019
+ this.notificationTokens.get(uuid) === connectionToken) {
1020
+ this.cleanupDeviceState(uuid);
1021
+ (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
1022
+ name: disconnectedDevice.name,
1023
+ id: disconnectedDevice.id,
1024
+ connectId: disconnectedDevice.id,
1025
+ });
1026
+ }
1027
+ });
1028
+ this.disconnectCleanups.set(uuid, disconnectCleanup);
1037
1029
  return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
1038
1030
  }
1039
1031
  catch (error) {
package/dist/webusb.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  /// <reference types="w3c-web-usb" />
2
- /// <reference types="node" />
3
2
  import transport, { ProtocolV2UsbTransportBase } from '@onekeyfe/hd-transport';
4
- import type EventEmitter from 'events';
5
3
  import type { AcquireInput, OneKeyDeviceInfoBase, ProtocolType, ProtocolV2CallContext, ProtocolV2Schemas, TransportCallOptions } from '@onekeyfe/hd-transport';
6
4
  export interface DeviceInfo extends OneKeyDeviceInfoBase {
7
5
  path: string;
@@ -23,14 +21,12 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
23
21
  configured: boolean;
24
22
  Log?: any;
25
23
  usb?: USB;
26
- emitter?: EventEmitter;
27
24
  deviceList: Array<DeviceInfo>;
28
25
  configurationId: number;
29
26
  endpointId: number;
30
27
  interfaceId: number;
31
28
  constructor();
32
- init(logger: any, emitter?: EventEmitter): void;
33
- emitDeviceDisconnect(path: string, device?: USBDevice): void;
29
+ init(logger: any): void;
34
30
  markProtocolStale(path: string): void;
35
31
  configure(signedData: any): void;
36
32
  configureProtocolV2(signedData: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-web-device",
3
- "version": "1.2.0-alpha.155",
3
+ "version": "1.2.0-alpha.157",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -21,13 +21,13 @@
21
21
  "lint:fix": "eslint . --fix"
22
22
  },
23
23
  "dependencies": {
24
- "@onekeyfe/hd-shared": "1.2.0-alpha.155",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.155"
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.157",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.157"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.0-alpha.155",
28
+ "@onekeyfe/hd-transport-electron": "1.2.0-alpha.157",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "922cb4e29b2d89511c9b67c25840294335cb8005"
32
+ "gitHead": "1e9aaf5fbf64562504ebc22dc34fb22220ba0b0b"
33
33
  }
@@ -11,7 +11,6 @@ import transport, {
11
11
  writeProtocolV2BleFrame,
12
12
  } from '@onekeyfe/hd-transport';
13
13
  import {
14
- EBleDisconnectReason,
15
14
  ERRORS,
16
15
  HardwareErrorCode,
17
16
  HardwareErrorCodeMessage,
@@ -145,15 +144,7 @@ export default class ElectronBleTransport {
145
144
 
146
145
  private mtuCleanups: Map<string, () => void> = new Map();
147
146
 
148
- /**
149
- * Transport-lifetime subscription to host BLE disconnects.
150
- *
151
- * This must NOT be scoped to acquire()/release(): a logical release keeps the
152
- * native link alive for the keep-alive window, so a device that drops while
153
- * idle would otherwise go unobserved and consumers would never learn it left
154
- * (OK-60486).
155
- */
156
- private hostDisconnectCleanup?: () => void;
147
+ private disconnectCleanups: Map<string, () => void> = new Map();
157
148
 
158
149
  private notificationTokens: Map<string, number> = new Map();
159
150
 
@@ -221,6 +212,12 @@ export default class ElectronBleTransport {
221
212
  mtuCleanup();
222
213
  this.mtuCleanups.delete(deviceId);
223
214
  }
215
+
216
+ const disconnectCleanup = this.disconnectCleanups.get(deviceId);
217
+ if (disconnectCleanup) {
218
+ disconnectCleanup();
219
+ this.disconnectCleanups.delete(deviceId);
220
+ }
224
221
  }
225
222
 
226
223
  init(logger: any, emitter?: EventEmitter) {
@@ -234,48 +231,9 @@ export default class ElectronBleTransport {
234
231
  );
235
232
  }
236
233
 
237
- this.subscribeHostDisconnects();
238
-
239
234
  this.Log?.debug('[Electron BLE] Transport initialized');
240
235
  }
241
236
 
242
- /**
243
- * One host subscription for the whole transport lifetime. init() can run
244
- * again after an SDK reset, so drop the previous listener first rather than
245
- * stacking duplicates.
246
- */
247
- private subscribeHostDisconnects() {
248
- this.hostDisconnectCleanup?.();
249
- this.hostDisconnectCleanup = window.desktopApi?.nobleBle?.onDeviceDisconnected(
250
- (disconnectedDevice: { id: string; name: string; reason?: EBleDisconnectReason }) => {
251
- const uuid = disconnectedDevice?.id;
252
- if (!uuid) return;
253
-
254
- // The link is gone, so renderer-side state must go with it; the next
255
- // acquire reconnects from scratch.
256
- this.cleanupDeviceState(uuid);
257
-
258
- // Every link drop is reported, including the main process reclaiming
259
- // an idle link on its keep-alive timer: consumers track whether a BLE
260
- // link is live, not whether the peripheral is theoretically in range,
261
- // and a link we closed ourselves is still a closed link. Nothing
262
- // reconnects on its own, so this settles once until the user acts.
263
- // `reason` is carried for diagnostics only — behaviour is uniform.
264
- this.Log?.debug(
265
- '[Electron BLE] Device link dropped:',
266
- uuid,
267
- disconnectedDevice.reason ?? EBleDisconnectReason.DeviceDisconnected
268
- );
269
-
270
- this.emitter?.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
271
- name: disconnectedDevice.name,
272
- id: uuid,
273
- connectId: uuid,
274
- });
275
- }
276
- );
277
- }
278
-
279
237
  configure(signedData: any) {
280
238
  this._messages = parseConfigure(signedData);
281
239
  this.configured = true;
@@ -372,6 +330,7 @@ export default class ElectronBleTransport {
372
330
 
373
331
  const cleanup = this.createNotificationSubscription(uuid);
374
332
  this.notificationCleanups.set(uuid, cleanup);
333
+ const connectionToken = this.notificationTokens.get(uuid);
375
334
 
376
335
  const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
377
336
  if (protocolType === 'V2') {
@@ -382,6 +341,23 @@ export default class ElectronBleTransport {
382
341
  });
383
342
  }
384
343
 
344
+ const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected(
345
+ (disconnectedDevice: any) => {
346
+ if (
347
+ disconnectedDevice.id === uuid &&
348
+ this.notificationTokens.get(uuid) === connectionToken
349
+ ) {
350
+ this.cleanupDeviceState(uuid);
351
+ this.emitter?.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
352
+ name: disconnectedDevice.name,
353
+ id: disconnectedDevice.id,
354
+ connectId: disconnectedDevice.id,
355
+ });
356
+ }
357
+ }
358
+ );
359
+ this.disconnectCleanups.set(uuid, disconnectCleanup);
360
+
385
361
  return {
386
362
  ...toBleDescriptor({ id: device.id, name: device.name }, protocolType),
387
363
  uuid,
package/src/webusb.ts CHANGED
@@ -8,7 +8,6 @@ import transport, {
8
8
  PROTOCOL_V2_FRAME_MAX_BYTES,
9
9
  ProtocolV2LinkError,
10
10
  ProtocolV2UsbTransportBase,
11
- TRANSPORT_EVENT,
12
11
  probeProtocolV2 as probeProtocolV2Helper,
13
12
  } from '@onekeyfe/hd-transport';
14
13
  import {
@@ -22,7 +21,6 @@ import {
22
21
  } from '@onekeyfe/hd-shared';
23
22
  import ByteBuffer from 'bytebuffer';
24
23
 
25
- import type EventEmitter from 'events';
26
24
  import type {
27
25
  AcquireInput,
28
26
  OneKeyDeviceInfoBase,
@@ -89,10 +87,6 @@ function registerActiveWebUsbTransport(instance: WebUsbTransport, usb: USB) {
89
87
  const path = resolveOneKeyUsbDevicePath(event.device);
90
88
  if (!path) return;
91
89
  activeWebUsbTransport?.markProtocolStale(path);
92
- // WebUSB has no device-list poller behind it, so this event is the only
93
- // signal that the device is gone. Without it consumers never see a
94
- // DEVICE.DISCONNECT for USB (OK-60486).
95
- activeWebUsbTransport?.emitDeviceDisconnect(path, event.device);
96
90
  });
97
91
  }
98
92
 
@@ -140,8 +134,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
140
134
 
141
135
  usb?: USB;
142
136
 
143
- emitter?: EventEmitter;
144
-
145
137
  /**
146
138
  * Cached list of connected devices
147
139
  * This is essential for maintaining device references between operations
@@ -165,9 +157,8 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
165
157
  /**
166
158
  * Initialize WebUSB transport
167
159
  */
168
- init(logger: any, emitter?: EventEmitter) {
160
+ init(logger: any) {
169
161
  this.Log = logger;
170
- this.emitter = emitter;
171
162
 
172
163
  const { usb } = navigator;
173
164
  if (!usb) {
@@ -180,18 +171,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
180
171
  registerActiveWebUsbTransport(this, usb);
181
172
  }
182
173
 
183
- /**
184
- * Announce that a USB device left. Called from the module-scoped disconnect
185
- * listener, which is why it is public rather than inlined.
186
- */
187
- emitDeviceDisconnect(path: string, device?: USBDevice) {
188
- this.emitter?.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
189
- name: device?.productName ?? '',
190
- id: path,
191
- connectId: path,
192
- });
193
- }
194
-
195
174
  /**
196
175
  * Protocol type is a property of the physical device keyed by USB serial number.
197
176
  * It can only change across a device reboot (e.g. normal ↔ bootloader mode), and