@onekeyfe/hd-transport-web-device 1.2.0-alpha.134 → 1.2.0-alpha.135

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/dist/index.d.ts CHANGED
@@ -20,13 +20,6 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
20
20
  /** Per-path protocol type detected by active wire-level probe. */
21
21
  private deviceProtocol;
22
22
  private deviceProtocolHints;
23
- /**
24
- * Paths whose cached protocol must be re-probed on the next acquire (a USB
25
- * disconnect was seen, or a transfer-level reconnect happened mid-call).
26
- */
27
- private staleProtocolPaths;
28
- /** Paths currently acquired (between a successful acquire() and its release()). */
29
- private acquiredPaths;
30
23
  /** Per-path USB endpoint / interface numbers (discovered from USB descriptors) */
31
24
  private deviceEndpoints;
32
25
  name: string;
@@ -47,17 +40,6 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
47
40
  * Initialize WebUSB transport
48
41
  */
49
42
  init(logger: any): void;
50
- /**
51
- * Protocol type is a property of the physical device keyed by USB serial number.
52
- * It can only change across a device reboot (e.g. normal ↔ bootloader mode), and
53
- * a reboot always surfaces as a USB disconnect. Disconnects (and transfer-level
54
- * reconnects, which cover a missed disconnect event) only MARK the cached probe
55
- * result stale instead of deleting it: an in-flight session keeps using the old
56
- * value so the transfer-level reconnect retries can absorb a transient
57
- * re-enumeration exactly as they did before the cache existed, while the next
58
- * acquire re-probes from scratch.
59
- */
60
- markProtocolStale(path: string): void;
61
43
  /**
62
44
  * Configure Protocol V1 protobuf schema (legacy chunked 0x3F framing).
63
45
  */
@@ -115,14 +97,6 @@ declare class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
115
97
  connectToDevice(path: string, first: boolean): Promise<void>;
116
98
  private closeOpenDevice;
117
99
  private clearEndpointHalt;
118
- /**
119
- * With the protocol cache surviving release(), deviceProtocol presence no
120
- * longer implies an active session. Guard call()/post() explicitly so a
121
- * post-release straggler fails fast instead of silently reopening the device
122
- * and driving it outside any session (pre-cache behavior: the deleted
123
- * protocol entry produced the same fail-fast).
124
- */
125
- private assertAcquired;
126
100
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
127
101
  private getErrorMessage;
128
102
  private isRetryablePacketIoError;
package/dist/index.js CHANGED
@@ -57,20 +57,6 @@ const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
57
57
  function inferProtocolHintFromDeviceName$1(name) {
58
58
  return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
59
59
  }
60
- let activeWebUsbTransport;
61
- let usbDisconnectListenerAttached = false;
62
- function attachUsbDisconnectListener(usb) {
63
- if (usbDisconnectListenerAttached)
64
- return;
65
- usbDisconnectListenerAttached = true;
66
- usb.addEventListener('disconnect', event => {
67
- var _a;
68
- const serial = (_a = event.device) === null || _a === void 0 ? void 0 : _a.serialNumber;
69
- if (typeof serial !== 'string' || serial.length === 0)
70
- return;
71
- activeWebUsbTransport === null || activeWebUsbTransport === void 0 ? void 0 : activeWebUsbTransport.markProtocolStale(serial);
72
- });
73
- }
74
60
  class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
75
61
  constructor() {
76
62
  super({
@@ -80,8 +66,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
80
66
  });
81
67
  this.deviceProtocol = new Map();
82
68
  this.deviceProtocolHints = new Map();
83
- this.staleProtocolPaths = new Set();
84
- this.acquiredPaths = new Set();
85
69
  this.deviceEndpoints = new Map();
86
70
  this.name = 'WebUsbTransport';
87
71
  this.stopped = false;
@@ -98,11 +82,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
98
82
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'WebUSB is not supported by current browsers');
99
83
  }
100
84
  this.usb = usb;
101
- activeWebUsbTransport = this;
102
- attachUsbDisconnectListener(usb);
103
- }
104
- markProtocolStale(path) {
105
- this.staleProtocolPaths.add(path);
106
85
  }
