@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.
- package/__tests__/webusb-protocol-v2-timeout.test.ts +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +20 -10
- package/dist/webusb.d.ts +1 -0
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/webusb.ts +34 -13
|
@@ -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
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
|
-
|
|
201
|
-
this.
|
|
202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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>;
|
package/dist/webusb.d.ts.map
CHANGED
|
@@ -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;
|
|
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.
|
|
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.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
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.
|
|
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": "
|
|
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
|
-
|
|
295
|
-
this.
|
|
296
|
-
|
|
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
|
-
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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) {
|