@onekeyfe/hd-transport-web-device 1.2.0-alpha.22 → 1.2.0-alpha.23

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.
@@ -43,6 +43,38 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
43
43
  expect(webusb.deviceProtocol.get(path)).toBe('V2');
44
44
  });
45
45
 
46
+ test('retries an expected Protocol V2 probe once after resetting the connection', async () => {
47
+ const webusb = new WebUsbTransport() as any;
48
+ const path = 'pro2-webusb';
49
+ webusb.probeProtocolV1 = jest.fn();
50
+ webusb.probeProtocolV2 = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
51
+ webusb.resetConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
52
+
53
+ await expect(webusb.detectProtocol(path, 'V2')).resolves.toBe('V2');
54
+
55
+ expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(2);
56
+ expect(webusb.probeProtocolV1).not.toHaveBeenCalled();
57
+ expect(webusb.resetConnectionAfterProbe).toHaveBeenCalledTimes(1);
58
+ expect(webusb.deviceProtocol.get(path)).toBe('V2');
59
+ });
60
+
61
+ test('reports a Protocol V2 probe timeout only after the bounded retry is exhausted', async () => {
62
+ const webusb = new WebUsbTransport() as any;
63
+ const path = 'pro2-webusb';
64
+ webusb.probeProtocolV1 = jest.fn();
65
+ webusb.probeProtocolV2 = jest.fn().mockResolvedValue(false);
66
+ webusb.resetConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
67
+
68
+ await expect(webusb.detectProtocol(path, 'V2')).rejects.toThrow(
69
+ 'Protocol V2 probe timeout after 2 attempts'
70
+ );
71
+
72
+ expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(2);
73
+ expect(webusb.probeProtocolV1).not.toHaveBeenCalled();
74
+ expect(webusb.resetConnectionAfterProbe).toHaveBeenCalledTimes(2);
75
+ expect(webusb.deviceProtocol.has(path)).toBe(false);
76
+ });
77
+
46
78
  test('invalidates and resets the cached connection before another call can start', async () => {
47
79
  const webusb = new WebUsbTransport() as any;
48
80
  const path = 'pro2-webusb';
package/dist/index.d.ts CHANGED
@@ -88,6 +88,7 @@ declare class WebUsbTransport {
88
88
  * fall back to a Protocol V2 Ping probe.
89
89
  */
90
90
  private createProtocolMismatchError;
91
+ private createProtocolProbeTimeoutError;
91
92
  private createProtocolDetectionError;
92
93
  private detectProtocol;
93
94
  /**
package/dist/index.js CHANGED
@@ -60,6 +60,7 @@ const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
60
60
  const PACKET_IO_MAX_RETRIES = 3;
61
61
  const PACKET_IO_RETRY_DELAY = 300;
62
62
  const PROTOCOL_PROBE_TIMEOUT = 1000;
63
+ const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
63
64
  function inferProtocolHintFromDeviceName$1(name) {
64
65
  return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
65
66
  }
@@ -183,10 +184,14 @@ class WebUsbTransport {
183
184
  createProtocolMismatchError(expected) {
184
185
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
185
186
  }
187
+ createProtocolProbeTimeoutError(expected, attempts) {
188
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol ${expected} probe timeout after ${attempts} attempts`);
189
+ }
186
190
  createProtocolDetectionError() {
187
191
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
188
192
  }
189
193
  detectProtocol(path, expectedProtocol, protocolHint) {
194
+ var _a;
190
195
  return __awaiter(this, void 0, void 0, function* () {
191
196
  if (expectedProtocol === 'V1') {
192
197
  if (yield this.probeProtocolV1(path)) {
@@ -197,11 +202,18 @@ class WebUsbTransport {
197
202
  throw this.createProtocolMismatchError(expectedProtocol);
198
203
  }
199
204
  if (expectedProtocol === 'V2') {
200
- if (yield this.probeProtocolV2(path)) {
201
- this.deviceProtocol.set(path, 'V2');
202
- return 'V2';
205
+ for (let attempt = 1; attempt <= EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS; attempt += 1) {
206
+ if (yield this.probeProtocolV2(path)) {
207
+ this.deviceProtocol.set(path, 'V2');
208
+ return 'V2';
209
+ }
210
+ yield this.resetConnectionAfterProbe(path);
211
+ if (attempt < EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS) {
212
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 probe timed out, retrying ${attempt + 1}/${EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS}`);
213
+ }
203
214
  }
204
- throw this.createProtocolMismatchError(expectedProtocol);
215
+ this.deviceProtocol.delete(path);
216
+ throw this.createProtocolProbeTimeoutError(expectedProtocol, EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS);
205
217
  }
206
218
  const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
207
219
  for (const protocol of probeOrder) {
@@ -210,9 +222,7 @@ class WebUsbTransport {
210
222
  this.deviceProtocol.set(path, protocol);
211
223
  return protocol;
212
224
  }
213
- if (protocol === 'V1') {
214
- yield this.resetConnectionAfterProbe(path);
215
- }
225
+ yield this.resetConnectionAfterProbe(path);
216
226
  }
217
227
  this.deviceProtocol.delete(path);
218
228
  throw this.createProtocolDetectionError();
@@ -574,7 +584,7 @@ class WebUsbTransport {
574
584
  return false;
575
585
  }
576
586
  return transport.probeProtocolV2({
577
- call: (name, data, options) => this.callProtocolV2(path, name, data, options),
587
+ call: (name, data, options) => this.callProtocolV2(path, name, data, options, false),
578
588
  timeoutMs: PROTOCOL_PROBE_TIMEOUT,
579
589
  logger: this.Log,
580
590
  logPrefix: 'ProtocolV2 WebUSB',
@@ -624,7 +634,7 @@ class WebUsbTransport {
624
634
  return check$1.call(jsonData);
625
635
  });
626
636
  }
627
- callProtocolV2(path, name, data, options) {
637
+ callProtocolV2(path, name, data, options, resetOnError = true) {
628
638
  return __awaiter(this, void 0, void 0, function* () {
629
639
  const protocolV1Messages = this.messages;
630
640
  if (!this.messagesV2) {
@@ -659,7 +669,7 @@ class WebUsbTransport {
659
669
  return yield session.call(name, data, options);
660
670
  }
661
671
  catch (error) {
662
- if (transport.isProtocolV2LinkError(error) || this.isRetryablePacketIoError(error)) {
672
+ if (resetOnError && (transport.isProtocolV2LinkError(error) || this.isRetryablePacketIoError(error))) {
663
673
  try {
664
674
  yield this.resetConnectionAfterProbe(path);
665
675
  }
package/dist/webusb.d.ts CHANGED
@@ -35,6 +35,7 @@ export default class WebUsbTransport {
35
35
  getConnectedDevices(): Promise<DeviceInfo[]>;
36
36
  acquire(input: AcquireInput): Promise<string | undefined>;
37
37
  private createProtocolMismatchError;
38
+ private createProtocolProbeTimeoutError;
38
39
  private createProtocolDetectionError;
39
40
  private detectProtocol;
40
41
  findDevice(path: string): Promise<USBDevice>;
@@ -1 +1 @@
1
- {"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAaN,MAAM,wBAAwB,CAAC;AAYhC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAqBhC,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAaD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGpE,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,kBAAkB,CAA6C;IAGvE,OAAO,CAAC,mBAAmB,CAAoD;IAG/E,OAAO,CAAC,eAAe,CAA2C;IAMlE,OAAO,CAAC,eAAe,CAA6C;IAEpE,OAAO,CAAC,iBAAiB,CAAK;IAE9B,IAAI,SAAqB;IAEzB,OAAO,UAAS;IAEhB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,GAAG,CAAC,EAAE,GAAG,CAAC;IAMV,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAM;IAEnC,eAAe,SAAoB;IAEnC,UAAU,SAAe;IAEzB,WAAW,SAAgB;IAK3B,IAAI,CAAC,MAAM,EAAE,GAAG;IAgBhB,SAAS,CAAC,UAAU,EAAE,GAAG;IASzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAU7B,kBAAkB;IAmBlB,SAAS;IAQf,OAAO,CAAC,aAAa;IAmBf,mBAAmB;IAgCnB,OAAO,CAAC,KAAK,EAAE,YAAY;IA0BjC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;IAiDtB,UAAU,CAAC,IAAI,EAAE,MAAM;IAwBvB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;IAkB1C,OAAO,CAAC,iBAAiB;IAiCnB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;YAmCpC,eAAe;YAmBf,iBAAiB;IAezB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIvE,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,wBAAwB;YAalB,yBAAyB;IAiCvC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;YASP,oBAAoB;YA2BpB,eAAe;YAaf,mBAAmB;YA2CnB,yBAAyB;YAwBzB,uBAAuB;YA0CvB,eAAe;YAaf,eAAe;IAgBvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA8BlB,cAAc;YAkCd,cAAc;YA0Dd,sBAAsB;IAqC9B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAgD5C,OAAO,CAAC,IAAI,EAAE,MAAM;IAkB1B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
1
+ {"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAaN,MAAM,wBAAwB,CAAC;AAYhC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAsBhC,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAaD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGpE,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,kBAAkB,CAA6C;IAGvE,OAAO,CAAC,mBAAmB,CAAoD;IAG/E,OAAO,CAAC,eAAe,CAA2C;IAMlE,OAAO,CAAC,eAAe,CAA6C;IAEpE,OAAO,CAAC,iBAAiB,CAAK;IAE9B,IAAI,SAAqB;IAEzB,OAAO,UAAS;IAEhB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,GAAG,CAAC,EAAE,GAAG,CAAC;IAMV,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAM;IAEnC,eAAe,SAAoB;IAEnC,UAAU,SAAe;IAEzB,WAAW,SAAgB;IAK3B,IAAI,CAAC,MAAM,EAAE,GAAG;IAgBhB,SAAS,CAAC,UAAU,EAAE,GAAG;IASzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAU7B,kBAAkB;IAmBlB,SAAS;IAQf,OAAO,CAAC,aAAa;IAmBf,mBAAmB;IAgCnB,OAAO,CAAC,KAAK,EAAE,YAAY;IA0BjC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,+BAA+B;IAOvC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;IA6DtB,UAAU,CAAC,IAAI,EAAE,MAAM;IAwBvB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;IAkB1C,OAAO,CAAC,iBAAiB;IAiCnB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;YAmCpC,eAAe;YAmBf,iBAAiB;IAezB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIvE,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,wBAAwB;YAalB,yBAAyB;IAiCvC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;YASP,oBAAoB;YA2BpB,eAAe;YAaf,mBAAmB;YA2CnB,yBAAyB;YAwBzB,uBAAuB;YA0CvB,eAAe;YAaf,eAAe;IAgBvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA8BlB,cAAc;YAkCd,cAAc;YA2Dd,sBAAsB;IAqC9B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAgD5C,OAAO,CAAC,IAAI,EAAE,MAAM;IAkB1B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-web-device",
3
- "version": "1.2.0-alpha.22",
3
+ "version": "1.2.0-alpha.23",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -20,13 +20,13 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-shared": "1.2.0-alpha.22",
24
- "@onekeyfe/hd-transport": "1.2.0-alpha.22"
23
+ "@onekeyfe/hd-shared": "1.2.0-alpha.23",
24
+ "@onekeyfe/hd-transport": "1.2.0-alpha.23"
25
25
  },
26
26
  "devDependencies": {
27
- "@onekeyfe/hd-transport-electron": "1.2.0-alpha.22",
27
+ "@onekeyfe/hd-transport-electron": "1.2.0-alpha.23",
28
28
  "@types/w3c-web-usb": "^1.0.6",
29
29
  "@types/web-bluetooth": "^0.0.17"
30
30
  },
31
- "gitHead": "ce94a5ebbe141b0c15db7c68d08085ca1ddb0166"
31
+ "gitHead": "7cadb40ca6414053a488756f28a9f413164b235d"
32
32
  }
package/src/webusb.ts CHANGED
@@ -43,6 +43,7 @@ const HEADER_LENGTH = PROTOCOL_V1_MESSAGE_HEADER_SIZE;
43
43
  const PACKET_IO_MAX_RETRIES = 3;
44
44
  const PACKET_IO_RETRY_DELAY = 300;
45
45
  const PROTOCOL_PROBE_TIMEOUT = 1000;
46
+ const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
46
47
  function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
47
48
  return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
48
49
  }
@@ -269,6 +270,13 @@ export default class WebUsbTransport {
269
270
  );
270
271
  }
271
272
 
273
+ private createProtocolProbeTimeoutError(expected: ProtocolType, attempts: number) {
274
+ return ERRORS.TypedError(
275
+ HardwareErrorCode.RuntimeError,
276
+ `Protocol ${expected} probe timeout after ${attempts} attempts`
277
+ );
278
+ }
279
+
272
280
  private createProtocolDetectionError() {
273
281
  return ERRORS.TypedError(
274
282
  HardwareErrorCode.RuntimeError,
@@ -291,11 +299,25 @@ export default class WebUsbTransport {
291
299
  }
292
300
 
293
301
  if (expectedProtocol === 'V2') {
294
- if (await this.probeProtocolV2(path)) {
295
- this.deviceProtocol.set(path, 'V2');
296
- return 'V2';
302
+ for (let attempt = 1; attempt <= EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS; attempt += 1) {
303
+ if (await this.probeProtocolV2(path)) {
304
+ this.deviceProtocol.set(path, 'V2');
305
+ return 'V2';
306
+ }
307
+ await this.resetConnectionAfterProbe(path);
308
+ if (attempt < EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS) {
309
+ this.Log?.debug(
310
+ `[WebUsbTransport] Protocol V2 probe timed out, retrying ${
311
+ attempt + 1
312
+ }/${EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS}`
313
+ );
314
+ }
297
315
  }
298
- throw this.createProtocolMismatchError(expectedProtocol);
316
+ this.deviceProtocol.delete(path);
317
+ throw this.createProtocolProbeTimeoutError(
318
+ expectedProtocol,
319
+ EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS
320
+ );
299
321
  }
300
322
 
301
323
  // Protocol must be actively probed after connection. Name, PID, and descriptors only
@@ -310,12 +332,10 @@ export default class WebUsbTransport {
310
332
  this.deviceProtocol.set(path, protocol);
311
333
  return protocol;
312
334
  }
313
- if (protocol === 'V1') {
314
- // A timed-out WebUSB transferIn cannot be cancelled in place. Closing and
315
- // reopening the device guarantees the next protocol probe cannot consume a
316
- // late V1 response. V2 timeout recovery is owned by callProtocolV2.
317
- await this.resetConnectionAfterProbe(path);
318
- }
335
+ // A timed-out WebUSB transferIn cannot be cancelled in place. Closing and
336
+ // reopening the device guarantees the next protocol probe cannot consume a
337
+ // late response from the previous protocol generation.
338
+ await this.resetConnectionAfterProbe(path);
319
339
  }
320
340
 
321
341
  this.deviceProtocol.delete(path);
@@ -716,7 +736,7 @@ export default class WebUsbTransport {
716
736
  }
717
737
 
718
738
  return probeProtocolV2Helper({
719
- call: (name, data, options) => this.callProtocolV2(path, name, data, options),
739
+ call: (name, data, options) => this.callProtocolV2(path, name, data, options, false),
720
740
  timeoutMs: PROTOCOL_PROBE_TIMEOUT,
721
741
  logger: this.Log,
722
742
  logPrefix: 'ProtocolV2 WebUSB',
@@ -798,7 +818,8 @@ export default class WebUsbTransport {
798
818
  path: string,
799
819
  name: string,
800
820
  data: Record<string, unknown>,
801
- options?: TransportCallOptions
821
+ options?: TransportCallOptions,
822
+ resetOnError = true
802
823
  ) {
803
824
  const protocolV1Messages = this.messages;
804
825
  if (!this.messagesV2) {
@@ -841,7 +862,7 @@ export default class WebUsbTransport {
841
862
  try {
842
863
  return await session.call(name, data, options);
843
864
  } catch (error) {
844
- if (isProtocolV2LinkError(error) || this.isRetryablePacketIoError(error)) {
865
+ if (resetOnError && (isProtocolV2LinkError(error) || this.isRetryablePacketIoError(error))) {
845
866
  try {
846
867
  await this.resetConnectionAfterProbe(path);
847
868
  } catch (resetError) {