@onekeyfe/hd-transport-web-device 1.2.3-alpha.4 → 1.2.3-alpha.5

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.
@@ -64,6 +64,54 @@ describe('WebUsbTransport protocol probe cache', () => {
64
64
  }
65
65
  );
66
66
 
67
+ test('reports claimInterface failures as WebUSB device access errors', async () => {
68
+ const webusb = new WebUsbTransport();
69
+ const path = 'connected-usb-device';
70
+ const claimError = Object.assign(new Error('Unable to claim interface'), {
71
+ name: 'NetworkError',
72
+ });
73
+ const device = {
74
+ opened: true,
75
+ configuration: { configurationValue: 1 },
76
+ configurations: [],
77
+ claimInterface: jest.fn().mockRejectedValue(claimError),
78
+ };
79
+ jest.spyOn(webusb, 'findDevice').mockResolvedValue(device as unknown as USBDevice);
80
+ jest.spyOn(webusb, 'getConnectedDevices').mockResolvedValue([]);
81
+ const state = webusb as unknown as { deviceProtocol: Map<string, 'V1' | 'V2'> };
82
+ state.deviceProtocol.set(path, 'V1');
83
+
84
+ await expect(webusb.connectToDevice(path, false)).rejects.toMatchObject({
85
+ errorCode: HardwareErrorCode.WebUsbDeviceAccessError,
86
+ params: {
87
+ operation: 'claimInterface',
88
+ nativeErrorName: 'NetworkError',
89
+ nativeErrorMessage: 'Unable to claim interface',
90
+ },
91
+ });
92
+ });
93
+
94
+ test('reports transferIn failures as WebUSB device access errors', async () => {
95
+ const webusb = new WebUsbTransport() as any;
96
+ const path = 'connected-usb-device';
97
+ const transferError = Object.assign(new Error('Transfer endpoint is unavailable'), {
98
+ name: 'NetworkError',
99
+ });
100
+ webusb.findDevice = jest.fn().mockResolvedValue({
101
+ opened: true,
102
+ transferIn: jest.fn().mockRejectedValue(transferError),
103
+ });
104
+
105
+ await expect(webusb.transferInWithRetry(path, 64)).rejects.toMatchObject({
106
+ errorCode: HardwareErrorCode.WebUsbDeviceAccessError,
107
+ params: {
108
+ operation: 'transferIn',
109
+ nativeErrorName: 'NetworkError',
110
+ nativeErrorMessage: 'Transfer endpoint is unavailable',
111
+ },
112
+ });
113
+ });
114
+
67
115
  test('acquire skips the wire probe when the protocol is already cached', async () => {
68
116
  const webusb = buildAcquirableTransport();
69
117
  const path = 'pro-webusb';
@@ -238,9 +238,15 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
238
238
  webusb.resetConnectionAfterProbe = jest.fn();
239
239
  await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
240
240
 
241
- await expect(webusb.callProtocolV2(path, 'Ping', { message: 'read-error' })).rejects.toThrow(
242
- 'NetworkError'
243
- );
241
+ await expect(
242
+ webusb.callProtocolV2(path, 'Ping', { message: 'read-error' })
243
+ ).rejects.toMatchObject({
244
+ errorCode: HardwareErrorCode.BridgeDeviceDisconnected,
245
+ params: {
246
+ operation: 'transferIn',
247
+ nativeErrorMessage: 'NetworkError: transferIn device disconnected',
248
+ },
249
+ });
244
250
 
245
251
  expect(webusb.readProtocolV2UsbPacket).toHaveBeenCalledTimes(1);
246
252
  expect(webusb.resetProtocolV2UsbNativeLink).toHaveBeenCalledWith(
package/dist/index.d.ts CHANGED
@@ -118,7 +118,7 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
118
118
  /**
119
119
  * Connect to device with retry mechanism
120
120
  */
121
- connect(path: string, first: boolean): Promise<void>;
121
+ connect(path: string, first: boolean): Promise<undefined>;
122
122
  /**
123
123
  * Discover vendor-class (0xFF) interface and its IN/OUT endpoint numbers from USB descriptors.
124
124
  * Falls back to legacy hardcoded values if no vendor interface is found.
@@ -128,7 +128,7 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
128
128
  * Connect to specific device.
129
129
  * Discovers interface/endpoint numbers from USB descriptors on first connection.
130
130
  */
131
- connectToDevice(path: string, first: boolean): Promise<void>;
131
+ connectToDevice(path: string, first: boolean): Promise<undefined>;
132
132
  private closeOpenDevice;
133
133
  private clearEndpointHalt;
134
134
  /**
@@ -141,6 +141,10 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
141
141
  private assertAcquired;
142
142
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
143
143
  private getErrorMessage;
144
+ private getErrorName;
145
+ private isWebUsbIoHardwareError;
146
+ private isDeviceStillEnumerated;
147
+ private throwWebUsbIoError;
144
148
  private isRetryablePacketIoError;
145
149
  private reconnectForPacketIoRetry;
146
150
  private getTransferInData;
package/dist/index.js CHANGED
@@ -395,7 +395,12 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
395
395
  }
396
396
  const endpoints = this.discoverEndpoints(device);
397
397
  this.deviceEndpoints.set(path, endpoints);
398
- yield device.claimInterface(endpoints.interfaceNumber);
398
+ try {
399
+ yield device.claimInterface(endpoints.interfaceNumber);
400
+ }
401
+ catch (error) {
402
+ return this.throwWebUsbIoError(path, 'claimInterface', error);
403
+ }
399
404
  yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
400
405
  yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
401
406
  });
@@ -459,6 +464,59 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
459
464
  }
460
465
  return String(error);
461
466
  }
467
+ getErrorName(error) {
468
+ if (typeof error === 'object' && error && 'name' in error) {
469
+ const { name } = error;
470
+ return typeof name === 'string' ? name : String(name !== null && name !== void 0 ? name : '');
471
+ }
472
+ return '';
473
+ }
474
+ isWebUsbIoHardwareError(error) {
475
+ return (error instanceof hdShared.HardwareError &&
476
+ (error.errorCode === hdShared.HardwareErrorCode.BridgeDeviceDisconnected ||
477
+ error.errorCode === hdShared.HardwareErrorCode.WebUsbDeviceAccessError));
478
+ }
479
+ isDeviceStillEnumerated(path) {
480
+ var _a;
481
+ return __awaiter(this, void 0, void 0, function* () {
482
+ if (!this.usb)
483
+ return undefined;
484
+ try {
485
+ const devices = yield this.usb.getDevices();
486
+ return devices.some(device => hdShared.resolveOneKeyUsbDevicePath(device) === path);
487
+ }
488
+ catch (error) {
489
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] failed to verify WebUSB device presence:', error);
490
+ return undefined;
491
+ }
492
+ });
493
+ }
494
+ throwWebUsbIoError(path, operation, error) {
495
+ var _a;
496
+ return __awaiter(this, void 0, void 0, function* () {
497
+ if (this.isWebUsbIoHardwareError(error))
498
+ throw error;
499
+ if (error instanceof transport.ProtocolV2LinkError && error.code !== 'io')
500
+ throw error;
501
+ const nativeError = error instanceof transport.ProtocolV2LinkError ? (_a = error.cause) !== null && _a !== void 0 ? _a : error : error;
502
+ if (this.isWebUsbIoHardwareError(nativeError))
503
+ throw nativeError;
504
+ const nativeErrorName = this.getErrorName(nativeError);
505
+ const nativeErrorMessage = this.getErrorMessage(nativeError);
506
+ const disconnectedByMessage = /(?:device )?disconnected|device not found|action was interrupted/i.test(`${nativeErrorName}: ${nativeErrorMessage}`);
507
+ const stillEnumerated = disconnectedByMessage
508
+ ? false
509
+ : yield this.isDeviceStillEnumerated(path);
510
+ const errorCode = disconnectedByMessage || stillEnumerated === false
511
+ ? hdShared.HardwareErrorCode.BridgeDeviceDisconnected
512
+ : hdShared.HardwareErrorCode.WebUsbDeviceAccessError;
513
+ throw hdShared.ERRORS.TypedError(errorCode, nativeErrorMessage || undefined, {
514
+ operation,
515
+ nativeErrorName: nativeErrorName || undefined,
516
+ nativeErrorMessage: nativeErrorMessage || undefined,
517
+ });
518
+ });
519
+ }
462
520
  isRetryablePacketIoError(error) {
463
521
  const message = this.getErrorMessage(error).toLowerCase();
464
522
  return (message.includes('transferout') ||
@@ -525,7 +583,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
525
583
  lastError = error;
526
584
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
527
585
  if (!shouldRetry) {
528
- throw error;
586
+ return this.throwWebUsbIoError(path, 'transferOut', error);
529
587
  }
530
588
  try {
531
589
  yield this.reconnectForPacketIoRetry(path, 'out', attempt, error);
@@ -536,7 +594,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
536
594
  }
537
595
  }
538
596
  }
539
- throw lastError;
597
+ return this.throwWebUsbIoError(path, 'transferOut', lastError);
540
598
  });
541
599
  }
542
600
  transferOutOnce(path, packet) {
@@ -577,7 +635,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
577
635
  }
578
636
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
579
637
  if (!shouldRetry) {
580
- throw error;
638
+ return this.throwWebUsbIoError(path, 'transferIn', error);
581
639
  }
582
640
  try {
583
641
  yield this.reconnectForPacketIoRetry(path, 'in', attempt, error);
@@ -588,7 +646,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
588
646
  }
589
647
  }
590
648
  }
591
- throw lastError;
649
+ return this.throwWebUsbIoError(path, 'transferIn', lastError);
592
650
  });
593
651
  }
594
652
  transferInOnce(path, length) {
@@ -665,7 +723,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
665
723
  });
666
724
  return true;
667
725
  }
668
- catch (_error) {
726
+ catch (error) {
727
+ if (this.isWebUsbIoHardwareError(error))
728
+ throw error;
669
729
  return false;
670
730
  }
671
731
  });
@@ -680,6 +740,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
680
740
  timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT,
681
741
  logger: this.Log,
682
742
  logPrefix: 'ProtocolV2 WebUSB',
743
+ shouldRethrow: error => this.isWebUsbIoHardwareError(error),
683
744
  });
684
745
  });
685
746
  }
@@ -726,7 +787,15 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
726
787
  }
727
788
  callProtocolV2(path, name, data, options) {
728
789
  return __awaiter(this, void 0, void 0, function* () {
729
- return this.callProtocolV2Usb(path, name, data, options);
790
+ try {
791
+ return yield this.callProtocolV2Usb(path, name, data, options);
792
+ }
793
+ catch (error) {
794
+ if (!(error instanceof transport.ProtocolV2LinkError) || error.code !== 'io')
795
+ throw error;
796
+ const operation = error.message.includes(' USB write failed:') ? 'transferOut' : 'transferIn';
797
+ return this.throwWebUsbIoError(path, operation, error);
798
+ }
730
799
  });
731
800
  }
732
801
  receiveData(path, timeoutMs) {
package/dist/webusb.d.ts CHANGED
@@ -44,14 +44,18 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
44
44
  private createProtocolDetectionError;
45
45
  private detectProtocol;
46
46
  findDevice(path: string): Promise<USBDevice>;
47
- connect(path: string, first: boolean): Promise<void>;
47
+ connect(path: string, first: boolean): Promise<undefined>;
48
48
  private discoverEndpoints;
49
- connectToDevice(path: string, first: boolean): Promise<void>;
49
+ connectToDevice(path: string, first: boolean): Promise<undefined>;
50
50
  private closeOpenDevice;
51
51
  private clearEndpointHalt;
52
52
  private assertAcquired;
53
53
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
54
54
  private getErrorMessage;
55
+ private getErrorName;
56
+ private isWebUsbIoHardwareError;
57
+ private isDeviceStillEnumerated;
58
+ private throwWebUsbIoError;
55
59
  private isRetryablePacketIoError;
56
60
  private reconnectForPacketIoRetry;
57
61
  private getTransferInData;
@@ -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.3-alpha.4",
3
+ "version": "1.2.3-alpha.5",
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.3-alpha.4",
25
- "@onekeyfe/hd-transport": "1.2.3-alpha.4"
24
+ "@onekeyfe/hd-shared": "1.2.3-alpha.5",
25
+ "@onekeyfe/hd-transport": "1.2.3-alpha.5"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.3-alpha.4",
28
+ "@onekeyfe/hd-transport-electron": "1.2.3-alpha.5",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "705729baaec54b86a4fc28cce310a85b67b82730"
32
+ "gitHead": "ee493c3ad41a6bc7fb249fba71d4b9bf8efcced8"
33
33
  }
package/src/webusb.ts CHANGED
@@ -13,6 +13,7 @@ import transport, {
13
13
  } from '@onekeyfe/hd-transport';
14
14
  import {
15
15
  ERRORS,
16
+ HardwareError,
16
17
  HardwareErrorCode,
17
18
  ONEKEY_WEBUSB_FILTER,
18
19
  inferProtocolHintFromUsbId,
@@ -70,6 +71,8 @@ interface TransferCancelToken {
70
71
  cancelled: boolean;
71
72
  }
72
73
 
74
+ type WebUsbOperation = 'claimInterface' | 'transferIn' | 'transferOut';
75
+
73
76
  /**
74
77
  * The navigator.usb disconnect listener is module-scoped and attached at most
75
78
  * once: listeners on navigator.usb are global and never garbage collected, so a
@@ -592,7 +595,11 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
592
595
  // Discover endpoints from USB descriptors; descriptors are not used for protocol selection.
593
596
  const endpoints = this.discoverEndpoints(device);
594
597
  this.deviceEndpoints.set(path, endpoints);
595
- await device.claimInterface(endpoints.interfaceNumber);
598
+ try {
599
+ await device.claimInterface(endpoints.interfaceNumber);
600
+ } catch (error) {
601
+ return this.throwWebUsbIoError(path, 'claimInterface', error);
602
+ }
596
603
  await this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
597
604
  await this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
598
605
  }
@@ -662,6 +669,65 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
662
669
  return String(error);
663
670
  }
664
671
 
672
+ private getErrorName(error: unknown) {
673
+ if (typeof error === 'object' && error && 'name' in error) {
674
+ const { name } = error as { name?: unknown };
675
+ return typeof name === 'string' ? name : String(name ?? '');
676
+ }
677
+ return '';
678
+ }
679
+
680
+ private isWebUsbIoHardwareError(error: unknown): error is HardwareError {
681
+ return (
682
+ error instanceof HardwareError &&
683
+ (error.errorCode === HardwareErrorCode.BridgeDeviceDisconnected ||
684
+ error.errorCode === HardwareErrorCode.WebUsbDeviceAccessError)
685
+ );
686
+ }
687
+
688
+ private async isDeviceStillEnumerated(path: string): Promise<boolean | undefined> {
689
+ if (!this.usb) return undefined;
690
+ try {
691
+ const devices = await this.usb.getDevices();
692
+ return devices.some(device => resolveOneKeyUsbDevicePath(device) === path);
693
+ } catch (error) {
694
+ this.Log?.debug('[WebUsbTransport] failed to verify WebUSB device presence:', error);
695
+ return undefined;
696
+ }
697
+ }
698
+
699
+ private async throwWebUsbIoError(
700
+ path: string,
701
+ operation: WebUsbOperation,
702
+ error: unknown
703
+ ): Promise<never> {
704
+ if (this.isWebUsbIoHardwareError(error)) throw error;
705
+ if (error instanceof ProtocolV2LinkError && error.code !== 'io') throw error;
706
+
707
+ const nativeError = error instanceof ProtocolV2LinkError ? error.cause ?? error : error;
708
+ if (this.isWebUsbIoHardwareError(nativeError)) throw nativeError;
709
+
710
+ const nativeErrorName = this.getErrorName(nativeError);
711
+ const nativeErrorMessage = this.getErrorMessage(nativeError);
712
+ const disconnectedByMessage =
713
+ /(?:device )?disconnected|device not found|action was interrupted/i.test(
714
+ `${nativeErrorName}: ${nativeErrorMessage}`
715
+ );
716
+ const stillEnumerated = disconnectedByMessage
717
+ ? false
718
+ : await this.isDeviceStillEnumerated(path);
719
+ const errorCode =
720
+ disconnectedByMessage || stillEnumerated === false
721
+ ? HardwareErrorCode.BridgeDeviceDisconnected
722
+ : HardwareErrorCode.WebUsbDeviceAccessError;
723
+
724
+ throw ERRORS.TypedError(errorCode, nativeErrorMessage || undefined, {
725
+ operation,
726
+ nativeErrorName: nativeErrorName || undefined,
727
+ nativeErrorMessage: nativeErrorMessage || undefined,
728
+ });
729
+ }
730
+
665
731
  private isRetryablePacketIoError(error: unknown) {
666
732
  const message = this.getErrorMessage(error).toLowerCase();
667
733
  return (
@@ -742,7 +808,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
742
808
  lastError = error;
743
809
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
744
810
  if (!shouldRetry) {
745
- throw error;
811
+ return this.throwWebUsbIoError(path, 'transferOut', error);
746
812
  }
747
813
  try {
748
814
  await this.reconnectForPacketIoRetry(path, 'out', attempt, error);
@@ -756,7 +822,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
756
822
  }
757
823
  }
758
824
  }
759
- throw lastError;
825
+ return this.throwWebUsbIoError(path, 'transferOut', lastError);
760
826
  }
761
827
 
762
828
  private async transferOutOnce(path: string, packet: Uint8Array) {
@@ -798,7 +864,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
798
864
  }
799
865
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
800
866
  if (!shouldRetry) {
801
- throw error;
867
+ return this.throwWebUsbIoError(path, 'transferIn', error);
802
868
  }
803
869
  try {
804
870
  await this.reconnectForPacketIoRetry(path, 'in', attempt, error);
@@ -812,7 +878,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
812
878
  }
813
879
  }
814
880
  }
815
- throw lastError;
881
+ return this.throwWebUsbIoError(path, 'transferIn', lastError);
816
882
  }
817
883
 
818
884
  private async transferInOnce(path: string, length: number): Promise<DataView> {
@@ -894,7 +960,8 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
894
960
  }
895
961
  );
896
962
  return true;
897
- } catch (_error) {
963
+ } catch (error) {
964
+ if (this.isWebUsbIoHardwareError(error)) throw error;
898
965
  return false;
899
966
  }
900
967
  }
@@ -909,6 +976,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
909
976
  timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT,
910
977
  logger: this.Log,
911
978
  logPrefix: 'ProtocolV2 WebUSB',
979
+ shouldRethrow: error => this.isWebUsbIoHardwareError(error),
912
980
  });
913
981
  }
914
982
 
@@ -986,7 +1054,13 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
986
1054
  data: Record<string, unknown>,
987
1055
  options?: TransportCallOptions
988
1056
  ) {
989
- return this.callProtocolV2Usb(path, name, data, options);
1057
+ try {
1058
+ return await this.callProtocolV2Usb(path, name, data, options);
1059
+ } catch (error) {
1060
+ if (!(error instanceof ProtocolV2LinkError) || error.code !== 'io') throw error;
1061
+ const operation = error.message.includes(' USB write failed:') ? 'transferOut' : 'transferIn';
1062
+ return this.throwWebUsbIoError(path, operation, error);
1063
+ }
990
1064
  }
991
1065
 
992
1066
  /**