107
86
  configure(signedData) {
108
87
  const messages = parseConfigure$1(signedData);
@@ -177,30 +156,18 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
177
156
  yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
178
157
  yield this.closeOpenDevice(input.path);
179
158
  yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
180
- if (this.staleProtocolPaths.has(input.path)) {
181
- this.staleProtocolPaths.delete(input.path);
182
- this.deviceProtocol.delete(input.path);
183
- }
184
- const cachedProtocol = this.deviceProtocol.get(input.path);
185
- if (cachedProtocol && input.expectedProtocol && cachedProtocol !== input.expectedProtocol) {
186
- this.deviceProtocol.delete(input.path);
187
- }
188
- if (!this.deviceProtocol.has(input.path)) {
189
- const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
190
- const protocolHint = input.expectedProtocol
191
- ? undefined
192
- : (_d = (_c = input.protocolHint) !== null && _c !== void 0 ? _c : this.deviceProtocolHints.get(input.path)) !== null && _d !== void 0 ? _d : inferProtocolHintFromDeviceName$1(deviceName);
193
- if (protocolHint) {
194
- this.deviceProtocolHints.set(input.path, protocolHint);
195
- }
196
- yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
159
+ const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
160
+ const protocolHint = input.expectedProtocol
161
+ ? undefined
162
+ : (_d = (_c = input.protocolHint) !== null && _c !== void 0 ? _c : this.deviceProtocolHints.get(input.path)) !== null && _d !== void 0 ? _d : inferProtocolHintFromDeviceName$1(deviceName);
163
+ if (protocolHint) {
164
+ this.deviceProtocolHints.set(input.path, protocolHint);
197
165
  }
198
- this.acquiredPaths.add(input.path);
166
+ yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
199
167
  return yield Promise.resolve(input.path);
200
168
  }
201
169
  catch (e) {
202
170
  this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
203
- this.acquiredPaths.delete(input.path);
204
171
  yield this.closeOpenDevice(input.path);
205
172
  throw e;
206
173
  }
@@ -384,14 +351,8 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
384
351
  }
385
352
  });
386
353
  }
