@onekeyfe/hd-transport-web-device 1.2.8-alpha.13 → 1.2.8-alpha.131
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__/electron-ble-transport.test.ts +228 -7
- package/__tests__/webusb-identity-probe.test.ts +935 -0
- package/__tests__/webusb-protocol-cache.test.ts +301 -1
- package/__tests__/webusb-protocol-v2-timeout.test.ts +18 -5
- package/dist/electron-ble-transport.d.ts +4 -1
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +41 -4
- package/dist/index.js +688 -68
- package/dist/webusb.d.ts +38 -3
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/electron-ble-transport.ts +58 -18
- package/src/webusb.ts +758 -52
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import transport from '@onekeyfe/hd-transport';
|
|
2
|
-
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
3
|
|
|
4
4
|
import WebUsbTransport from '../src/webusb';
|
|
5
5
|
|
|
@@ -64,6 +64,157 @@ describe('WebUsbTransport protocol probe cache', () => {
|
|
|
64
64
|
}
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
+
test.each([undefined, 2, 1])(
|
|
68
|
+
'configures a replacement V1 handle only when needed during packet recovery: %s',
|
|
69
|
+
async configurationValue => {
|
|
70
|
+
const webusb = new WebUsbTransport();
|
|
71
|
+
const path = 'replacement-v1-device';
|
|
72
|
+
const state = webusb as unknown as {
|
|
73
|
+
Log: { debug: jest.Mock };
|
|
74
|
+
deviceProtocol: Map<string, 'V1' | 'V2'>;
|
|
75
|
+
reconnectForPacketIoRetry: (
|
|
76
|
+
path: string,
|
|
77
|
+
direction: 'in' | 'out',
|
|
78
|
+
attempt: number,
|
|
79
|
+
error: unknown
|
|
80
|
+
) => Promise<void>;
|
|
81
|
+
};
|
|
82
|
+
state.Log = { debug: jest.fn() };
|
|
83
|
+
state.deviceProtocol.set(path, 'V1');
|
|
84
|
+
const replacement = {
|
|
85
|
+
opened: false,
|
|
86
|
+
configuration: configurationValue ? { configurationValue } : undefined,
|
|
87
|
+
configurations: [],
|
|
88
|
+
open: jest.fn().mockImplementation(() => {
|
|
89
|
+
replacement.opened = true;
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
}),
|
|
92
|
+
selectConfiguration: jest.fn().mockImplementation((value: number) => {
|
|
93
|
+
replacement.configuration = { configurationValue: value };
|
|
94
|
+
return Promise.resolve();
|
|
95
|
+
}),
|
|
96
|
+
reset: jest.fn(),
|
|
97
|
+
clearHalt: jest.fn(),
|
|
98
|
+
claimInterface: jest.fn().mockImplementation(() => {
|
|
99
|
+
if (replacement.configuration?.configurationValue !== 1) {
|
|
100
|
+
return Promise.reject(new Error('USB configuration is not selected'));
|
|
101
|
+
}
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
let current = { opened: false } as USBDevice;
|
|
106
|
+
jest.spyOn(webusb, 'findDevice').mockImplementation(() => Promise.resolve(current));
|
|
107
|
+
jest.spyOn(webusb, 'getConnectedDevices').mockImplementation(() => {
|
|
108
|
+
current = replacement as unknown as USBDevice;
|
|
109
|
+
return Promise.resolve([]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await state.reconnectForPacketIoRetry(path, 'in', 0, new Error('transferIn failed'));
|
|
113
|
+
|
|
114
|
+
expect(replacement.selectConfiguration).toHaveBeenCalledTimes(
|
|
115
|
+
configurationValue === 1 ? 0 : 1
|
|
116
|
+
);
|
|
117
|
+
if (configurationValue !== 1) {
|
|
118
|
+
expect(replacement.selectConfiguration).toHaveBeenCalledWith(1);
|
|
119
|
+
}
|
|
120
|
+
expect(replacement.open).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(replacement.claimInterface).toHaveBeenCalledWith(0);
|
|
122
|
+
expect(replacement.reset).not.toHaveBeenCalled();
|
|
123
|
+
expect(replacement.clearHalt).not.toHaveBeenCalled();
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
test('uses the SDK 1.1.31 WebUSB sequence with descriptor endpoints for Protocol V1', async () => {
|
|
128
|
+
const webusb = new WebUsbTransport() as any;
|
|
129
|
+
const logger = { debug: jest.fn() };
|
|
130
|
+
const path = 'legacy-v1-device';
|
|
131
|
+
const device = {
|
|
132
|
+
opened: false,
|
|
133
|
+
configuration: { configurationValue: 1 },
|
|
134
|
+
configurations: [
|
|
135
|
+
{
|
|
136
|
+
interfaces: [
|
|
137
|
+
{
|
|
138
|
+
interfaceNumber: 7,
|
|
139
|
+
alternates: [
|
|
140
|
+
{
|
|
141
|
+
interfaceClass: 0xff,
|
|
142
|
+
endpoints: [
|
|
143
|
+
{ direction: 'in', endpointNumber: 3 },
|
|
144
|
+
{ direction: 'out', endpointNumber: 4 },
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
open: jest.fn().mockImplementation(() => {
|
|
153
|
+
device.opened = true;
|
|
154
|
+
return Promise.resolve();
|
|
155
|
+
}),
|
|
156
|
+
reset: jest.fn().mockResolvedValue(undefined),
|
|
157
|
+
selectConfiguration: jest.fn().mockResolvedValue(undefined),
|
|
158
|
+
claimInterface: jest.fn().mockResolvedValue(undefined),
|
|
159
|
+
clearHalt: jest.fn().mockResolvedValue(undefined),
|
|
160
|
+
};
|
|
161
|
+
webusb.Log = logger;
|
|
162
|
+
webusb.findDevice = jest.fn().mockResolvedValue(device);
|
|
163
|
+
webusb.getConnectedDevices = jest.fn().mockResolvedValue([]);
|
|
164
|
+
|
|
165
|
+
await webusb.connect(path, true, { expectedProtocol: 'V1' });
|
|
166
|
+
|
|
167
|
+
expect(device.open).toHaveBeenCalledTimes(1);
|
|
168
|
+
expect(device.selectConfiguration).toHaveBeenCalledWith(1);
|
|
169
|
+
expect(device.reset).toHaveBeenCalledTimes(1);
|
|
170
|
+
expect(device.claimInterface).toHaveBeenCalledWith(7);
|
|
171
|
+
expect(webusb.deviceEndpoints.get(path)).toEqual({
|
|
172
|
+
interfaceNumber: 7,
|
|
173
|
+
endpointIn: 3,
|
|
174
|
+
endpointOut: 4,
|
|
175
|
+
});
|
|
176
|
+
expect(device.selectConfiguration.mock.invocationCallOrder[0]).toBeLessThan(
|
|
177
|
+
device.reset.mock.invocationCallOrder[0]
|
|
178
|
+
);
|
|
179
|
+
expect(device.reset.mock.invocationCallOrder[0]).toBeLessThan(
|
|
180
|
+
device.claimInterface.mock.invocationCallOrder[0]
|
|
181
|
+
);
|
|
182
|
+
expect(webusb.getConnectedDevices).not.toHaveBeenCalled();
|
|
183
|
+
expect(device.clearHalt).not.toHaveBeenCalled();
|
|
184
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
185
|
+
'[WebUsbTransport][lifecycle]',
|
|
186
|
+
expect.objectContaining({
|
|
187
|
+
event: 'connect-attempt',
|
|
188
|
+
phase: 'start',
|
|
189
|
+
connectionStrategy: 'protocol-v1-legacy-1.1.31',
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('keeps the current WebUSB sequence when a cached V1 protocol is force-reprobed', async () => {
|
|
195
|
+
const webusb = new WebUsbTransport() as any;
|
|
196
|
+
const path = 'force-reprobe-device';
|
|
197
|
+
const device = {
|
|
198
|
+
opened: true,
|
|
199
|
+
configuration: { configurationValue: 1 },
|
|
200
|
+
configurations: [],
|
|
201
|
+
reset: jest.fn().mockResolvedValue(undefined),
|
|
202
|
+
selectConfiguration: jest.fn().mockResolvedValue(undefined),
|
|
203
|
+
claimInterface: jest.fn().mockResolvedValue(undefined),
|
|
204
|
+
clearHalt: jest.fn().mockResolvedValue(undefined),
|
|
205
|
+
};
|
|
206
|
+
webusb.Log = { debug: jest.fn() };
|
|
207
|
+
webusb.deviceProtocol.set(path, 'V1');
|
|
208
|
+
webusb.findDevice = jest.fn().mockResolvedValue(device);
|
|
209
|
+
webusb.getConnectedDevices = jest.fn().mockResolvedValue([]);
|
|
210
|
+
|
|
211
|
+
await webusb.connectToDevice(path, true, { forceProtocolDetection: true });
|
|
212
|
+
|
|
213
|
+
expect(device.reset).toHaveBeenCalledTimes(1);
|
|
214
|
+
expect(webusb.getConnectedDevices).toHaveBeenCalledTimes(1);
|
|
215
|
+
expect(device.clearHalt).toHaveBeenCalledTimes(2);
|
|
216
|
+
});
|
|
217
|
+
|
|
67
218
|
test('reports claimInterface failures as WebUSB device access errors', async () => {
|
|
68
219
|
const webusb = new WebUsbTransport();
|
|
69
220
|
const path = 'connected-usb-device';
|
|
@@ -91,6 +242,151 @@ describe('WebUsbTransport protocol probe cache', () => {
|
|
|
91
242
|
});
|
|
92
243
|
});
|
|
93
244
|
|
|
245
|
+
test('does not retry a typed WebUSB handle error', async () => {
|
|
246
|
+
const webusb = new WebUsbTransport() as any;
|
|
247
|
+
const logger = { debug: jest.fn() };
|
|
248
|
+
const path = 'sensitive-device-path';
|
|
249
|
+
const accessError = ERRORS.TypedError(
|
|
250
|
+
HardwareErrorCode.WebUsbDeviceAccessError,
|
|
251
|
+
'Unable to claim interface',
|
|
252
|
+
{ operation: 'claimInterface' }
|
|
253
|
+
);
|
|
254
|
+
webusb.Log = logger;
|
|
255
|
+
webusb.connectToDevice = jest.fn().mockRejectedValue(accessError);
|
|
256
|
+
|
|
257
|
+
await expect(webusb.connect(path, true)).rejects.toBe(accessError);
|
|
258
|
+
|
|
259
|
+
expect(webusb.connectToDevice).toHaveBeenCalledTimes(1);
|
|
260
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
261
|
+
'[WebUsbTransport][lifecycle]',
|
|
262
|
+
expect.objectContaining({
|
|
263
|
+
event: 'connect-attempt',
|
|
264
|
+
phase: 'error',
|
|
265
|
+
attempt: 1,
|
|
266
|
+
maxAttempts: 5,
|
|
267
|
+
willRetry: false,
|
|
268
|
+
errorCode: HardwareErrorCode.WebUsbDeviceAccessError,
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
expect(JSON.stringify(logger.debug.mock.calls)).not.toContain(path);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('preserves the existing reconnect retry for a transient disconnect', async () => {
|
|
275
|
+
const webusb = new WebUsbTransport() as any;
|
|
276
|
+
const disconnected = ERRORS.TypedError(HardwareErrorCode.BridgeDeviceDisconnected);
|
|
277
|
+
webusb.Log = { debug: jest.fn() };
|
|
278
|
+
webusb.connectToDevice = jest
|
|
279
|
+
.fn()
|
|
280
|
+
.mockRejectedValueOnce(disconnected)
|
|
281
|
+
.mockResolvedValueOnce(undefined);
|
|
282
|
+
|
|
283
|
+
await expect(webusb.connect('device-path', true)).resolves.toBeUndefined();
|
|
284
|
+
|
|
285
|
+
expect(webusb.connectToDevice).toHaveBeenCalledTimes(2);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test.each([false, true])('retains claim error when cleanup fails=%s', async cleanupFails => {
|
|
289
|
+
const webusb = new WebUsbTransport() as any;
|
|
290
|
+
const logger = { debug: jest.fn() };
|
|
291
|
+
const path = 'sensitive-device-path';
|
|
292
|
+
const claimError = Object.assign(new Error('Unable to claim interface'), {
|
|
293
|
+
name: 'NetworkError',
|
|
294
|
+
});
|
|
295
|
+
const usbInterface = {
|
|
296
|
+
interfaceNumber: 0,
|
|
297
|
+
claimed: false,
|
|
298
|
+
alternates: [],
|
|
299
|
+
};
|
|
300
|
+
const originalDevice = {
|
|
301
|
+
vendorId: 0x1209,
|
|
302
|
+
productId: 0x53c1,
|
|
303
|
+
serialNumber: path,
|
|
304
|
+
opened: false,
|
|
305
|
+
configuration: { configurationValue: 1, interfaces: [usbInterface] },
|
|
306
|
+
configurations: [],
|
|
307
|
+
open: jest.fn().mockImplementation(() => {
|
|
308
|
+
originalDevice.opened = true;
|
|
309
|
+
return Promise.resolve();
|
|
310
|
+
}),
|
|
311
|
+
reset: jest.fn().mockResolvedValue(undefined),
|
|
312
|
+
selectConfiguration: jest.fn().mockResolvedValue(undefined),
|
|
313
|
+
claimInterface: jest.fn().mockResolvedValue(undefined),
|
|
314
|
+
releaseInterface: jest.fn().mockResolvedValue(undefined),
|
|
315
|
+
close: jest.fn().mockImplementation(() => {
|
|
316
|
+
originalDevice.opened = false;
|
|
317
|
+
return Promise.resolve();
|
|
318
|
+
}),
|
|
319
|
+
clearHalt: jest.fn().mockResolvedValue(undefined),
|
|
320
|
+
};
|
|
321
|
+
const replacementDevice = {
|
|
322
|
+
...originalDevice,
|
|
323
|
+
opened: false,
|
|
324
|
+
open: jest.fn().mockImplementation(() => {
|
|
325
|
+
replacementDevice.opened = true;
|
|
326
|
+
return Promise.resolve();
|
|
327
|
+
}),
|
|
328
|
+
reset: jest.fn().mockResolvedValue(undefined),
|
|
329
|
+
selectConfiguration: jest.fn().mockResolvedValue(undefined),
|
|
330
|
+
claimInterface: jest.fn().mockRejectedValue(claimError),
|
|
331
|
+
releaseInterface: jest.fn().mockResolvedValue(undefined),
|
|
332
|
+
close: jest.fn().mockImplementation(() => {
|
|
333
|
+
replacementDevice.opened = false;
|
|
334
|
+
return Promise.resolve();
|
|
335
|
+
}),
|
|
336
|
+
clearHalt: jest.fn().mockResolvedValue(undefined),
|
|
337
|
+
};
|
|
338
|
+
if (cleanupFails) {
|
|
339
|
+
replacementDevice.close.mockRejectedValueOnce(new Error('native close failed'));
|
|
340
|
+
}
|
|
341
|
+
webusb.Log = logger;
|
|
342
|
+
webusb.usb = { getDevices: jest.fn().mockResolvedValue([replacementDevice]) };
|
|
343
|
+
webusb.deviceList = [{ path, device: originalDevice, commType: 'webusb' }];
|
|
344
|
+
webusb.rotateProtocolV2UsbGeneration = jest.fn().mockResolvedValue(undefined);
|
|
345
|
+
|
|
346
|
+
await expect(webusb.acquire({ path })).rejects.toMatchObject({
|
|
347
|
+
errorCode: HardwareErrorCode.WebUsbDeviceAccessError,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
expect(originalDevice.claimInterface).not.toHaveBeenCalled();
|
|
351
|
+
expect(replacementDevice.claimInterface).toHaveBeenCalledTimes(1);
|
|
352
|
+
expect(originalDevice.releaseInterface).not.toHaveBeenCalled();
|
|
353
|
+
expect(replacementDevice.releaseInterface).not.toHaveBeenCalled();
|
|
354
|
+
expect(originalDevice.close).toHaveBeenCalledTimes(1);
|
|
355
|
+
expect(replacementDevice.close).toHaveBeenCalledTimes(1);
|
|
356
|
+
expect(originalDevice.opened).toBe(false);
|
|
357
|
+
expect(replacementDevice.opened).toBe(cleanupFails);
|
|
358
|
+
if (cleanupFails) {
|
|
359
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
360
|
+
'[WebUsbTransport][lifecycle]',
|
|
361
|
+
expect.objectContaining({
|
|
362
|
+
event: 'acquire-cleanup',
|
|
363
|
+
phase: 'error',
|
|
364
|
+
errorMessage: 'native close failed',
|
|
365
|
+
})
|
|
366
|
+
);
|
|
367
|
+
const competing = new WebUsbTransport();
|
|
368
|
+
jest
|
|
369
|
+
.spyOn(competing, 'findDevice')
|
|
370
|
+
.mockResolvedValue(replacementDevice as unknown as USBDevice);
|
|
371
|
+
await expect(competing.connectToDevice(path, true)).rejects.toThrow(
|
|
372
|
+
'USB device is already in use'
|
|
373
|
+
);
|
|
374
|
+
await webusb.release(path);
|
|
375
|
+
expect(replacementDevice.opened).toBe(false);
|
|
376
|
+
}
|
|
377
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
378
|
+
'[WebUsbTransport][lifecycle]',
|
|
379
|
+
expect.objectContaining({
|
|
380
|
+
event: 'handle-operation',
|
|
381
|
+
operation: 'releaseInterface',
|
|
382
|
+
phase: 'skipped',
|
|
383
|
+
reason: 'interface-not-claimed',
|
|
384
|
+
deviceRefId: expect.any(Number),
|
|
385
|
+
})
|
|
386
|
+
);
|
|
387
|
+
expect(JSON.stringify(logger.debug.mock.calls)).not.toContain(path);
|
|
388
|
+
});
|
|
389
|
+
|
|
94
390
|
test('reports transferIn failures as WebUSB device access errors', async () => {
|
|
95
391
|
const webusb = new WebUsbTransport() as any;
|
|
96
392
|
const path = 'connected-usb-device';
|
|
@@ -193,6 +489,10 @@ describe('WebUsbTransport protocol probe cache', () => {
|
|
|
193
489
|
|
|
194
490
|
await expect(webusb.acquire({ path, expectedProtocol: 'V1' })).resolves.toBe(path);
|
|
195
491
|
|
|
492
|
+
expect(webusb.connect).toHaveBeenCalledWith(path, true, {
|
|
493
|
+
expectedProtocol: 'V1',
|
|
494
|
+
forceProtocolDetection: undefined,
|
|
495
|
+
});
|
|
196
496
|
expect(webusb.detectProtocol).not.toHaveBeenCalled();
|
|
197
497
|
expect(webusb.deviceProtocol.get(path)).toBe('V1');
|
|
198
498
|
expect(webusb.acquiredPaths.has(path)).toBe(true);
|
|
@@ -102,7 +102,7 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
|
|
|
102
102
|
expect(webusb.deviceProtocol.get(path)).toBe('V2');
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
test('reports
|
|
105
|
+
test('reports a typed probe failure when automatic detection exhausts both protocols', async () => {
|
|
106
106
|
const webusb = new WebUsbTransport() as any;
|
|
107
107
|
const path = 'unresponsive-webusb';
|
|
108
108
|
webusb.probeProtocolV1 = jest.fn().mockResolvedValue(false);
|
|
@@ -111,7 +111,7 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
|
|
|
111
111
|
webusb.closeConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
112
112
|
|
|
113
113
|
await expect(webusb.detectProtocol(path)).rejects.toMatchObject({
|
|
114
|
-
errorCode: HardwareErrorCode.
|
|
114
|
+
errorCode: HardwareErrorCode.TransportProtocolProbeFailed,
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
expect(webusb.probeProtocolV1).toHaveBeenCalledTimes(1);
|
|
@@ -154,7 +154,20 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
|
|
|
154
154
|
expect(webusb.deviceProtocol.get(path)).toBe('V2');
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
test('reports a
|
|
157
|
+
test('reports a strict V1 probe miss without falling back to another protocol', async () => {
|
|
158
|
+
const webusb = new WebUsbTransport() as any;
|
|
159
|
+
webusb.probeProtocolV1 = jest.fn().mockResolvedValue(false);
|
|
160
|
+
webusb.probeProtocolV2 = jest.fn();
|
|
161
|
+
webusb.closeConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
162
|
+
await expect(webusb.detectProtocol('classic-webusb', 'V1')).rejects.toMatchObject({
|
|
163
|
+
errorCode: HardwareErrorCode.TransportProtocolProbeFailed,
|
|
164
|
+
params: { expectedProtocol: 'V1' },
|
|
165
|
+
});
|
|
166
|
+
expect(webusb.probeProtocolV2).not.toHaveBeenCalled();
|
|
167
|
+
expect(webusb.closeConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('reports a typed protocol probe failure only after the bounded retry is exhausted', async () => {
|
|
158
171
|
const webusb = new WebUsbTransport() as any;
|
|
159
172
|
const path = 'pro2-webusb';
|
|
160
173
|
webusb.probeProtocolV1 = jest.fn();
|
|
@@ -163,8 +176,8 @@ describe('WebUsbTransport Protocol V2 timeout recovery', () => {
|
|
|
163
176
|
webusb.closeConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
164
177
|
|
|
165
178
|
await expect(webusb.detectProtocol(path, 'V2')).rejects.toMatchObject({
|
|
166
|
-
errorCode: HardwareErrorCode.
|
|
167
|
-
|
|
179
|
+
errorCode: HardwareErrorCode.TransportProtocolProbeFailed,
|
|
180
|
+
params: { expectedProtocol: 'V2', attempts: 2 },
|
|
168
181
|
});
|
|
169
182
|
|
|
170
183
|
expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(2);
|
|
@@ -25,6 +25,8 @@ export default class ElectronBleTransport {
|
|
|
25
25
|
Log?: any;
|
|
26
26
|
emitter?: EventEmitter;
|
|
27
27
|
private connectedDevices;
|
|
28
|
+
private retainedDevices;
|
|
29
|
+
private protocolV2CallCounts;
|
|
28
30
|
private acquiringDevices;
|
|
29
31
|
private deviceProtocol;
|
|
30
32
|
private deviceProtocolHints;
|
|
@@ -59,9 +61,10 @@ export default class ElectronBleTransport {
|
|
|
59
61
|
debug: boolean;
|
|
60
62
|
id: string;
|
|
61
63
|
name: string | null;
|
|
64
|
+
bleColorCode?: string | undefined;
|
|
62
65
|
protocolType?: ProtocolType | undefined;
|
|
63
66
|
}>;
|
|
64
|
-
release(id: string,
|
|
67
|
+
release(id: string, onclose?: boolean, keepSession?: boolean): Promise<void>;
|
|
65
68
|
disconnect(id: string): Promise<void>;
|
|
66
69
|
private releaseNative;
|
|
67
70
|
private releaseLogical;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAA4B,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,
|
|
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
|
@@ -12,7 +12,16 @@ interface DeviceInfo extends OneKeyDeviceInfoBase {
|
|
|
12
12
|
device: USBDevice;
|
|
13
13
|
protocolType?: ProtocolType;
|
|
14
14
|
}
|
|
15
|
+
interface WebUsbConnectOptions {
|
|
16
|
+
expectedProtocol?: ProtocolType;
|
|
17
|
+
forceProtocolDetection?: boolean;
|
|
18
|
+
}
|
|
15
19
|
declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
|
|
20
|
+
private readonly identityProbe;
|
|
21
|
+
private readonly transportInstanceId;
|
|
22
|
+
private handleOperationSequence;
|
|
23
|
+
private deviceLogSequence;
|
|
24
|
+
private deviceLogIds;
|
|
16
25
|
messages: ReturnType<typeof _onekeyfe_hd_transport__default.parseConfigure> | undefined;
|
|
17
26
|
/** Protobuf schema for Protocol V2 transports. */
|
|
18
27
|
messagesV2: ReturnType<typeof _onekeyfe_hd_transport__default.parseConfigure> | undefined;
|
|
@@ -29,6 +38,11 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
|
|
|
29
38
|
private staleProtocolPaths;
|
|
30
39
|
/** Paths currently acquired (between a successful acquire() and its release()). */
|
|
31
40
|
private acquiredPaths;
|
|
41
|
+
private identityProbeDevices;
|
|
42
|
+
private normalDevices;
|
|
43
|
+
private pendingHandleOperations;
|
|
44
|
+
private stopPromise?;
|
|
45
|
+
private identityProbeCleanupPaths;
|
|
32
46
|
/**
|
|
33
47
|
* The exact USBDevice object each cached protocol was probed against. The
|
|
34
48
|
* browser returns the same object identity for a device as long as it stays
|
|
@@ -53,11 +67,22 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
|
|
|
53
67
|
configurationId: number;
|
|
54
68
|
endpointId: number;
|
|
55
69
|
interfaceId: number;
|
|
56
|
-
constructor();
|
|
70
|
+
constructor(identityProbe?: boolean);
|
|
57
71
|
/**
|
|
58
72
|
* Initialize WebUSB transport
|
|
59
73
|
*/
|
|
60
74
|
init(logger: any, emitter?: EventEmitter): void;
|
|
75
|
+
stop(): Promise<void>;
|
|
76
|
+
private stopResources;
|
|
77
|
+
private assertRunning;
|
|
78
|
+
private runHandleOperation;
|
|
79
|
+
private getInterfaceClaimed;
|
|
80
|
+
private getDeviceLogId;
|
|
81
|
+
private getHandleLogState;
|
|
82
|
+
private getDiagnosticError;
|
|
83
|
+
private logLifecycle;
|
|
84
|
+
private logSkippedHandleOperation;
|
|
85
|
+
private runLoggedHandleOperation;
|
|
61
86
|
/**
|
|
62
87
|
* Announce that a USB device left. Called from the module-scoped disconnect
|
|
63
88
|
* listener, which is why it is public rather than inlined.
|
|
@@ -118,7 +143,8 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
|
|
|
118
143
|
/**
|
|
119
144
|
* Connect to device with retry mechanism
|
|
120
145
|
*/
|
|
121
|
-
connect(path: string, first: boolean): Promise<undefined>;
|
|
146
|
+
connect(path: string, first: boolean, options?: WebUsbConnectOptions): Promise<undefined>;
|
|
147
|
+
private shouldUseLegacyV1Connection;
|
|
122
148
|
/**
|
|
123
149
|
* Discover vendor-class (0xFF) interface and its IN/OUT endpoint numbers from USB descriptors.
|
|
124
150
|
* Falls back to legacy hardcoded values if no vendor interface is found.
|
|
@@ -128,8 +154,16 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
|
|
|
128
154
|
* Connect to specific device.
|
|
129
155
|
* Discovers interface/endpoint numbers from USB descriptors on first connection.
|
|
130
156
|
*/
|
|
131
|
-
connectToDevice(path: string, first: boolean): Promise<undefined>;
|
|
157
|
+
connectToDevice(path: string, first: boolean, options?: WebUsbConnectOptions): Promise<undefined>;
|
|
158
|
+
private claimDeviceInterface;
|
|
159
|
+
private assertHandleAvailable;
|
|
160
|
+
private claimNormalHandle;
|
|
161
|
+
private releaseNormalHandles;
|
|
162
|
+
private isHandleOwnershipError;
|
|
163
|
+
private claimIdentityProbeHandle;
|
|
164
|
+
private releaseIdentityProbeHandle;
|
|
132
165
|
private closeOpenDevice;
|
|
166
|
+
private closeDeviceHandle;
|
|
133
167
|
private clearEndpointHalt;
|
|
134
168
|
/**
|
|
135
169
|
* With the protocol cache surviving release(), deviceProtocol presence no
|
|
@@ -221,6 +255,8 @@ declare class ElectronBleTransport {
|
|
|
221
255
|
Log?: any;
|
|
222
256
|
emitter?: EventEmitter;
|
|
223
257
|
private connectedDevices;
|
|
258
|
+
private retainedDevices;
|
|
259
|
+
private protocolV2CallCounts;
|
|
224
260
|
/**
|
|
225
261
|
* Devices whose acquire() is still in flight.
|
|
226
262
|
*
|
|
@@ -276,9 +312,10 @@ declare class ElectronBleTransport {
|
|
|
276
312
|
debug: boolean;
|
|
277
313
|
id: string;
|
|
278
314
|
name: string | null;
|
|
315
|
+
bleColorCode?: string | undefined;
|
|
279
316
|
protocolType?: ProtocolType | undefined;
|
|
280
317
|
}>;
|
|
281
|
-
release(id: string,
|
|
318
|
+
release(id: string, onclose?: boolean, keepSession?: boolean): Promise<void>;
|
|
282
319
|
disconnect(id: string): Promise<void>;
|
|
283
320
|
private releaseNative;
|
|
284
321
|
private releaseLogical;
|