@onekeyfe/hd-transport-web-device 1.2.0-alpha.143 → 1.2.0-alpha.145

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.
@@ -440,11 +440,51 @@ describe('ElectronBleTransport protocol detection', () => {
440
440
  expect(transport.getProtocolType(device.id)).toBeUndefined();
441
441
  });
442
442
 
443
+ test('keeps a first expected Protocol V2 probe miss retryable', async () => {
444
+ const device = { id: 'first-v2-id', name: 'OneKey Pro 2' };
445
+ const nobleBle = createNobleBle(device);
446
+ const transport = configureTransport(nobleBle);
447
+ jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
448
+
449
+ await expect(
450
+ transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
451
+ ).rejects.toMatchObject({
452
+ errorCode: HardwareErrorCode.RuntimeError,
453
+ });
454
+
455
+ expect(nobleBle.connect).toHaveBeenCalledTimes(1);
456
+ expect(transport.getProtocolType(device.id)).toBeUndefined();
457
+ });
458
+
459
+ test('reports a stale bond after a second expected Protocol V2 probe miss', async () => {
460
+ const device = { id: 'retry-pro2-id', name: 'OneKey Pro 2' };
461
+ const nobleBle = createNobleBle(device);
462
+ const transport = configureTransport(nobleBle);
463
+ jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
464
+
465
+ await expect(
466
+ transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
467
+ ).rejects.toMatchObject({
468
+ errorCode: HardwareErrorCode.RuntimeError,
469
+ });
470
+ await expect(
471
+ transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
472
+ ).rejects.toMatchObject({
473
+ errorCode: HardwareErrorCode.BleDeviceBondError,
474
+ });
475
+
476
+ expect(transport.getProtocolType(device.id)).toBeUndefined();
477
+ });
478
+
443
479
  test('reports a stale bond when a previously confirmed Protocol V2 device stops responding', async () => {
444
480
  const device = { id: 'reset-pro2-id', name: 'OneKey Pro 2' };
445
481
  const nobleBle = createNobleBle(device);
446
482
  const transport = configureTransport(nobleBle);
447
- jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
483
+ const probe = jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(true);
484
+
485
+ await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
486
+ await transport.release(device.id);
487
+ probe.mockResolvedValue(false);
448
488
 
449
489
  await expect(
450
490
  transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
@@ -452,13 +492,12 @@ describe('ElectronBleTransport protocol detection', () => {
452
492
  errorCode: HardwareErrorCode.BleDeviceBondError,
453
493
  });
454
494
 
455
- expect(nobleBle.connect).toHaveBeenCalledTimes(1);
456
495
  expect(nobleBle.unsubscribe).toHaveBeenCalledWith(device.id);
457
496
  expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
458
497
  expect(transport.getProtocolType(device.id)).toBeUndefined();
459
498
  });
460
499
 
461
- test('probes Protocol V2 instead of trusting the Pro2 name hint', async () => {
500
+ test('does not take a Protocol V2 hint from the BLE name', async () => {
462
501
  const device = { id: 'named-pro2-id', name: 'OneKey Pro 2' };
463
502
  const nobleBle = createNobleBle(device);
464
503
  let notificationHandler: ((deviceId: string, data: string) => void) | undefined;
@@ -488,15 +527,15 @@ describe('ElectronBleTransport protocol detection', () => {
488
527
  protocolType: 'V2',
489
528
  })
490
529
  );
491
- expect(nobleBle.write).toHaveBeenCalledTimes(1);
530
+ expect(nobleBle.write.mock.calls.length).toBeGreaterThan(1);
492
531
  expect(transport.getProtocolType(device.id)).toBe('V2');
493
532
  await expect(transport.call(device.id, 'Ping', { message: 'after-probe' })).resolves.toEqual({
494
533
  type: 'Success',
495
534
  message: { message: 'ok' },
496
535
  });
497
- const sentSeqs = nobleBle.write.mock.calls.map(([, hex]) =>
498
- Number.parseInt(hex.slice(12, 14), 16)
499
- );
536
+ const sentSeqs = nobleBle.write.mock.calls
537
+ .map(([, hex]) => Number.parseInt(hex.slice(12, 14), 16))
538
+ .filter(seq => seq > 0);
500
539
  expect(sentSeqs).toEqual([1, 2]);
501
540
  } finally {
502
541
  await transport.release(device.id);
@@ -576,9 +615,9 @@ describe('ElectronBleTransport protocol detection', () => {
576
615
  message: { message: 'ok' },
577
616
  });
578
617
 
579
- const sentSeqs = nobleBle.write.mock.calls.map(([, hex]) =>
580
- Number.parseInt(hex.slice(12, 14), 16)
581
- );
618
+ const sentSeqs = nobleBle.write.mock.calls
619
+ .map(([, hex]) => Number.parseInt(hex.slice(12, 14), 16))
620
+ .filter(seq => seq > 0);
582
621
  expect(sentSeqs).toEqual([1, 2, 3]);
583
622
  } finally {
584
623
  await transport.release(device.id);
@@ -230,7 +230,7 @@ describe('WebUsbTransport protocol probe cache', () => {
230
230
  expect(second.deviceProtocol.get(path)).toBe('V1');
231
231
  expect(first.staleProtocolPaths.has(path)).toBe(false);
232
232
 
233
- // Events without a usable serial are ignored.
233
+ // Events without a device identity are ignored.
234
234
  handler({ device: { serialNumber: null } });
235
235
  handler({});
236
236
  expect(second.staleProtocolPaths.size).toBe(1);
@@ -21,8 +21,9 @@ const schema = {
21
21
  };
22
22
 
23
23
  describe('WebUsbTransport Protocol V2 timeout recovery', () => {
24
- test('only enumerates devices with real USB serial numbers', async () => {
25
- const filter = ONEKEY_WEBUSB_FILTER[0];
24
+ test('enumerates OneKey USB devices even when the serial string is omitted', async () => {
25
+ const filter =
26
+ ONEKEY_WEBUSB_FILTER.find(item => item.productId === 0x4f4c) ?? ONEKEY_WEBUSB_FILTER[0];
26
27
  const deviceWithSerial = {
27
28
  ...filter,
28
29
  manufacturerName: 'OneKey',
@@ -32,7 +33,7 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
32
33
  const deviceWithoutSerial = {
33
34
  ...filter,
34
35
  manufacturerName: 'OneKey',
35
- productName: 'OneKey Pro 2',
36
+ productName: 'OneKey Neo',
36
37
  serialNumber: null,
37
38
  } as USBDevice;
38
39
  const webusb = new WebUsbTransport();
@@ -46,6 +47,11 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
46
47
  device: deviceWithSerial,
47
48
  commType: 'webusb',
48
49
  },
50
+ {
51
+ path: 'usb-1209-4f4c-onekey-neo',
52
+ device: deviceWithoutSerial,
53
+ commType: 'webusb',
54
+ },
49
55
  ]);
50
56
  });
51
57
 
@@ -27,6 +27,8 @@ export default class ElectronBleTransport {
27
27
  private connectedDevices;
28
28
  private deviceProtocol;
29
29
  private deviceProtocolHints;
30
+ private confirmedProtocolV2;
31
+ private retryableV2Mismatch;
30
32
  private deviceMtus;
31
33
  private devicePacketCapacities;
32
34
  private v1Buffers;
@@ -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
@@ -210,6 +210,10 @@ declare class ElectronBleTransport {
210
210
  private connectedDevices;
211
211
  private deviceProtocol;
212
212
  private deviceProtocolHints;
213
+ /** Endpoints that answered a V2 probe in this transport lifetime. Survives disconnect. */
214
+ private confirmedProtocolV2;
215
+ /** First expected-V2 miss for an unconfirmed endpoint; the next miss is a stale bond. */
216
+ private retryableV2Mismatch;
213
217
  private deviceMtus;
214
218
  private devicePacketCapacities;
215
219
  private v1Buffers;
package/dist/index.js CHANGED
@@ -54,9 +54,6 @@ const PACKET_IO_RETRY_DELAY = 300;
54
54
  const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
55
55
  const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
56
56
  const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
57
- function inferProtocolHintFromDeviceName$1(name) {
58
- return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
59
- }
60
57
  let activeWebUsbTransport;
61
58
  let usbDisconnectListenerAttached = false;
62
59
  function registerActiveWebUsbTransport(instance, usb) {
@@ -65,11 +62,12 @@ function registerActiveWebUsbTransport(instance, usb) {
65
62
  return;
66
63
  usbDisconnectListenerAttached = true;
67
64
  usb.addEventListener('disconnect', event => {
68
- var _a;
69
- const serial = (_a = event.device) === null || _a === void 0 ? void 0 : _a.serialNumber;
70
- if (typeof serial !== 'string' || serial.length === 0)
65
+ if (!event.device)
71
66
  return;
72
- activeWebUsbTransport === null || activeWebUsbTransport === void 0 ? void 0 : activeWebUsbTransport.markProtocolStale(serial);
67
+ const path = hdShared.resolveOneKeyUsbDevicePath(event.device);
68
+ if (!path)
69
+ return;
70
+ activeWebUsbTransport === null || activeWebUsbTransport === void 0 ? void 0 : activeWebUsbTransport.markProtocolStale(path);
73
71
  });
74
72
  }
75
73
  class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
@@ -152,20 +150,23 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
152
150
  const devices = yield this.usb.getDevices();
153
151
  const onekeyDevices = devices.filter(dev => {
154
152
  const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
155
- const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
156
- return isOneKey && hasSerialNumber && !hdShared.isKnownTrezorWebUsbDevice(dev);
153
+ return isOneKey && !hdShared.isKnownTrezorWebUsbDevice(dev);
157
154
  });
158
- this.deviceList = onekeyDevices.map(device => {
159
- const path = device.serialNumber;
160
- const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
155
+ this.deviceList = onekeyDevices.flatMap(device => {
156
+ const path = hdShared.resolveOneKeyUsbDevicePath(device);
157
+ if (!path)
158
+ return [];
159
+ const protocolHint = hdShared.inferProtocolHintFromUsbId(device.vendorId, device.productId);
161
160
  if (protocolHint) {
162
161
  this.deviceProtocolHints.set(path, protocolHint);
163
162
  }
164
- return {
165
- path,
166
- device,
167
- commType: 'webusb',
168
- };
163
+ return [
164
+ {
165
+ path,
166
+ device,
167
+ commType: 'webusb',
168
+ },
169
+ ];
169
170
  });
170
171
  return this.deviceList;
171
172
  });
@@ -199,10 +200,10 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
199
200
  this.deviceProtocol.delete(input.path);
200
201
  }
201
202
  if (!this.deviceProtocol.has(input.path)) {
202
- const deviceName = (_c = this.deviceList.find(device => device.path === input.path)) === null || _c === void 0 ? void 0 : _c.device.productName;
203
+ const usbDevice = (_c = this.deviceList.find(device => device.path === input.path)) === null || _c === void 0 ? void 0 : _c.device;
203
204
  const protocolHint = input.expectedProtocol
204
205
  ? undefined
205
- : (_e = (_d = input.protocolHint) !== null && _d !== void 0 ? _d : this.deviceProtocolHints.get(input.path)) !== null && _e !== void 0 ? _e : inferProtocolHintFromDeviceName$1(deviceName);
206
+ : (_e = (_d = input.protocolHint) !== null && _d !== void 0 ? _d : this.deviceProtocolHints.get(input.path)) !== null && _e !== void 0 ? _e : hdShared.inferProtocolHintFromUsbId(usbDevice === null || usbDevice === void 0 ? void 0 : usbDevice.vendorId, usbDevice === null || usbDevice === void 0 ? void 0 : usbDevice.productId);
206
207
  if (protocolHint) {
207
208
  this.deviceProtocolHints.set(input.path, protocolHint);
208
209
  }
@@ -792,9 +793,6 @@ function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapa
792
793
  }
793
794
 
794
795
  const { parseConfigure, ProtocolV1, check } = transport__default["default"];
795
- function inferProtocolHintFromDeviceName(name) {
796
- return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
797
- }
798
796
  const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
799
797
  const BLE_PACKET_SIZE_FALLBACK = 192;
800
798
  const BLE_PACKET_SIZE_MAXIMUM = 244;
@@ -810,6 +808,8 @@ class ElectronBleTransport {
810
808
  this.connectedDevices = new Set();
811
809
  this.deviceProtocol = new Map();
812
810
  this.deviceProtocolHints = new Map();
811
+ this.confirmedProtocolV2 = new Set();
812
+ this.retryableV2Mismatch = new Set();
813
813
  this.deviceMtus = new Map();
814
814
  this.devicePacketCapacities = new Map();
815
815
  this.v1Buffers = new Map();
@@ -949,10 +949,6 @@ class ElectronBleTransport {
949
949
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
950
950
  for (const dev of devices) {
951
951
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
952
- const protocolHint = inferProtocolHintFromDeviceName(dev.name);
953
- if (protocolHint) {
954
- this.deviceProtocolHints.set(dev.id, protocolHint);
955
- }
956
952
  }
957
953
  return devices.map(device => toBleDescriptor(device));
958
954
  }
@@ -963,7 +959,7 @@ class ElectronBleTransport {
963
959
  });
964
960
  }
965
961
  acquire(input) {
966
- var _a, _b, _c, _d, _e, _f, _g, _h;
962
+ var _a, _b, _c, _d, _e, _f, _g;
967
963
  return __awaiter(this, void 0, void 0, function* () {
968
964
  const { uuid, forceCleanRunPromise, expectedProtocol } = input;
969
965
  if (!uuid) {
@@ -988,7 +984,7 @@ class ElectronBleTransport {
988
984
  }
989
985
  const protocolHint = expectedProtocol
990
986
  ? undefined
991
- : (_c = (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName(device.name);
987
+ : (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid);
992
988
  if (protocolHint) {
993
989
  this.deviceProtocolHints.set(uuid, protocolHint);
994
990
  }
@@ -1012,10 +1008,10 @@ class ElectronBleTransport {
1012
1008
  const connectionToken = this.notificationTokens.get(uuid);
1013
1009
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
1014
1010
  if (protocolType === 'V2') {
1015
- (_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[Electron BLE] Protocol V2 write configured', {
1011
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[Electron BLE] Protocol V2 write configured', {
1016
1012
  writeMode: 'withoutResponse',
1017
1013
  negotiatedMtu: this.deviceMtus.get(uuid),
1018
- packetCapacity: (_e = this.devicePacketCapacities.get(uuid)) !== null && _e !== void 0 ? _e : BLE_PACKET_SIZE_FALLBACK,
1014
+ packetCapacity: (_d = this.devicePacketCapacities.get(uuid)) !== null && _d !== void 0 ? _d : BLE_PACKET_SIZE_FALLBACK,
1019
1015
  });
1020
1016
  }
1021
1017
  const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
@@ -1034,15 +1030,15 @@ class ElectronBleTransport {
1034
1030
  return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
1035
1031
  }
1036
1032
  catch (error) {
1037
- (_f = this.Log) === null || _f === void 0 ? void 0 : _f.error('[Electron BLE] acquire failed:', error);
1033
+ (_e = this.Log) === null || _e === void 0 ? void 0 : _e.error('[Electron BLE] acquire failed:', error);
1038
1034
  try {
1039
- if (((_g = window.desktopApi) === null || _g === void 0 ? void 0 : _g.nobleBle) && this.connectedDevices.has(uuid)) {
1035
+ if (((_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle) && this.connectedDevices.has(uuid)) {
1040
1036
  yield window.desktopApi.nobleBle.unsubscribe(uuid);
1041
1037
  yield window.desktopApi.nobleBle.disconnect(uuid);
1042
1038
  }
1043
1039
  }
1044
1040
  catch (cleanupError) {
1045
- (_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
1041
+ (_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
1046
1042
  }
1047
1043
  this.cleanupDeviceState(uuid);
1048
1044
  throw error;
@@ -1109,8 +1105,16 @@ class ElectronBleTransport {
1109
1105
  }
1110
1106
  });
1111
1107
  }
1112
- createProtocolMismatchError(expected) {
1113
- return hdShared.ERRORS.TypedError(expected === 'V2' ? hdShared.HardwareErrorCode.BleDeviceBondError : hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
1108
+ createProtocolMismatchError(expected, uuid) {
1109
+ const isStaleV2Bond = expected === 'V2' &&
1110
+ (this.confirmedProtocolV2.has(uuid) || this.retryableV2Mismatch.has(uuid));
1111
+ if (expected === 'V2' && !isStaleV2Bond) {
1112
+ this.retryableV2Mismatch.add(uuid);
1113
+ }
1114
+ else if (isStaleV2Bond) {
1115
+ this.retryableV2Mismatch.delete(uuid);
1116
+ }
1117
+ return hdShared.ERRORS.TypedError(isStaleV2Bond ? hdShared.HardwareErrorCode.BleDeviceBondError : hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
1114
1118
  }
1115
1119
  createProtocolDetectionError() {
1116
1120
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
@@ -1129,15 +1133,17 @@ class ElectronBleTransport {
1129
1133
  (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V1 (expected)`);
1130
1134
  return 'V1';
1131
1135
  }
1132
- throw this.createProtocolMismatchError(expectedProtocol);
1136
+ throw this.createProtocolMismatchError(expectedProtocol, uuid);
1133
1137
  }
1134
1138
  if (expectedProtocol === 'V2') {
1135
1139
  if (yield this.probeProtocolV2(uuid)) {
1136
1140
  this.deviceProtocol.set(uuid, 'V2');
1141
+ this.confirmedProtocolV2.add(uuid);
1142
+ this.retryableV2Mismatch.delete(uuid);
1137
1143
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
1138
1144
  return 'V2';
1139
1145
  }
1140
- throw this.createProtocolMismatchError(expectedProtocol);
1146
+ throw this.createProtocolMismatchError(expectedProtocol, uuid);
1141
1147
  }
1142
1148
  const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1143
1149
  for (let i = 0; i < probeOrder.length; i += 1) {
@@ -1148,6 +1154,10 @@ class ElectronBleTransport {
1148
1154
  const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
1149
1155
  if (detected) {
1150
1156
  this.deviceProtocol.set(uuid, protocol);
1157
+ if (protocol === 'V2') {
1158
+ this.confirmedProtocolV2.add(uuid);
1159
+ this.retryableV2Mismatch.delete(uuid);
1160
+ }
1151
1161
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
1152
1162
  return protocol;
1153
1163
  }
@@ -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.143",
3
+ "version": "1.2.0-alpha.145",
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.143",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.143"
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.145",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.145"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.0-alpha.143",
28
+ "@onekeyfe/hd-transport-electron": "1.2.0-alpha.145",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "17a4c59d984da31727aaabc2d2e59d988ec9e734"
32
+ "gitHead": "9a136f881865c15e603ef271ae820c2b5a991dcc"
33
33
  }
@@ -51,10 +51,6 @@ interface PacketProcessResult {
51
51
  error?: string;
52
52
  }
53
53
 
54
- function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
55
- return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
56
- }
57
-
58
54
  const toBleDescriptor = (
59
55
  device: { id: string; name: string | null },
60
56
  protocolType?: ProtocolType
@@ -105,6 +101,12 @@ export default class ElectronBleTransport {
105
101
 
106
102
  private deviceProtocolHints: Map<string, ProtocolType> = new Map();
107
103
 
104
+ /** Endpoints that answered a V2 probe in this transport lifetime. Survives disconnect. */
105
+ private confirmedProtocolV2 = new Set<string>();
106
+
107
+ /** First expected-V2 miss for an unconfirmed endpoint; the next miss is a stale bond. */
108
+ private retryableV2Mismatch = new Set<string>();
109
+
108
110
  private deviceMtus: Map<string, number> = new Map();
109
111
 
110
112
  private devicePacketCapacities: Map<string, number> = new Map();
@@ -269,10 +271,6 @@ export default class ElectronBleTransport {
269
271
  this.Log?.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
270
272
  for (const dev of devices) {
271
273
  this.Log?.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
272
- const protocolHint = inferProtocolHintFromDeviceName(dev.name);
273
- if (protocolHint) {
274
- this.deviceProtocolHints.set(dev.id, protocolHint);
275
- }
276
274
  }
277
275
  return devices.map(device => toBleDescriptor(device));
278
276
  } catch (error) {
@@ -310,9 +308,7 @@ export default class ElectronBleTransport {
310
308
  }
311
309
  const protocolHint = expectedProtocol
312
310
  ? undefined
313
- : input.protocolHint ??
314
- this.deviceProtocolHints.get(uuid) ??
315
- inferProtocolHintFromDeviceName(device.name);
311
+ : input.protocolHint ?? this.deviceProtocolHints.get(uuid);
316
312
  if (protocolHint) {
317
313
  this.deviceProtocolHints.set(uuid, protocolHint);
318
314
  }
@@ -442,11 +438,20 @@ export default class ElectronBleTransport {
442
438
  }
443
439
  }
444
440
 
445
- private createProtocolMismatchError(expected: ProtocolType) {
446
- // A persisted V2 expectation means this endpoint answered a V2 probe before.
447
- // If it no longer answers after reconnect, the device-side bond was most likely reset.
441
+ private createProtocolMismatchError(expected: ProtocolType, uuid: string) {
442
+ // Caller `expectedProtocol: 'V2'` is not proof this endpoint already answered.
443
+ // A first-connect or flaky Ping must stay retryable. A later miss after a
444
+ // confirmed V2 answer, or a second miss on the same uuid, is a stale bond.
445
+ const isStaleV2Bond =
446
+ expected === 'V2' &&
447
+ (this.confirmedProtocolV2.has(uuid) || this.retryableV2Mismatch.has(uuid));
448
+ if (expected === 'V2' && !isStaleV2Bond) {
449
+ this.retryableV2Mismatch.add(uuid);
450
+ } else if (isStaleV2Bond) {
451
+ this.retryableV2Mismatch.delete(uuid);
452
+ }
448
453
  return ERRORS.TypedError(
449
- expected === 'V2' ? HardwareErrorCode.BleDeviceBondError : HardwareErrorCode.RuntimeError,
454
+ isStaleV2Bond ? HardwareErrorCode.BleDeviceBondError : HardwareErrorCode.RuntimeError,
450
455
  `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`
451
456
  );
452
457
  }
@@ -475,16 +480,18 @@ export default class ElectronBleTransport {
475
480
  this.Log?.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V1 (expected)`);
476
481
  return 'V1';
477
482
  }
478
- throw this.createProtocolMismatchError(expectedProtocol);
483
+ throw this.createProtocolMismatchError(expectedProtocol, uuid);
479
484
  }
480
485
 
481
486
  if (expectedProtocol === 'V2') {
482
487
  if (await this.probeProtocolV2(uuid)) {
483
488
  this.deviceProtocol.set(uuid, 'V2');
489
+ this.confirmedProtocolV2.add(uuid);
490
+ this.retryableV2Mismatch.delete(uuid);
484
491
  this.Log?.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
485
492
  return 'V2';
486
493
  }
487
- throw this.createProtocolMismatchError(expectedProtocol);
494
+ throw this.createProtocolMismatchError(expectedProtocol, uuid);
488
495
  }
489
496
 
490
497
  // Protocol must be actively probed after connection. Name, PID, and descriptors only
@@ -503,6 +510,10 @@ export default class ElectronBleTransport {
503
510
  protocol === 'V1' ? await this.probeProtocolV1(uuid) : await this.probeProtocolV2(uuid);
504
511
  if (detected) {
505
512
  this.deviceProtocol.set(uuid, protocol);
513
+ if (protocol === 'V2') {
514
+ this.confirmedProtocolV2.add(uuid);
515
+ this.retryableV2Mismatch.delete(uuid);
516
+ }
506
517
  this.Log?.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
507
518
  return protocol;
508
519
  }
package/src/webusb.ts CHANGED
@@ -14,7 +14,9 @@ import {
14
14
  ERRORS,
15
15
  HardwareErrorCode,
16
16
  ONEKEY_WEBUSB_FILTER,
17
+ inferProtocolHintFromUsbId,
17
18
  isKnownTrezorWebUsbDevice,
19
+ resolveOneKeyUsbDevicePath,
18
20
  wait,
19
21
  } from '@onekeyfe/hd-shared';
20
22
  import ByteBuffer from 'bytebuffer';
@@ -45,9 +47,6 @@ const PACKET_IO_RETRY_DELAY = 300;
45
47
  const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
46
48
  const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
47
49
  const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
48
- function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
49
- return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
50
- }
51
50
 
52
51
  /**
53
52
  * Device information with path and WebUSB device instance
@@ -84,9 +83,10 @@ function registerActiveWebUsbTransport(instance: WebUsbTransport, usb: USB) {
84
83
  if (usbDisconnectListenerAttached) return;
85
84
  usbDisconnectListenerAttached = true;
86
85
  usb.addEventListener('disconnect', event => {
87
- const serial = event.device?.serialNumber;
88
- if (typeof serial !== 'string' || serial.length === 0) return;
89
- activeWebUsbTransport?.markProtocolStale(serial);
86
+ if (!event.device) return;
87
+ const path = resolveOneKeyUsbDevicePath(event.device);
88
+ if (!path) return;
89
+ activeWebUsbTransport?.markProtocolStale(path);
90
90
  });
91
91
  }
92
92
 
@@ -256,22 +256,24 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
256
256
  (desc: { vendorId: number; productId: number }) =>
257
257
  dev.vendorId === desc.vendorId && dev.productId === desc.productId
258
258
  );
259
- const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
260
- return isOneKey && hasSerialNumber && !isKnownTrezorWebUsbDevice(dev);
259
+ return isOneKey && !isKnownTrezorWebUsbDevice(dev);
261
260
  });
262
261
 
263
- this.deviceList = onekeyDevices.map(device => {
264
- const path = device.serialNumber as string;
265
- const protocolHint = inferProtocolHintFromDeviceName(device.productName);
262
+ this.deviceList = onekeyDevices.flatMap(device => {
263
+ const path = resolveOneKeyUsbDevicePath(device);
264
+ if (!path) return [];
265
+ const protocolHint = inferProtocolHintFromUsbId(device.vendorId, device.productId);
266
266
  if (protocolHint) {
267
267
  this.deviceProtocolHints.set(path, protocolHint);
268
268
  }
269
269
 
270
- return {
271
- path,
272
- device,
273
- commType: 'webusb',
274
- };
270
+ return [
271
+ {
272
+ path,
273
+ device,
274
+ commType: 'webusb',
275
+ },
276
+ ];
275
277
  });
276
278
 
277
279
  return this.deviceList;
@@ -316,13 +318,12 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
316
318
  this.deviceProtocol.delete(input.path);
317
319
  }
318
320
  if (!this.deviceProtocol.has(input.path)) {
319
- const deviceName = this.deviceList.find(device => device.path === input.path)?.device
320
- .productName;
321
+ const usbDevice = this.deviceList.find(device => device.path === input.path)?.device;
321
322
  const protocolHint = input.expectedProtocol
322
323
  ? undefined
323
324
  : input.protocolHint ??
324
325
  this.deviceProtocolHints.get(input.path) ??
325
- inferProtocolHintFromDeviceName(deviceName);
326
+ inferProtocolHintFromUsbId(usbDevice?.vendorId, usbDevice?.productId);
326
327
  if (protocolHint) {
327
328
  this.deviceProtocolHints.set(input.path, protocolHint);
328
329
  }