387
- assertAcquired(path) {
388
- if (!this.acquiredPaths.has(path)) {
389
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device is not acquired for ${path}`);
390
- }
391
- }
392
354
  post(session, name, data) {
393
355
  return __awaiter(this, void 0, void 0, function* () {
394
- this.assertAcquired(session);
395
356
  if (this.deviceProtocol.get(session) === 'V2') {
396
357
  yield this.sendProtocolV2UsbFlowControl(session, name, data);
397
358
  return;
@@ -424,7 +385,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
424
385
  var _a;
425
386
  return __awaiter(this, void 0, void 0, function* () {
426
387
  this.Log.debug(`[WebUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
427
- this.staleProtocolPaths.add(path);
428
388
  yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
429
389
  try {
430
390
  const currentDevice = yield this.findDevice(path);
@@ -639,7 +599,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
639
599
  if (this.messages == null) {
640
600
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
641
601
  }
642
- this.assertAcquired(path);
643
602
  const device = yield this.findDevice(path);
644
603
  if (!device) {
645
604
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
@@ -719,9 +678,10 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
719
678
  }
720
679
  release(path) {
721
680
  return __awaiter(this, void 0, void 0, function* () {
722
- this.acquiredPaths.delete(path);
723
681
  yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
724
682
  yield this.closeOpenDevice(path);
683
+ this.deviceProtocol.delete(path);
684
+ this.deviceProtocolHints.delete(path);
725
685
  this.deviceEndpoints.delete(path);
726
686
  });
727
687
  }
package/dist/webusb.d.ts CHANGED
@@ -12,8 +12,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
12
12
  private protocolV2SchemaSource;
13
13
  private deviceProtocol;
14
14
  private deviceProtocolHints;
15
- private staleProtocolPaths;
16
- private acquiredPaths;
17
15
  private deviceEndpoints;
18
16
  name: string;
19
17
  stopped: boolean;
@@ -26,7 +24,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
26
24
  interfaceId: number;
27
25
  constructor();
28
26
  init(logger: any): void;
29
- markProtocolStale(path: string): void;
30
27
  configure(signedData: any): void;
31
28
  configureProtocolV2(signedData: any): void;
32
29
  promptDeviceAccess(): Promise<USBDevice | null>;
@@ -43,7 +40,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
43
40
  connectToDevice(path: string, first: boolean): Promise<void>;
44
41
  private closeOpenDevice;
45
42
  private clearEndpointHalt;
46
- private assertAcquired;
47
43
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
48
44
  private getErrorMessage;
49
45
  private isRetryablePacketIoError;
@@ -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.134",
3
+ "version": "1.2.0-alpha.135",
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.134",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.134"
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.135",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.135"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.0-alpha.134",
28
+ "@onekeyfe/hd-transport-electron": "1.2.0-alpha.135",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "47de2b0244584f6a541a84b0f94e4676bf63221a"
32
+ "gitHead": "321e900381de2c1a9c583e90e8abfc2f8dab8266"
33
33
  }
package/src/webusb.ts CHANGED
@@ -69,26 +69,6 @@ interface TransferCancelToken {
69
69
  cancelled: boolean;
70
70
  }
71
71
 
72
- /**
73
- * The navigator.usb disconnect listener is module-scoped and attached at most
74
- * once: listeners on navigator.usb are global and never garbage collected, so a
75
- * per-instance listener would retain every transport instance created across
76
- * SDK re-initializations. Events are routed to the most recently initialized
77
- * transport instance instead.
78
- */
79
- let activeWebUsbTransport: WebUsbTransport | undefined;
80
- let usbDisconnectListenerAttached = false;
81
-
82
- function attachUsbDisconnectListener(usb: USB) {
83
- if (usbDisconnectListenerAttached) return;
84
- usbDisconnectListenerAttached = true;
85
- usb.addEventListener('disconnect', event => {
86
- const serial = event.device?.serialNumber;
87
- if (typeof serial !== 'string' || serial.length === 0) return;
88
- activeWebUsbTransport?.markProtocolStale(serial);
89
- });
90
- }
91
-
92
72
  export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string> {
93
73
  messages: ReturnType<typeof transport.parseConfigure> | undefined;
94
74
 
@@ -102,15 +82,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
102
82
 
103
83
  private deviceProtocolHints: Map<string, ProtocolType> = new Map();
104
84
 
105
- /**
106
- * Paths whose cached protocol must be re-probed on the next acquire (a USB
107
- * disconnect was seen, or a transfer-level reconnect happened mid-call).
108
- */
109
- private staleProtocolPaths: Set<string> = new Set();
110
-
111
- /** Paths currently acquired (between a successful acquire() and its release()). */
112
- private acquiredPaths: Set<string> = new Set();
113
-
114
85
  /** Per-path USB endpoint / interface numbers (discovered from USB descriptors) */
115
86
  private deviceEndpoints: Map<string, DeviceEndpoints> = new Map();
116
87
 
@@ -158,22 +129,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
158
129
  );
159
130
  }
160
131
  this.usb = usb;
161
- activeWebUsbTransport = this;
162
- attachUsbDisconnectListener(usb);
163
- }
164
-
165
- /**
166
- * Protocol type is a property of the physical device keyed by USB serial number.
167
- * It can only change across a device reboot (e.g. normal ↔ bootloader mode), and
168
- * a reboot always surfaces as a USB disconnect. Disconnects (and transfer-level
169
- * reconnects, which cover a missed disconnect event) only MARK the cached probe
170
- * result stale instead of deleting it: an in-flight session keeps using the old
171
- * value so the transfer-level reconnect retries can absorb a transient
172
- * re-enumeration exactly as they did before the cache existed, while the next
173
- * acquire re-probes from scratch.
174
- */
175
- markProtocolStale(path: string) {
176
- this.staleProtocolPaths.add(path);
177
132
  }
178
133
 
179
134
  /**
@@ -276,36 +231,20 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
276
231
  await this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
277
232
  await this.closeOpenDevice(input.path);
278
233
  await this.connect(input.path ?? '', true);
279
- if (this.staleProtocolPaths.has(input.path)) {
280
- // The device disconnected (possibly rebooting into another mode) since
281
- // the protocol was probed — drop the cache so it is re-probed below.
282
- this.staleProtocolPaths.delete(input.path);
283
- this.deviceProtocol.delete(input.path);
284
- }
285
- const cachedProtocol = this.deviceProtocol.get(input.path);
286
- if (cachedProtocol && input.expectedProtocol && cachedProtocol !== input.expectedProtocol) {
287
- // The caller expects a different protocol than the cached probe result;
288
- // the cache is stale — drop it and re-probe on the wire below.
289
- this.deviceProtocol.delete(input.path);
290
- }
291
- if (!this.deviceProtocol.has(input.path)) {
292
- const deviceName = this.deviceList.find(device => device.path === input.path)?.device
293
- .productName;
294
- const protocolHint = input.expectedProtocol
295
- ? undefined
296
- : input.protocolHint ??
297
- this.deviceProtocolHints.get(input.path) ??
298
- inferProtocolHintFromDeviceName(deviceName);
299
- if (protocolHint) {
300
- this.deviceProtocolHints.set(input.path, protocolHint);
301
- }
302
- await this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
234
+ const deviceName = this.deviceList.find(device => device.path === input.path)?.device
235
+ .productName;
236
+ const protocolHint = input.expectedProtocol
237
+ ? undefined
238
+ : input.protocolHint ??
239
+ this.deviceProtocolHints.get(input.path) ??
240
+ inferProtocolHintFromDeviceName(deviceName);
241
+ if (protocolHint) {
242
+ this.deviceProtocolHints.set(input.path, protocolHint);
303
243
  }
304
- this.acquiredPaths.add(input.path);
244
+ await this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
305
245
  return await Promise.resolve(input.path);
306
246
  } catch (e) {
307
247
  this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
308
- this.acquiredPaths.delete(input.path);
309
248
  await this.closeOpenDevice(input.path);
310
249
  throw e;
311
250
  }
@@ -541,24 +480,7 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
541
480
  }
542
481
  }
543
482
 
544
- /**
545
- * With the protocol cache surviving release(), deviceProtocol presence no
546
- * longer implies an active session. Guard call()/post() explicitly so a
547
- * post-release straggler fails fast instead of silently reopening the device
548
- * and driving it outside any session (pre-cache behavior: the deleted
549
- * protocol entry produced the same fail-fast).
550
- */
551
- private assertAcquired(path: string) {
552
- if (!this.acquiredPaths.has(path)) {
553
- throw ERRORS.TypedError(
554
- HardwareErrorCode.RuntimeError,
555
- `Device is not acquired for ${path}`
556
- );
557
- }
558
- }
559
-
560
483
  async post(session: string, name: string, data: Record<string, unknown>) {
561
- this.assertAcquired(session);
562
484
  if (this.deviceProtocol.get(session) === 'V2') {
563
485
  await this.sendProtocolV2UsbFlowControl(session, name, data);
564
486
  return;
@@ -600,11 +522,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
600
522
  error
601
523
  )}`
602
524
  );
603
- // The device dropped off the bus mid-call and may have rebooted into a
604
- // different mode. The in-flight retry keeps the known protocol, but the
605
- // next acquire must re-probe — this also self-heals a stale cache when the
606
- // USB disconnect event itself was missed.
607
- this.staleProtocolPaths.add(path);
608
525
  await wait(attempt * PACKET_IO_RETRY_DELAY);
609
526
 
610
527
  try {
@@ -838,7 +755,6 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
838
755
  if (this.messages == null) {
839
756
  throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
840
757
  }
841
- this.assertAcquired(path);
842
758
 
843
759
  const device = await this.findDevice(path);
844
760
  if (!device) {
@@ -955,14 +871,10 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
955
871
  * Release device
956
872
  */
957
873
  async release(path: string) {
958
- this.acquiredPaths.delete(path);
959
874
  await this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
960
875
  await this.closeOpenDevice(path);
961
- // Keep deviceProtocol/deviceProtocolHints across release: the probe result is a
962
- // physical-device property, so the next acquire can skip the wire-level probe.
963
- // V2 entries are still dropped by onProtocolV2UsbLinkInvalidated via the link
964
- // invalidation above, and any entry is re-probed after a USB disconnect or a
965
- // transfer-level reconnect (see markProtocolStale).
876
+ this.deviceProtocol.delete(path);
877
+ this.deviceProtocolHints.delete(path);
966
878
  this.deviceEndpoints.delete(path);
967
879
  }
968
880
 
@@ -1,204 +0,0 @@
1
- import transport from '@onekeyfe/hd-transport';
2
- import { HardwareErrorCode } from '@onekeyfe/hd-shared';
3
-
4
- import WebUsbTransport from '../src/webusb';
5
-
6
- const schema = {
7
- nested: {
8
- Ping: { fields: { message: { type: 'string', id: 1 } } },
9
- Success: { fields: { message: { type: 'string', id: 1 } } },
10
- MessageType: {
11
- values: {
12
- MessageType_Ping: 60206,
13
- MessageType_Success: 60207,
14
- },
15
- },
16
- },
17
- };
18
-
19
- function buildAcquirableTransport() {
20
- const webusb = new WebUsbTransport() as any;
21
- webusb.Log = { debug: jest.fn() };
22
- webusb.rotateProtocolV2UsbGeneration = jest.fn().mockResolvedValue(undefined);
23
- webusb.closeOpenDevice = jest.fn().mockResolvedValue(undefined);
24
- webusb.connect = jest.fn().mockResolvedValue(undefined);
25
- return webusb;
26
- }
27
-
28
- describe('WebUsbTransport protocol probe cache', () => {
29
- test('acquire skips the wire probe when the protocol is already cached', async () => {
30
- const webusb = buildAcquirableTransport();
31
- const path = 'pro-webusb';
32
- webusb.deviceProtocol.set(path, 'V1');
33
- webusb.detectProtocol = jest.fn();
34
-
35
- await expect(webusb.acquire({ path, expectedProtocol: 'V1' })).resolves.toBe(path);
36
-
37
- expect(webusb.detectProtocol).not.toHaveBeenCalled();
38
- expect(webusb.deviceProtocol.get(path)).toBe('V1');
39
- expect(webusb.acquiredPaths.has(path)).toBe(true);
40
- });
41
-
42
- test('acquire re-probes when the caller expects a different protocol than cached', async () => {
43
- const webusb = buildAcquirableTransport();
44
- const path = 'pro-webusb';
45
- webusb.deviceProtocol.set(path, 'V1');
46
- webusb.detectProtocol = jest.fn().mockImplementation((p: string) => {
47
- webusb.deviceProtocol.set(p, 'V2');
48
- return Promise.resolve('V2');
49
- });
50
-
51
- await expect(webusb.acquire({ path, expectedProtocol: 'V2' })).resolves.toBe(path);
52
-
53
- expect(webusb.detectProtocol).toHaveBeenCalledWith(path, 'V2', undefined);
54
- expect(webusb.deviceProtocol.get(path)).toBe('V2');
55
- });
56
-
57
- test('acquire probes when nothing is cached for the path', async () => {
58
- const webusb = buildAcquirableTransport();
59
- const path = 'pro-webusb';
60
- webusb.detectProtocol = jest.fn().mockResolvedValue('V1');
61
-
62
- await expect(webusb.acquire({ path, expectedProtocol: 'V1' })).resolves.toBe(path);
63
-
64
- expect(webusb.detectProtocol).toHaveBeenCalledWith(path, 'V1', undefined);
65
- });
66
-
67
- test('acquire re-probes a stale-marked path even when a protocol is cached', async () => {
68
- const webusb = buildAcquirableTransport();
69
- const path = 'pro-webusb';
70
- webusb.deviceProtocol.set(path, 'V1');
71
- webusb.markProtocolStale(path);
72
- webusb.detectProtocol = jest.fn().mockImplementation((p: string) => {
73
- webusb.deviceProtocol.set(p, 'V1');
74
- return Promise.resolve('V1');
75
- });
76
-
77
- await expect(webusb.acquire({ path, expectedProtocol: 'V1' })).resolves.toBe(path);
78
-
79
- expect(webusb.detectProtocol).toHaveBeenCalledTimes(1);
80
- expect(webusb.staleProtocolPaths.has(path)).toBe(false);
81
- });
82
-
83
- test('release keeps the cached V1 protocol so the next acquire can reuse it', async () => {
84
- const webusb = new WebUsbTransport() as any;
85
- const path = 'pro-webusb';
86
- webusb.deviceProtocol.set(path, 'V1');
87
- webusb.deviceProtocolHints.set(path, 'V2');
88
- webusb.deviceEndpoints.set(path, { interfaceNumber: 0, endpointIn: 1, endpointOut: 1 });
89
- webusb.acquiredPaths.add(path);
90
- webusb.closeOpenDevice = jest.fn().mockResolvedValue(undefined);
91
-
92
- await webusb.release(path);
93
-
94
- expect(webusb.deviceProtocol.get(path)).toBe('V1');
95
- expect(webusb.deviceProtocolHints.get(path)).toBe('V2');
96
- expect(webusb.deviceEndpoints.has(path)).toBe(false);
97
- expect(webusb.acquiredPaths.has(path)).toBe(false);
98
- });
99
-
100
- test('release still drops a cached V2 protocol through link invalidation', async () => {
101
- const webusb = new WebUsbTransport() as any;
102
- const path = 'pro2-webusb';
103
- webusb.Log = { debug: jest.fn() };
104
- webusb.messages = transport.parseConfigure(schema);
105
- webusb.messagesV2 = transport.parseConfigure(schema);
106
- webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
107
- let markReadStarted: () => void = () => undefined;
108
- const readStarted = new Promise<void>(resolve => {
109
- markReadStarted = resolve;
110
- });
111
- webusb.readProtocolV2UsbPacket = jest.fn().mockImplementation(() => {
112
- markReadStarted();
113
- return new Promise<void>(() => {});
114
- });
115
- webusb.closeOpenDevice = jest.fn().mockResolvedValue(undefined);
116
- webusb.deviceProtocol.set(path, 'V2');
117
- await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
118
-
119
- const call = webusb.callProtocolV2(path, 'Ping', { message: 'release' });
120
- await readStarted;
121
- await webusb.release(path);
122
-
123
- await expect(call).rejects.toThrow('WebUSB transport released');
124
- expect(webusb.deviceProtocol.has(path)).toBe(false);
125
- });
126
-
127
- test('call and post fail fast for a path that is not acquired', async () => {
128
- const webusb = new WebUsbTransport() as any;
129
- const path = 'pro-webusb';
130
- webusb.Log = { debug: jest.fn() };
131
- webusb.messages = transport.parseConfigure(schema);
132
- webusb.messagesV2 = transport.parseConfigure(schema);
133
- // A surviving protocol cache entry must NOT act as a session token.
134
- webusb.deviceProtocol.set(path, 'V1');
135
-
136
- await expect(webusb.call(path, 'Ping', {})).rejects.toMatchObject({
137
- errorCode: HardwareErrorCode.RuntimeError,
138
- message: expect.stringContaining('not acquired'),
139
- });
140
- await expect(webusb.post(path, 'Ping', {})).rejects.toMatchObject({
141
- errorCode: HardwareErrorCode.RuntimeError,
142
- message: expect.stringContaining('not acquired'),
143
- });
144
- });
145
-
146
- test('a transfer-level reconnect marks the protocol stale for the next acquire', async () => {
147
- const webusb = new WebUsbTransport() as any;
148
- const path = 'pro-webusb';
149
- webusb.Log = { debug: jest.fn() };
150
- webusb.deviceProtocol.set(path, 'V1');
151
- webusb.findDevice = jest.fn().mockResolvedValue({ opened: false });
152
- webusb.getConnectedDevices = jest.fn().mockResolvedValue([]);
153
- webusb.connect = jest.fn().mockResolvedValue(undefined);
154
-
155
- await webusb.reconnectForPacketIoRetry(path, 'in', 0, new Error('transferIn failed'));
156
-
157
- // The in-flight call keeps the cached protocol; only the next acquire re-probes.
158
- expect(webusb.deviceProtocol.get(path)).toBe('V1');
159
- expect(webusb.staleProtocolPaths.has(path)).toBe(true);
160
- });
161
-
162
- test('USB disconnect marks the serial stale and the listener attaches only once', () => {
163
- const addEventListener = jest.fn();
164
- const usb = { addEventListener } as unknown as USB;
165
- const originalNavigator = (globalThis as any).navigator;
166
- Object.defineProperty(globalThis, 'navigator', {
167
- value: { usb },
168
- configurable: true,
169
- });
170
- try {
171
- const first = new WebUsbTransport() as any;
172
- first.init({ debug: jest.fn() });
173
- const second = new WebUsbTransport() as any;
174
- second.init({ debug: jest.fn() });
175
-
176
- // Module-level listener: one registration across instances.
177
- expect(addEventListener).toHaveBeenCalledTimes(1);
178
- const handler = addEventListener.mock.calls[0][1] as (event: {
179
- device?: { serialNumber?: string | null };
180
- }) => void;
181
-
182
- const path = 'pro-webusb';
183
- first.deviceProtocol.set(path, 'V1');
184
- second.deviceProtocol.set(path, 'V1');
185
- handler({ device: { serialNumber: path } });
186
-
187
- // Routed to the most recently initialized instance; the cached value is
188
- // retained (in-flight sessions keep working) but marked stale.
189
- expect(second.staleProtocolPaths.has(path)).toBe(true);
190
- expect(second.deviceProtocol.get(path)).toBe('V1');
191
- expect(first.staleProtocolPaths.has(path)).toBe(false);
192
-
193
- // Events without a usable serial are ignored.
194
- handler({ device: { serialNumber: null } });
195
- handler({});
196
- expect(second.staleProtocolPaths.size).toBe(1);
197
- } finally {
198
- Object.defineProperty(globalThis, 'navigator', {
199
- value: originalNavigator,
200
- configurable: true,
201
- });
202
- }
203
- });
204
- });