@onekeyfe/hd-transport-web-device 1.2.0-alpha.2 → 1.2.0-alpha.20

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.js CHANGED
@@ -41,6 +41,14 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
41
41
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
42
42
  };
43
43
 
44
+ const HIGH_VOLUME_CALLS = new Set(['FileWrite', 'FilesystemFileWrite', 'EmmcFileWrite']);
45
+ function shouldSuppressHighVolumeCallLog(name) {
46
+ return HIGH_VOLUME_CALLS.has(name);
47
+ }
48
+ function createTransportCallLog(name, protocol) {
49
+ return { name, protocol };
50
+ }
51
+
44
52
  const { parseConfigure: parseConfigure$1, check: check$1, ProtocolV1: ProtocolV1$1 } = transport__default["default"];
45
53
  const CONFIGURATION_ID = 1;
46
54
  const INTERFACE_ID = 0;
@@ -52,19 +60,6 @@ const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
52
60
  const PACKET_IO_MAX_RETRIES = 3;
53
61
  const PACKET_IO_RETRY_DELAY = 300;
54
62
  const PROTOCOL_PROBE_TIMEOUT = 1000;
55
- const WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
56
- function shouldSuppressWebUsbCallLog(name) {
57
- const normalized = name.replace(/[_\s-]/g, '');
58
- return WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
59
- }
60
- function isLogBlockCommand$1(name) {
61
- var _a, _b;
62
- return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
63
- }
64
- function shouldBlockWebUsbCallDataLog(name) {
65
- const normalized = name.replace(/[_\s-]/g, '');
66
- return isLogBlockCommand$1(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
67
- }
68
63
  function inferProtocolHintFromDeviceName$1(name) {
69
64
  return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
70
65
  }
@@ -74,7 +69,9 @@ class WebUsbTransport {
74
69
  this.deviceProtocolHints = new Map();
75
70
  this.protocolV2Assemblers = new Map();
76
71
  this.protocolV2Sessions = new Map();
72
+ this.protocolV2Sequences = new Map();
77
73
  this.protocolV2ReadTimeouts = new Map();
74
+ this.protocolV2WriteTimeoutMs = transport.PROTOCOL_V2_WRITE_WATCHDOG_TIMEOUT_MS;
78
75
  this.deviceEndpoints = new Map();
79
76
  this.mockSerialPaths = new WeakMap();
80
77
  this.mockSerialCounter = 0;
@@ -100,11 +97,9 @@ class WebUsbTransport {
100
97
  this.messages = messages;
101
98
  }
102
99
  configureProtocolV2(signedData) {
103
- var _a;
104
100
  this.messagesV2 = parseConfigure$1(signedData);
105
101
  this.protocolV2Sessions.clear();
106
102
  this.protocolV2ReadTimeouts.clear();
107
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] Protocol V2 schema configured');
108
103
  }
109
104
  promptDeviceAccess() {
110
105
  return __awaiter(this, void 0, void 0, function* () {
@@ -145,7 +140,10 @@ class WebUsbTransport {
145
140
  if (!this.usb)
146
141
  return [];
147
142
  const devices = yield this.usb.getDevices();
148
- const onekeyDevices = devices.filter(dev => hdShared.ONEKEY_WEBUSB_FILTER.some(desc => dev.vendorId === desc.vendorId && dev.productId === desc.productId));
143
+ const onekeyDevices = devices.filter(dev => {
144
+ const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
145
+ return isOneKey && !hdShared.isKnownTrezorWebUsbDevice(dev);
146
+ });
149
147
  this.deviceList = onekeyDevices.map(device => {
150
148
  const path = this.getDevicePath(device);
151
149
  const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
@@ -158,10 +156,6 @@ class WebUsbTransport {
158
156
  commType: 'webusb',
159
157
  };
160
158
  });
161
- for (const dev of onekeyDevices) {
162
- this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
163
- `VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
164
- }
165
159
  return this.deviceList;
166
160
  });
167
161
  }
@@ -200,14 +194,13 @@ class WebUsbTransport {
200
194
  if (expectedProtocol === 'V1') {
201
195
  if (yield this.probeProtocolV1(path)) {
202
196
  this.deviceProtocol.set(path, 'V1');
203
- this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
204
197
  return 'V1';
205
198
  }
199
+ yield this.resetConnectionAfterProbe(path);
206
200
  throw this.createProtocolMismatchError(expectedProtocol);
207
201
  }
208
202
  if (expectedProtocol === 'V2') {
209
203
  this.deviceProtocol.set(path, 'V2');
210
- this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
211
204
  return 'V2';
212
205
  }
213
206
  const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
@@ -215,9 +208,11 @@ class WebUsbTransport {
215
208
  const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
216
209
  if (detected) {
217
210
  this.deviceProtocol.set(path, protocol);
218
- this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
219
211
  return protocol;
220
212
  }
213
+ if (protocol === 'V1') {
214
+ yield this.resetConnectionAfterProbe(path);
215
+ }
221
216
  }
222
217
  this.deviceProtocol.delete(path);
223
218
  throw this.createProtocolDetectionError();
@@ -287,7 +282,6 @@ class WebUsbTransport {
287
282
  var _a, _b;
288
283
  return __awaiter(this, void 0, void 0, function* () {
289
284
  let device = yield this.findDevice(path);
290
- this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
291
285
  if (!device.opened) {
292
286
  yield device.open();
293
287
  }
@@ -420,19 +414,11 @@ class WebUsbTransport {
420
414
  return copied.buffer;
421
415
  }
422
416
  transferOutWithRetry(path, packet) {
423
- var _a;
424
417
  return __awaiter(this, void 0, void 0, function* () {
425
418
  let lastError;
426
419
  for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
427
420
  try {
428
- const device = yield this.findDevice(path);
429
- if (!device.opened) {
430
- yield this.connect(path, false);
431
- }
432
- const endpoints = this.deviceEndpoints.get(path);
433
- const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
434
- const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
435
- yield device.transferOut(endpointOut, transferBuffer);
421
+ yield this.transferOutOnce(path, packet);
436
422
  return;
437
423
  }
438
424
  catch (error) {
@@ -453,6 +439,19 @@ class WebUsbTransport {
453
439
  throw lastError;
454
440
  });
455
441
  }
442
+ transferOutOnce(path, packet) {
443
+ var _a;
444
+ return __awaiter(this, void 0, void 0, function* () {
445
+ const device = yield this.findDevice(path);
446
+ if (!device.opened) {
447
+ yield this.connect(path, false);
448
+ }
449
+ const endpoints = this.deviceEndpoints.get(path);
450
+ const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
451
+ const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
452
+ yield device.transferOut(endpointOut, transferBuffer);
453
+ });
454
+ }
456
455
  transferInWithRetry(path, length, cancelToken) {
457
456
  var _a;
458
457
  return __awaiter(this, void 0, void 0, function* () {
@@ -519,7 +518,7 @@ class WebUsbTransport {
519
518
  yield this.connect(path, false);
520
519
  });
521
520
  }
522
- withProtocolReadTimeout(path, promise, timeoutMs, protocol, onTimeout) {
521
+ withProtocolReadTimeout(_path, promise, timeoutMs, protocol, onTimeout) {
523
522
  return __awaiter(this, void 0, void 0, function* () {
524
523
  let timer;
525
524
  let timedOut = false;
@@ -534,11 +533,11 @@ class WebUsbTransport {
534
533
  return yield Promise.race([
535
534
  guardedPromise,
536
535
  new Promise((_, reject) => {
537
- timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
536
+ timer = setTimeout(() => {
538
537
  timedOut = true;
539
538
  onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
540
539
  reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
541
- }), timeoutMs);
540
+ }, timeoutMs);
542
541
  }),
543
542
  ]);
544
543
  }
@@ -557,8 +556,7 @@ class WebUsbTransport {
557
556
  yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
558
557
  return true;
559
558
  }
560
- catch (error) {
561
- this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
559
+ catch (_error) {
562
560
  return false;
563
561
  }
564
562
  });
@@ -573,7 +571,6 @@ class WebUsbTransport {
573
571
  timeoutMs: PROTOCOL_PROBE_TIMEOUT,
574
572
  logger: this.Log,
575
573
  logPrefix: 'ProtocolV2 WebUSB',
576
- onProbeFailed: () => this.resetConnectionAfterProbe(path),
577
574
  });
578
575
  });
579
576
  }
@@ -590,12 +587,8 @@ class WebUsbTransport {
590
587
  if (!protocol) {
591
588
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
592
589
  }
593
- if (shouldSuppressWebUsbCallLog(name)) ;
594
- else if (shouldBlockWebUsbCallDataLog(name)) {
595
- this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
596
- }
597
- else {
598
- this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
590
+ if (!shouldSuppressHighVolumeCallLog(name)) {
591
+ this.Log.debug('transport call', createTransportCallLog(name, protocol));
599
592
  }
600
593
  if (protocol === 'V2') {
601
594
  return this.callProtocolV2(path, name, data, options);
@@ -636,13 +629,20 @@ class WebUsbTransport {
636
629
  }
637
630
  let session = this.protocolV2Sessions.get(path);
638
631
  if (!session) {
632
+ let sequenceCursor = this.protocolV2Sequences.get(path);
633
+ if (!sequenceCursor) {
634
+ sequenceCursor = new transport.ProtocolV2SequenceCursor();
635
+ this.protocolV2Sequences.set(path, sequenceCursor);
636
+ }
639
637
  session = new transport.ProtocolV2Session({
640
638
  schemas: {
641
639
  protocolV1: protocolV1Messages,
642
640
  protocolV2: this.messagesV2,
643
641
  },
644
642
  router: transport.PROTOCOL_V2_CHANNEL_USB,
645
- writeFrame: (frame) => this.transferOutWithRetry(path, frame),
643
+ sequenceCursor,
644
+ writeTimeoutMs: this.protocolV2WriteTimeoutMs,
645
+ writeFrame: (frame) => this.transferOutOnce(path, frame),
646
646
  readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
647
647
  logger: this.Log,
648
648
  logPrefix: 'ProtocolV2 WebUSB',
@@ -655,6 +655,21 @@ class WebUsbTransport {
655
655
  try {
656
656
  return yield session.call(name, data, options);
657
657
  }
658
+ catch (error) {
659
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
660
+ if (message.includes('protocol v2 read timeout') ||
661
+ message.includes('protocol v2 write timeout') ||
662
+ message.includes('protocol v2 delivery timeout') ||
663
+ message.includes('response timeout')) {
664
+ try {
665
+ yield this.resetConnectionAfterProbe(path);
666
+ }
667
+ catch (resetError) {
668
+ this.Log.debug('[WebUsbTransport] Protocol V2 timeout reset failed:', resetError);
669
+ }
670
+ }
671
+ throw error;
672
+ }
658
673
  finally {
659
674
  this.protocolV2ReadTimeouts.delete(path);
660
675
  }
@@ -737,6 +752,8 @@ class WebUsbTransport {
737
752
  this.deviceProtocolHints.delete(path);
738
753
  (_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
739
754
  this.protocolV2Assemblers.delete(path);
755
+ this.protocolV2Sessions.delete(path);
756
+ this.protocolV2ReadTimeouts.delete(path);
740
757
  this.deviceEndpoints.delete(path);
741
758
  });
742
759
  }
@@ -745,15 +762,6 @@ class WebUsbTransport {
745
762
  }
746
763
  }
747
764
 
748
- const FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
749
- function shouldSuppressHighVolumeCallLog(name) {
750
- const normalized = name.replace(/[_\s-]/g, '');
751
- return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
752
- }
753
- function isLogBlockCommand(name) {
754
- var _a, _b;
755
- return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
756
- }
757
765
  const { parseConfigure, ProtocolV1, check } = transport__default["default"];
758
766
  function inferProtocolHintFromDeviceName(name) {
759
767
  return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
@@ -761,8 +769,6 @@ function inferProtocolHintFromDeviceName(name) {
761
769
  const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
762
770
  const BLE_PACKET_SIZE = 192;
763
771
  const BLE_WRITE_DELAY_MS = 5;
764
- const BLE_WRITE_MAX_RETRIES = 3;
765
- const BLE_WRITE_RETRY_DELAY_MS = 300;
766
772
  const BLE_RESPONSE_TIMEOUT_MS = 30000;
767
773
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
768
774
  const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
@@ -778,8 +784,27 @@ class ElectronBleTransport {
778
784
  this.v2Assemblers = new Map();
779
785
  this.v2FrameQueues = new Map();
780
786
  this.v2FramePromises = new Map();
781
- this.activeProtocolV2Call = null;
782
- this.nextProtocolV2CallToken = 1;
787
+ this.protocolV2Links = new transport.ProtocolV2LinkManager({
788
+ getSchemas: () => {
789
+ if (!this._messages || !this._messagesV2) {
790
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
791
+ }
792
+ return {
793
+ protocolV1: this._messages,
794
+ protocolV2: this._messagesV2,
795
+ };
796
+ },
797
+ classifyError: () => 'link-fatal',
798
+ onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
799
+ var _a, _b;
800
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
801
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
802
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
803
+ if (reason.startsWith('Protocol V2 link-fatal error:')) {
804
+ yield this.release(uuid);
805
+ }
806
+ }),
807
+ });
783
808
  this.notificationCleanups = new Map();
784
809
  this.disconnectCleanups = new Map();
785
810
  this.notificationTokens = new Map();
@@ -815,15 +840,14 @@ class ElectronBleTransport {
815
840
  throw error;
816
841
  }
817
842
  cleanupDeviceState(deviceId) {
818
- var _a;
843
+ this.protocolV2Links
844
+ .invalidateLink(deviceId, 'Electron BLE device state cleaned')
845
+ .catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
819
846
  this.connectedDevices.delete(deviceId);
820
847
  this.deviceProtocol.delete(deviceId);
821
848
  this.v1Buffers.delete(deviceId);
822
849
  this.v2Assemblers.delete(deviceId);
823
850
  this.resetProtocolV2Frames(deviceId);
824
- if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
825
- this.activeProtocolV2Call = null;
826
- }
827
851
  this.notificationTokens.delete(deviceId);
828
852
  const notifyCleanup = this.notificationCleanups.get(deviceId);
829
853
  if (notifyCleanup) {
@@ -850,9 +874,10 @@ class ElectronBleTransport {
850
874
  this.configured = true;
851
875
  }
852
876
  configureProtocolV2(signedData) {
853
- var _a;
854
877
  this._messagesV2 = parseConfigure(signedData);
855
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V2 schema configured');
878
+ this.protocolV2Links
879
+ .invalidateAllLinks('Protocol V2 schema reconfigured')
880
+ .catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
856
881
  }
857
882
  listen() {
858
883
  return __awaiter(this, void 0, void 0, function* () {
@@ -890,12 +915,14 @@ class ElectronBleTransport {
890
915
  if (!uuid) {
891
916
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
892
917
  }
918
+ if (this.connectedDevices.has(uuid)) {
919
+ yield this.release(uuid);
920
+ }
893
921
  if (forceCleanRunPromise && this.runPromise) {
894
922
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
895
923
  this.runPromise.reject(error);
896
924
  this.rejectAllProtocolV2Frames(error);
897
925
  this.runPromise = null;
898
- this.activeProtocolV2Call = null;
899
926
  }
900
927
  try {
901
928
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
@@ -963,6 +990,7 @@ class ElectronBleTransport {
963
990
  var _a, _b;
964
991
  return __awaiter(this, void 0, void 0, function* () {
965
992
  try {
993
+ yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
966
994
  if (this.connectedDevices.has(id)) {
967
995
  if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
968
996
  yield window.desktopApi.nobleBle.unsubscribe(id);
@@ -1036,14 +1064,12 @@ class ElectronBleTransport {
1036
1064
  });
1037
1065
  }
1038
1066
  resetProbeStateAfterProtocolProbe(uuid, protocol) {
1039
- var _a, _b, _c, _d, _e, _f, _g, _h;
1067
+ var _a, _b, _c, _d, _e, _f, _g;
1040
1068
  return __awaiter(this, void 0, void 0, function* () {
1069
+ yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
1041
1070
  this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
1042
1071
  (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1043
1072
  this.resetProtocolV2Frames(uuid);
1044
- if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
1045
- this.activeProtocolV2Call = null;
1046
- }
1047
1073
  if (this.runPromise) {
1048
1074
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1049
1075
  this.runPromise.reject(error);
@@ -1056,16 +1082,16 @@ class ElectronBleTransport {
1056
1082
  }
1057
1083
  this.notificationTokens.delete(uuid);
1058
1084
  try {
1059
- yield ((_d = (_c = window.desktopApi) === null || _c === void 0 ? void 0 : _c.nobleBle) === null || _d === void 0 ? void 0 : _d.unsubscribe(uuid));
1085
+ yield ((_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.unsubscribe(uuid));
1060
1086
  }
1061
1087
  catch (error) {
1062
- (_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
1088
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
1063
1089
  }
1064
1090
  try {
1065
- yield ((_g = (_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle) === null || _g === void 0 ? void 0 : _g.subscribe(uuid));
1091
+ yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.subscribe(uuid));
1066
1092
  }
1067
1093
  catch (error) {
1068
- (_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
1094
+ (_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
1069
1095
  throw error;
1070
1096
  }
1071
1097
  const cleanup = this.createNotificationSubscription(uuid);
@@ -1120,52 +1146,40 @@ class ElectronBleTransport {
1120
1146
  const totalBytes = hexData.length / 2;
1121
1147
  if (totalBytes <= BLE_PACKET_SIZE) {
1122
1148
  yield hdShared.wait(BLE_WRITE_DELAY_MS);
1123
- yield this.writeWithRetry(uuid, hexData);
1149
+ yield this.writeOnce(uuid, hexData);
1124
1150
  return;
1125
1151
  }
1126
1152
  for (let offset = 0; offset < hexData.length;) {
1127
1153
  const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
1128
1154
  const chunkHex = hexData.substring(offset, offset + chunkHexLen);
1129
1155
  offset += chunkHexLen;
1130
- yield this.writeWithRetry(uuid, chunkHex);
1156
+ yield this.writeOnce(uuid, chunkHex);
1131
1157
  if (offset < hexData.length) {
1132
1158
  yield hdShared.wait(BLE_WRITE_DELAY_MS);
1133
1159
  }
1134
1160
  }
1135
1161
  });
1136
1162
  }
1137
- writeWithRetry(uuid, hexData) {
1138
- var _a, _b, _c;
1163
+ writeOnce(uuid, hexData) {
1164
+ var _a;
1139
1165
  return __awaiter(this, void 0, void 0, function* () {
1140
- let lastError;
1141
1166
  const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
1142
1167
  if (!nobleBle) {
1143
1168
  throw new Error('Noble BLE API not available');
1144
1169
  }
1145
- for (let attempt = 1; attempt <= BLE_WRITE_MAX_RETRIES; attempt++) {
1146
- try {
1147
- yield nobleBle.write(uuid, hexData);
1148
- return;
1149
- }
1150
- catch (error) {
1151
- lastError = error;
1152
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error(`[Electron BLE] write failed (attempt ${attempt}/${BLE_WRITE_MAX_RETRIES}):`, error);
1153
- if (attempt < BLE_WRITE_MAX_RETRIES) {
1154
- yield hdShared.wait(BLE_WRITE_RETRY_DELAY_MS);
1155
- }
1156
- }
1157
- }
1158
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write failed after ${BLE_WRITE_MAX_RETRIES} attempts: ${(_c = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _c !== void 0 ? _c : lastError}`);
1170
+ yield nobleBle.write(uuid, hexData);
1159
1171
  });
1160
1172
  }
1161
1173
  handleNotification(deviceId, hexData) {
1162
1174
  var _a, _b;
1163
1175
  if (hexData === 'PAIRING_REJECTED') {
1164
1176
  (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
1165
- if (this.runPromise) {
1166
- const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
1177
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
1178
+ if (this.deviceProtocol.get(deviceId) === 'V2') {
1179
+ this.rejectProtocolV2Frames(deviceId, error);
1180
+ }
1181
+ else if (this.runPromise) {
1167
1182
  this.runPromise.reject(error);
1168
- this.rejectAllProtocolV2Frames(error);
1169
1183
  }
1170
1184
  return;
1171
1185
  }
@@ -1181,13 +1195,8 @@ class ElectronBleTransport {
1181
1195
  this.handleProtocolV1Notification(deviceId, hexData);
1182
1196
  }
1183
1197
  handleProtocolV2Notification(deviceId, hexData) {
1184
- var _a, _b, _c;
1198
+ var _a;
1185
1199
  try {
1186
- if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
1187
- (_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
1188
- this.resetProtocolV2Frames(deviceId);
1189
- return;
1190
- }
1191
1200
  const bytes = transport.hexToBytes(hexData);
1192
1201
  if (bytes.length === 0)
1193
1202
  return;
@@ -1199,12 +1208,9 @@ class ElectronBleTransport {
1199
1208
  }
1200
1209
  }
1201
1210
  catch (error) {
1202
- (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Electron BLE] Protocol V2 notification error:', error);
1203
- if (this.runPromise) {
1204
- const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1205
- this.runPromise.reject(notifyError);
1206
- this.rejectAllProtocolV2Frames(notifyError);
1207
- }
1211
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 notification error:', error);
1212
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1213
+ this.rejectProtocolV2Frames(deviceId, notifyError);
1208
1214
  }
1209
1215
  }
1210
1216
  getProtocolV2FrameQueue(uuid) {
@@ -1235,9 +1241,13 @@ class ElectronBleTransport {
1235
1241
  this.v2FrameQueues.delete(uuid);
1236
1242
  this.v2FramePromises.delete(uuid);
1237
1243
  }
1238
- isActiveProtocolV2Call(uuid, token) {
1239
- var _a;
1240
- return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
1244
+ rejectProtocolV2Frames(uuid, error) {
1245
+ this.v2FrameQueues.delete(uuid);
1246
+ const framePromise = this.v2FramePromises.get(uuid);
1247
+ if (framePromise) {
1248
+ this.v2FramePromises.delete(uuid);
1249
+ framePromise.reject(error);
1250
+ }
1241
1251
  }
1242
1252
  readProtocolV2Frame(uuid) {
1243
1253
  return __awaiter(this, void 0, void 0, function* () {
@@ -1272,7 +1282,7 @@ class ElectronBleTransport {
1272
1282
  }
1273
1283
  }
1274
1284
  call(uuid, name, data, options) {
1275
- var _a, _b;
1285
+ var _a;
1276
1286
  return __awaiter(this, void 0, void 0, function* () {
1277
1287
  if (!this._messages) {
1278
1288
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
@@ -1284,12 +1294,8 @@ class ElectronBleTransport {
1284
1294
  if (!protocol) {
1285
1295
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
1286
1296
  }
1287
- if (shouldSuppressHighVolumeCallLog(name)) ;
1288
- else if (isLogBlockCommand(name)) {
1289
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
1290
- }
1291
- else {
1292
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
1297
+ if (!shouldSuppressHighVolumeCallLog(name)) {
1298
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', createTransportCallLog(name, protocol));
1293
1299
  }
1294
1300
  if (protocol === 'V2') {
1295
1301
  return this.callProtocolV2(uuid, name, data, options);
@@ -1360,76 +1366,60 @@ class ElectronBleTransport {
1360
1366
  });
1361
1367
  }
1362
1368
  callProtocolV2(uuid, name, data, options) {
1363
- var _a, _b, _c, _d, _e;
1369
+ var _a, _b;
1364
1370
  return __awaiter(this, void 0, void 0, function* () {
1365
1371
  if (!this._messages || !this._messagesV2) {
1366
1372
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1367
1373
  }
1368
- const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
1369
- if (this.runPromise) {
1370
- if (!forceRun) {
1371
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1372
- }
1373
- const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1374
- this.runPromise.reject(error);
1375
- this.rejectAllProtocolV2Frames(error);
1376
- this.runPromise = null;
1377
- this.activeProtocolV2Call = null;
1378
- }
1379
- const runPromise = hdShared.createDeferred();
1380
- runPromise.promise.catch(() => undefined);
1381
- this.runPromise = runPromise;
1382
- const callToken = this.nextProtocolV2CallToken++;
1383
- this.activeProtocolV2Call = { uuid, token: callToken };
1384
- (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1385
- this.resetProtocolV2Frames(uuid);
1386
- let completed = false;
1387
- const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
1374
+ const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : BLE_RESPONSE_TIMEOUT_MS });
1388
1375
  try {
1389
- const session = new transport.ProtocolV2Session({
1390
- schemas: {
1391
- protocolV1: this._messages,
1392
- protocolV2: this._messagesV2,
1393
- },
1394
- router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1395
- writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
1396
- readFrame: () => __awaiter(this, void 0, void 0, function* () {
1397
- const rxFrame = yield this.readProtocolV2Frame(uuid);
1398
- if (!(rxFrame instanceof Uint8Array)) {
1399
- throw new Error('Response is not Uint8Array');
1400
- }
1401
- return rxFrame;
1402
- }),
1403
- logger: this.Log,
1404
- logPrefix: 'ProtocolV2 BLE',
1405
- createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1406
- });
1407
- const result = yield session.call(name, data, callOptions);
1408
- completed = true;
1409
- return result;
1376
+ return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
1410
1377
  }
1411
1378
  catch (e) {
1412
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1413
- (_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1414
- this.resetProtocolV2Frames(uuid);
1415
- }
1416
- (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] Protocol V2 call error:', e);
1379
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V2 call error:', e);
1417
1380
  throw e;
1418
1381
  }
1419
- finally {
1420
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1421
- if (!completed) {
1422
- (_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
1423
- }
1424
- this.resetProtocolV2Frames(uuid);
1425
- this.activeProtocolV2Call = null;
1426
- }
1427
- if (this.runPromise === runPromise) {
1428
- this.runPromise = null;
1429
- }
1430
- }
1431
1382
  });
1432
1383
  }
1384
+ createProtocolV2Adapter(uuid) {
1385
+ var _a;
1386
+ const generation = (_a = this.notificationTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
1387
+ const assertCurrentGeneration = () => {
1388
+ if (this.notificationTokens.get(uuid) !== generation) {
1389
+ throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
1390
+ }
1391
+ };
1392
+ return {
1393
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1394
+ generation,
1395
+ prepareCall: () => {
1396
+ var _a;
1397
+ assertCurrentGeneration();
1398
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1399
+ this.resetProtocolV2Frames(uuid);
1400
+ },
1401
+ writeFrame: (frame) => {
1402
+ assertCurrentGeneration();
1403
+ return this.writeWithChunking(uuid, transport.bytesToHex(frame));
1404
+ },
1405
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1406
+ assertCurrentGeneration();
1407
+ const rxFrame = yield this.readProtocolV2Frame(uuid);
1408
+ if (!(rxFrame instanceof Uint8Array)) {
1409
+ throw new Error('Response is not Uint8Array');
1410
+ }
1411
+ return rxFrame;
1412
+ }),
1413
+ reset: (reason) => {
1414
+ var _a;
1415
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1416
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
1417
+ },
1418
+ logger: this.Log,
1419
+ logPrefix: 'ProtocolV2 BLE',
1420
+ createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
1421
+ };
1422
+ }
1433
1423
  processProtocolV1Notification(deviceId, hexData) {
1434
1424
  try {
1435
1425
  if (typeof hexData !== 'string') {
@@ -0,0 +1,7 @@
1
+ import type { ProtocolType } from '@onekeyfe/hd-transport';
2
+ export declare function shouldSuppressHighVolumeCallLog(name: string): boolean;
3
+ export declare function createTransportCallLog(name: string, protocol: ProtocolType): {
4
+ name: string;
5
+ protocol: ProtocolType;
6
+ };
7
+ //# sourceMappingURL=transportLog.d.ts.map