@trezor/connect 9.4.8-beta.2 → 9.5.0

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +59 -44
  2. package/README.md +1 -1
  3. package/lib/api/authorizeCoinjoin.js +1 -1
  4. package/lib/api/binance/api/binanceGetAddress.js +2 -4
  5. package/lib/api/binance/api/binanceGetPublicKey.js +1 -0
  6. package/lib/api/binance/api/binanceSignTransaction.js +1 -2
  7. package/lib/api/bitcoin/Fees.js +4 -1
  8. package/lib/api/bitcoin/TransactionComposer.js +9 -2
  9. package/lib/api/bitcoin/enhanceSignTx.js +1 -2
  10. package/lib/api/bitcoin/refTx.js +4 -6
  11. package/lib/api/blockchainDisconnect.js +1 -1
  12. package/lib/api/blockchainSubscribe.js +1 -2
  13. package/lib/api/blockchainUnsubscribe.js +1 -2
  14. package/lib/api/cardano/api/cardanoComposeTransaction.js +1 -1
  15. package/lib/api/cardano/api/cardanoGetAddress.js +2 -4
  16. package/lib/api/cardano/api/cardanoGetPublicKey.js +1 -0
  17. package/lib/api/cardano/cardanoAuxiliaryData.js +2 -2
  18. package/lib/api/cardano/cardanoUtils.js +5 -6
  19. package/lib/api/cipherKeyValue.js +1 -0
  20. package/lib/api/common/Discovery.js +16 -1
  21. package/lib/api/common/paramsValidator.js +2 -2
  22. package/lib/api/composeTransaction.js +6 -6
  23. package/lib/api/eos/api/eosGetPublicKey.js +1 -0
  24. package/lib/api/ethereum/api/ethereumGetAddress.js +2 -4
  25. package/lib/api/ethereum/api/ethereumGetPublicKey.js +1 -0
  26. package/lib/api/ethereum/api/ethereumSignMessage.js +1 -2
  27. package/lib/api/ethereum/api/ethereumSignTransaction.js +1 -1
  28. package/lib/api/ethereum/api/ethereumSignTypedData.js +1 -1
  29. package/lib/api/ethereum/ethereumDefinitions.js +2 -2
  30. package/lib/api/ethereum/ethereumSignTx.d.ts +2 -2
  31. package/lib/api/ethereum/ethereumSignTx.js +3 -2
  32. package/lib/api/firmware/verifyAuthenticityProof.js +3 -3
  33. package/lib/api/getAccountDescriptor.js +2 -4
  34. package/lib/api/getAccountInfo.js +4 -5
  35. package/lib/api/getAddress.js +5 -8
  36. package/lib/api/getDeviceState.js +1 -1
  37. package/lib/api/getOwnershipId.js +1 -0
  38. package/lib/api/getOwnershipProof.js +1 -0
  39. package/lib/api/getPublicKey.js +3 -2
  40. package/lib/api/nem/api/nemGetAddress.js +2 -4
  41. package/lib/api/nem/api/nemSignTransaction.js +1 -2
  42. package/lib/api/requestLogin.js +1 -0
  43. package/lib/api/ripple/api/rippleGetAddress.js +2 -4
  44. package/lib/api/signMessage.js +1 -2
  45. package/lib/api/signTransaction.js +6 -8
  46. package/lib/api/solana/additionalInfo.js +2 -3
  47. package/lib/api/solana/api/solanaComposeTransaction.js +2 -3
  48. package/lib/api/solana/api/solanaGetAddress.js +2 -4
  49. package/lib/api/solana/api/solanaGetPublicKey.js +1 -0
  50. package/lib/api/solana/solanaUtils.js +6 -5
  51. package/lib/api/stellar/api/stellarGetAddress.js +2 -4
  52. package/lib/api/tezos/api/tezosGetAddress.js +2 -4
  53. package/lib/api/tezos/api/tezosGetPublicKey.js +1 -0
  54. package/lib/backend/BackendManager.js +11 -16
  55. package/lib/backend/Blockchain.js +10 -4
  56. package/lib/backend/BlockchainLink.js +1 -1
  57. package/lib/constants/errors.js +2 -0
  58. package/lib/core/AbstractMethod.js +30 -5
  59. package/lib/core/index.js +24 -34
  60. package/lib/core/onCallFirmwareUpdate.d.ts +3 -2
  61. package/lib/core/onCallFirmwareUpdate.js +12 -59
  62. package/lib/data/DataManager.js +3 -2
  63. package/lib/data/analyticsInfo.js +10 -11
  64. package/lib/data/connectSettings.js +3 -2
  65. package/lib/data/defaultFeeLevels.js +4 -7
  66. package/lib/data/deviceAuthenticityConfig.js +16 -1
  67. package/lib/data/firmwareInfo.js +5 -6
  68. package/lib/data/version.d.ts +1 -1
  69. package/lib/data/version.js +1 -1
  70. package/lib/device/Device.d.ts +10 -2
  71. package/lib/device/Device.js +65 -56
  72. package/lib/device/DeviceCommands.d.ts +5 -1
  73. package/lib/device/DeviceCommands.js +7 -2
  74. package/lib/device/DeviceList.d.ts +2 -0
  75. package/lib/device/DeviceList.js +44 -24
  76. package/lib/device/StateStorage.js +5 -6
  77. package/lib/device/checkFirmwareRevision.js +11 -6
  78. package/lib/device/prompts.js +4 -7
  79. package/lib/events/call.d.ts +1 -0
  80. package/lib/events/call.js +3 -3
  81. package/lib/impl/core-in-module.js +25 -23
  82. package/lib/impl/dynamic.js +7 -1
  83. package/lib/index.js +9 -12
  84. package/lib/types/api/ethereum/index.d.ts +4 -4
  85. package/lib/types/api/ethereum/index.js +2 -2
  86. package/lib/types/api/firmwareUpdate.d.ts +1 -8
  87. package/lib/utils/assets.js +1 -1
  88. package/lib/utils/assets.native.js +1 -1
  89. package/lib/utils/hdnodeUtils.js +1 -2
  90. package/lib/utils/interactionTimeout.js +2 -2
  91. package/lib/utils/popupPromiseManager.js +2 -2
  92. package/lib/utils/proxy-event-emitter.js +1 -0
  93. package/lib/utils/uiPromiseManager.js +3 -4
  94. package/lib/utils/urlUtils.js +5 -8
  95. package/package.json +14 -14
  96. package/lib/utils/abortablePromise.d.ts +0 -5
  97. package/lib/utils/abortablePromise.js +0 -17
@@ -20,46 +20,68 @@ const types_1 = require("../types");
20
20
  const debug_1 = require("../utils/debug");
21
21
  const deviceFeaturesUtils_1 = require("../utils/deviceFeaturesUtils");
22
22
  const _log = (0, debug_1.initLog)('Device');
23
- exports.GET_FEATURES_TIMEOUT = 3000;
24
- exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20000;
23
+ exports.GET_FEATURES_TIMEOUT = 3_000;
24
+ exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20_000;
25
25
  const parseRunOptions = (options) => {
26
26
  if (!options)
27
27
  options = {};
28
28
  return options;
29
29
  };
30
30
  class Device extends utils_1.TypedEmitter {
31
+ transport;
32
+ protocol;
33
+ transportPath;
34
+ transportSessionOwner;
35
+ transportDescriptorType;
36
+ session;
37
+ lastAcquiredHere;
38
+ unreadableError;
39
+ _firmwareStatus;
31
40
  get firmwareStatus() {
32
41
  return this._firmwareStatus;
33
42
  }
43
+ _firmwareRelease;
34
44
  get firmwareRelease() {
35
45
  return this._firmwareRelease;
36
46
  }
47
+ _features;
37
48
  get features() {
38
49
  return this._features;
39
50
  }
51
+ _featuresNeedsReload = false;
52
+ acquirePromise;
53
+ releasePromise;
54
+ runPromise;
55
+ keepTransportSession = false;
56
+ commands;
57
+ cancelableAction;
58
+ loaded = false;
59
+ inconsistent = false;
60
+ firstRunPromise;
61
+ instance = 0;
62
+ state = [];
63
+ stateStorage = undefined;
64
+ _unavailableCapabilities = {};
40
65
  get unavailableCapabilities() {
41
66
  return this._unavailableCapabilities;
42
67
  }
68
+ _firmwareType;
43
69
  get firmwareType() {
44
70
  return this._firmwareType;
45
71
  }
72
+ name = 'Trezor';
73
+ color;
74
+ availableTranslations = [];
75
+ authenticityChecks = {
76
+ firmwareRevision: null,
77
+ firmwareHash: null,
78
+ };
79
+ uniquePath;
80
+ emitLifecycle;
81
+ sessionDfd;
82
+ handshakeFinished = false;
46
83
  constructor({ id, transport, descriptor, listener }) {
47
84
  super();
48
- this._featuresNeedsReload = false;
49
- this.keepTransportSession = false;
50
- this.loaded = false;
51
- this.inconsistent = false;
52
- this.instance = 0;
53
- this.state = [];
54
- this.stateStorage = undefined;
55
- this._unavailableCapabilities = {};
56
- this.name = 'Trezor';
57
- this.availableTranslations = [];
58
- this.authenticityChecks = {
59
- firmwareRevision: null,
60
- firmwareHash: null,
61
- };
62
- this.handshakeFinished = false;
63
85
  this.emitLifecycle = listener;
64
86
  this.protocol = protocol_1.v1;
65
87
  this.uniquePath = id;
@@ -107,11 +129,10 @@ class Device extends utils_1.TypedEmitter {
107
129
  .acquire({ input: { path: this.transportPath, previous: this.session } })
108
130
  .then(result => this.waitAndCompareSession(result, sessionPromise))
109
131
  .then(result => {
110
- var _a;
111
132
  if (result.success) {
112
133
  this.session = result.payload;
113
134
  this.lastAcquiredHere = true;
114
- (_a = this.commands) === null || _a === void 0 ? void 0 : _a.dispose();
135
+ this.commands?.dispose();
115
136
  this.commands = new DeviceCommands_1.DeviceCommands(this, this.transport, this.session);
116
137
  return result;
117
138
  }
@@ -165,9 +186,8 @@ class Device extends utils_1.TypedEmitter {
165
186
  }
166
187
  }
167
188
  async handshake(delay) {
168
- var _a;
169
189
  if (delay) {
170
- await (0, utils_1.createTimeoutPromise)(501 + delay);
190
+ await (0, utils_1.resolveAfter)(501 + delay);
171
191
  }
172
192
  while (true) {
173
193
  if (this.isUsedElsewhere()) {
@@ -192,12 +212,12 @@ class Device extends utils_1.TypedEmitter {
192
212
  this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
193
213
  }
194
214
  else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
195
- ((_a = error.message) === null || _a === void 0 ? void 0 : _a.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE)) >= 0) {
196
- this.unreadableError = error === null || error === void 0 ? void 0 : error.message;
215
+ error.message?.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE) >= 0) {
216
+ this.unreadableError = error?.message;
197
217
  this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
198
218
  }
199
219
  else {
200
- await (0, utils_1.createTimeoutPromise)(501);
220
+ await (0, utils_1.resolveAfter)(501);
201
221
  continue;
202
222
  }
203
223
  }
@@ -207,14 +227,13 @@ class Device extends utils_1.TypedEmitter {
207
227
  }
208
228
  }
209
229
  async updateDescriptor(descriptor) {
210
- var _a, _b;
211
- (_a = this.sessionDfd) === null || _a === void 0 ? void 0 : _a.resolve(descriptor.session);
230
+ this.sessionDfd?.resolve(descriptor.session);
212
231
  await Promise.all([this.acquirePromise, this.releasePromise]);
213
232
  if (descriptor.session && descriptor.session !== this.session) {
214
233
  this.usedElsewhere();
215
234
  }
216
235
  if (!descriptor.session) {
217
- const methodStillRunning = !((_b = this.commands) === null || _b === void 0 ? void 0 : _b.isDisposed());
236
+ const methodStillRunning = !this.commands?.isDisposed();
218
237
  if (methodStillRunning) {
219
238
  this.releaseTransportSession();
220
239
  }
@@ -266,10 +285,9 @@ class Device extends utils_1.TypedEmitter {
266
285
  this.cancelableAction = undefined;
267
286
  }
268
287
  async interruptionFromUser(error) {
269
- var _a, _b;
270
288
  _log.debug('interruptionFromUser');
271
- await ((_a = this.cancelableAction) === null || _a === void 0 ? void 0 : _a.call(this, error));
272
- await ((_b = this.commands) === null || _b === void 0 ? void 0 : _b.cancel());
289
+ await this.cancelableAction?.(error);
290
+ await this.commands?.cancel();
273
291
  if (this.runPromise) {
274
292
  this.runPromise.reject(error);
275
293
  delete this.runPromise;
@@ -294,11 +312,10 @@ class Device extends utils_1.TypedEmitter {
294
312
  }
295
313
  }
296
314
  async _runInner(fn, options) {
297
- var _a, _b;
298
315
  if (this.releasePromise) {
299
316
  await this.releasePromise;
300
317
  }
301
- const acquireNeeded = !this.isUsedHere() || ((_a = this.commands) === null || _a === void 0 ? void 0 : _a.disposed);
318
+ const acquireNeeded = !this.isUsedHere() || this.commands?.disposed;
302
319
  if (acquireNeeded) {
303
320
  await this.acquire();
304
321
  }
@@ -353,7 +370,7 @@ class Device extends utils_1.TypedEmitter {
353
370
  await this.checkFirmwareRevisionWithRetries();
354
371
  }
355
372
  if (!options.skipLanguageChecks &&
356
- ((_b = this.features) === null || _b === void 0 ? void 0 : _b.language) &&
373
+ this.features?.language &&
357
374
  !this.features.language_version_matches &&
358
375
  this.atLeast('2.7.0')) {
359
376
  _log.info('language version mismatch. silently updating...');
@@ -409,7 +426,6 @@ class Device extends utils_1.TypedEmitter {
409
426
  return this.state[this.instance];
410
427
  }
411
428
  setState(state) {
412
- var _a;
413
429
  if (!state) {
414
430
  delete this.state[this.instance];
415
431
  }
@@ -420,11 +436,10 @@ class Device extends utils_1.TypedEmitter {
420
436
  ...state,
421
437
  };
422
438
  this.state[this.instance] = newState;
423
- (_a = this.stateStorage) === null || _a === void 0 ? void 0 : _a.saveState(this, newState);
439
+ this.stateStorage?.saveState(this, newState);
424
440
  }
425
441
  }
426
442
  async validateState(preauthorized = false) {
427
- var _a;
428
443
  if (!this.features)
429
444
  return;
430
445
  if (!this.features.unlocked && preauthorized) {
@@ -432,7 +447,7 @@ class Device extends utils_1.TypedEmitter {
432
447
  return;
433
448
  }
434
449
  }
435
- const expectedState = (_a = this.getState()) === null || _a === void 0 ? void 0 : _a.staticSessionId;
450
+ const expectedState = this.getState()?.staticSessionId;
436
451
  const state = await this.getCommands().getDeviceState();
437
452
  const uniqueState = `${state}@${this.features.device_id}:${this.instance}`;
438
453
  if (this.features.session_id) {
@@ -458,7 +473,7 @@ class Device extends utils_1.TypedEmitter {
458
473
  }
459
474
  const { message } = await this.getCommands().typedCall('Initialize', 'Features', payload);
460
475
  this._updateFeatures(message);
461
- this.setState({ deriveCardano: payload === null || payload === void 0 ? void 0 : payload.derive_cardano });
476
+ this.setState({ deriveCardano: payload?.derive_cardano });
462
477
  }
463
478
  initStorage(storage) {
464
479
  this.stateStorage = storage;
@@ -469,15 +484,14 @@ class Device extends utils_1.TypedEmitter {
469
484
  this._updateFeatures(message);
470
485
  }
471
486
  async checkFirmwareHashWithRetries() {
472
- var _a;
473
487
  const lastResult = this.authenticityChecks.firmwareHash;
474
488
  const notDoneYet = lastResult === null;
475
- const attemptsDone = (_a = lastResult === null || lastResult === void 0 ? void 0 : lastResult.attemptCount) !== null && _a !== void 0 ? _a : 0;
489
+ const attemptsDone = lastResult?.attemptCount ?? 0;
476
490
  if (attemptsDone >= constants_1.FIRMWARE.HASH_CHECK_MAX_ATTEMPTS)
477
491
  return;
478
492
  const wasError = lastResult !== null && !lastResult.success;
479
493
  const wasErrorRetriable = wasError && (0, utils_1.isArrayMember)(lastResult.error, constants_1.FIRMWARE.HASH_CHECK_RETRIABLE_ERRORS);
480
- const lastErrorPayload = wasError ? lastResult === null || lastResult === void 0 ? void 0 : lastResult.errorPayload : null;
494
+ const lastErrorPayload = wasError ? lastResult?.errorPayload : null;
481
495
  if (notDoneYet || wasErrorRetriable) {
482
496
  const result = await this.checkFirmwareHash();
483
497
  this.authenticityChecks.firmwareHash = result;
@@ -490,7 +504,6 @@ class Device extends utils_1.TypedEmitter {
490
504
  }
491
505
  }
492
506
  async checkFirmwareHash() {
493
- var _a;
494
507
  const createFailResult = (error, errorPayload) => ({
495
508
  success: false,
496
509
  error,
@@ -523,7 +536,7 @@ class Device extends utils_1.TypedEmitter {
523
536
  const { hash: expectedHash, challenge } = (0, firmware_1.calculateFirmwareHash)(this.features.major_version, strippedBinary, (0, crypto_1.randomBytes)(32));
524
537
  try {
525
538
  const deviceResponse = await this.getCommands().typedCall('GetFirmwareHash', 'FirmwareHash', { challenge });
526
- if (!((_a = deviceResponse === null || deviceResponse === void 0 ? void 0 : deviceResponse.message) === null || _a === void 0 ? void 0 : _a.hash)) {
539
+ if (!deviceResponse?.message?.hash) {
527
540
  return createFailResult('other-error', 'Device response is missing hash');
528
541
  }
529
542
  if (deviceResponse.message.hash !== expectedHash) {
@@ -560,7 +573,7 @@ class Device extends utils_1.TypedEmitter {
560
573
  internalModel: this.features.internal_model,
561
574
  deviceRevision: this.features.revision,
562
575
  firmwareVersion,
563
- expectedRevision: release === null || release === void 0 ? void 0 : release.firmware_revision,
576
+ expectedRevision: release?.firmware_revision,
564
577
  });
565
578
  }
566
579
  async changeLanguage({ language, binary, }) {
@@ -605,13 +618,12 @@ class Device extends utils_1.TypedEmitter {
605
618
  return response.message;
606
619
  }
607
620
  _updateFeatures(feat) {
608
- var _a, _b, _c, _d;
609
621
  const capabilities = (0, deviceFeaturesUtils_1.parseCapabilities)(feat);
610
622
  feat.capabilities = capabilities;
611
623
  if (this.features && this.features.session_id && !feat.session_id) {
612
624
  feat.session_id = this.features.session_id;
613
625
  }
614
- feat.unlocked = (_a = feat.unlocked) !== null && _a !== void 0 ? _a : true;
626
+ feat.unlocked = feat.unlocked ?? true;
615
627
  const revision = (0, deviceFeaturesUtils_1.parseRevision)(feat);
616
628
  feat.revision = revision;
617
629
  if (!feat.model && feat.major_version === 1) {
@@ -637,7 +649,7 @@ class Device extends utils_1.TypedEmitter {
637
649
  this._unavailableCapabilities = (0, deviceFeaturesUtils_1.getUnavailableCapabilities)(feat, (0, coinInfo_1.getAllNetworks)());
638
650
  this._firmwareStatus = (0, firmwareInfo_1.getFirmwareStatus)(feat);
639
651
  this._firmwareRelease = (0, firmwareInfo_1.getRelease)(feat);
640
- this.availableTranslations = (_c = (_b = this.firmwareRelease) === null || _b === void 0 ? void 0 : _b.translations) !== null && _c !== void 0 ? _c : [];
652
+ this.availableTranslations = this.firmwareRelease?.translations ?? [];
641
653
  }
642
654
  this._features = feat;
643
655
  this._featuresNeedsReload = false;
@@ -655,12 +667,12 @@ class Device extends utils_1.TypedEmitter {
655
667
  ? types_1.FirmwareType.BitcoinOnly
656
668
  : types_1.FirmwareType.Regular;
657
669
  }
658
- const deviceInfo = (_d = models_1.models[feat.internal_model]) !== null && _d !== void 0 ? _d : {
670
+ const deviceInfo = models_1.models[feat.internal_model] ?? {
659
671
  name: `Unknown ${feat.internal_model}`,
660
672
  colors: {},
661
673
  };
662
674
  this.name = deviceInfo.name;
663
- if (feat === null || feat === void 0 ? void 0 : feat.unit_color) {
675
+ if (feat?.unit_color) {
664
676
  const deviceUnitColor = feat.unit_color.toString();
665
677
  if (deviceUnitColor in deviceInfo.colors) {
666
678
  this.color = deviceInfo.colors[deviceUnitColor];
@@ -674,9 +686,8 @@ class Device extends utils_1.TypedEmitter {
674
686
  return !!this.unreadableError;
675
687
  }
676
688
  disconnect() {
677
- var _a;
678
689
  _log.debug('Disconnect cleanup');
679
- (_a = this.sessionDfd) === null || _a === void 0 ? void 0 : _a.reject(new Error());
690
+ this.sessionDfd?.reject(new Error());
680
691
  this.lastAcquiredHere = false;
681
692
  this.emitLifecycle(events_1.DEVICE.DISCONNECT);
682
693
  return this.interruptionFromUser(constants_1.ERRORS.TypedError('Device_Disconnected'));
@@ -754,12 +765,11 @@ class Device extends utils_1.TypedEmitter {
754
765
  return null;
755
766
  }
756
767
  async dispose() {
757
- var _a, _b;
758
768
  this.removeAllListeners();
759
769
  if (this.session && this.lastAcquiredHere) {
760
770
  try {
761
- await ((_a = this.cancelableAction) === null || _a === void 0 ? void 0 : _a.call(this));
762
- await ((_b = this.commands) === null || _b === void 0 ? void 0 : _b.cancel());
771
+ await this.cancelableAction?.();
772
+ await this.commands?.cancel();
763
773
  return this.transport.release({
764
774
  session: this.session,
765
775
  path: this.transportPath,
@@ -780,7 +790,6 @@ class Device extends utils_1.TypedEmitter {
780
790
  return 'normal';
781
791
  }
782
792
  toMessageObject() {
783
- var _a;
784
793
  const { name, uniquePath: path } = this;
785
794
  const base = { path, name };
786
795
  if (this.unreadableError) {
@@ -812,7 +821,7 @@ class Device extends utils_1.TypedEmitter {
812
821
  id: this.features.device_id,
813
822
  label,
814
823
  _state: this.getState(),
815
- state: (_a = this.getState()) === null || _a === void 0 ? void 0 : _a.staticSessionId,
824
+ state: this.getState()?.staticSessionId,
816
825
  status,
817
826
  mode: this.getMode(),
818
827
  color: this.color,
@@ -80,7 +80,11 @@ export declare class DeviceCommands {
80
80
  cancelWithFallback(): Promise<{
81
81
  readonly success: false;
82
82
  readonly error: "session not found";
83
- } | import("@trezor/transport/lib/types").Success<import("@trezor/protobuf").MessageFromTrezor> | import("@trezor/transport/lib/types").ErrorGeneric<"session not found" | "Network request failed" | "Wrong result type." | "other call in progress" | "Malformed protocol format" | "device disconnected during action" | "unexpected error" | "Aborted by timeout" | "Aborted by signal" | "This transport can not be used in this environment" | "device not found" | "Unable to open device" | "A transfer error has occurred."> | import("@trezor/transport/lib/types").Success<undefined> | undefined>;
83
+ } | import("@trezor/transport/lib/types").Success<import("@trezor/protobuf").MessageFromTrezor> | {
84
+ success: false;
85
+ error: "session not found" | "Network request failed" | "Wrong result type." | "other call in progress" | "Malformed protocol format" | "device disconnected during action" | "unexpected error" | "Aborted by timeout" | "Aborted by signal" | "This transport can not be used in this environment" | "device not found" | "Unable to open device" | "A transfer error has occurred.";
86
+ message?: string;
87
+ } | import("@trezor/transport/lib/types").Success<undefined> | undefined>;
84
88
  cancel(): Promise<void>;
85
89
  }
86
90
  export type TypedCall = DeviceCommands['typedCall'];
@@ -51,6 +51,11 @@ const filterForLog = (type, msg) => {
51
51
  return msg;
52
52
  };
53
53
  class DeviceCommands {
54
+ device;
55
+ transport;
56
+ transportSession;
57
+ disposed;
58
+ callPromise;
54
59
  constructor(device, transport, transportSession) {
55
60
  this.device = device;
56
61
  this.transport = transport;
@@ -234,7 +239,7 @@ class DeviceCommands {
234
239
  if (this.disposed) {
235
240
  throw constants_1.ERRORS.TypedError('Runtime', 'typedCall: DeviceCommands already disposed');
236
241
  }
237
- (0, schema_utils_1.Assert)(protobuf_1.MessagesSchema.MessageType.properties[type], msg !== null && msg !== void 0 ? msg : {});
242
+ (0, schema_utils_1.Assert)(protobuf_1.MessagesSchema.MessageType.properties[type], msg ?? {});
238
243
  const response = await this._commonCall(type, msg);
239
244
  try {
240
245
  assertType(response, resType);
@@ -372,7 +377,7 @@ class DeviceCommands {
372
377
  const { name, version } = this.transport;
373
378
  if (name === 'BridgeTransport' && !utils_1.versionUtils.isNewer(version, '2.0.28')) {
374
379
  try {
375
- await (0, utils_1.createTimeoutPromise)(1);
380
+ await (0, utils_1.resolveAfter)(1);
376
381
  await this.device.acquire();
377
382
  await (0, prompts_1.cancelPrompt)(this.device, false);
378
383
  }
@@ -45,6 +45,7 @@ export declare class DeviceList extends TypedEmitter<DeviceListEvents> implement
45
45
  }[];
46
46
  private readonly locks;
47
47
  private transportLock;
48
+ private readonly scheduledUpgradeChecks;
48
49
  constructor({ messages, priority, debug, _sessionsBackgroundUrl, manifest, }: ConstructorParams);
49
50
  private tryGetTransport;
50
51
  private getOrCreateTransport;
@@ -56,6 +57,7 @@ export declare class DeviceList extends TypedEmitter<DeviceListEvents> implement
56
57
  init(initParams?: InitParams): Promise<void>;
57
58
  private createInitPromise;
58
59
  private createReconnectDelay;
60
+ private scheduleUpgradeCheck;
59
61
  private selectTransport;
60
62
  private initializeTransport;
61
63
  private waitForDevices;
@@ -9,7 +9,6 @@ const Device_1 = require("./Device");
9
9
  const transportInfo_1 = require("../data/transportInfo");
10
10
  const types_1 = require("../types");
11
11
  const utils_2 = require("../types/utils");
12
- const abortablePromise_1 = require("../utils/abortablePromise");
13
12
  const debug_1 = require("../utils/debug");
14
13
  const createAuthPenaltyManager = (priority) => {
15
14
  const penalizedDevices = {};
@@ -68,6 +67,13 @@ const assertDeviceListConnected = deviceList => {
68
67
  };
69
68
  exports.assertDeviceListConnected = assertDeviceListConnected;
70
69
  class DeviceList extends utils_1.TypedEmitter {
70
+ transport = {};
71
+ transports = [];
72
+ devices = createDeviceCollection();
73
+ deviceCounter = Date.now();
74
+ handshakeLock;
75
+ authPenaltyManager;
76
+ transportCommonArgs;
71
77
  isConnected() {
72
78
  return !!Object.keys(this.transport).length;
73
79
  }
@@ -81,13 +87,13 @@ class DeviceList extends utils_1.TypedEmitter {
81
87
  getActiveTransports() {
82
88
  return Object.values(this.transport).map(getTransportInfo);
83
89
  }
90
+ locks = {};
84
91
  async transportLock(apiType, abortMessage, action) {
85
- var _a, _b;
86
- const lock = (_a = this.locks[apiType]) !== null && _a !== void 0 ? _a : (this.locks[apiType] = { sequence: 0 });
92
+ const lock = this.locks[apiType] ?? (this.locks[apiType] = { sequence: 0 });
87
93
  lock.abortMessage = abortMessage;
88
94
  const sequence = ++lock.sequence;
89
95
  while (lock.promise) {
90
- (_b = lock.abort) === null || _b === void 0 ? void 0 : _b.abort(new Error(abortMessage));
96
+ lock.abort?.abort(new Error(abortMessage));
91
97
  await lock.promise.catch(() => { });
92
98
  }
93
99
  if (sequence !== lock.sequence)
@@ -99,13 +105,9 @@ class DeviceList extends utils_1.TypedEmitter {
99
105
  });
100
106
  return lock.promise;
101
107
  }
108
+ scheduledUpgradeChecks = {};
102
109
  constructor({ messages, priority, debug, _sessionsBackgroundUrl, manifest, }) {
103
110
  super();
104
- this.transport = {};
105
- this.transports = [];
106
- this.devices = createDeviceCollection();
107
- this.deviceCounter = Date.now();
108
- this.locks = {};
109
111
  const transportLogger = (0, debug_1.initLog)('@trezor/transport', debug);
110
112
  this.handshakeLock = (0, utils_1.getSynchronize)();
111
113
  this.authPenaltyManager = createAuthPenaltyManager(priority);
@@ -113,14 +115,13 @@ class DeviceList extends utils_1.TypedEmitter {
113
115
  messages,
114
116
  logger: transportLogger,
115
117
  sessionsBackgroundUrl: _sessionsBackgroundUrl,
116
- id: (manifest === null || manifest === void 0 ? void 0 : manifest.appUrl) || 'unknown app',
118
+ id: manifest?.appUrl || 'unknown app',
117
119
  };
118
120
  }
119
121
  tryGetTransport(name) {
120
122
  return this.transports.find(t => t.name === name);
121
123
  }
122
124
  getOrCreateTransport(transportType) {
123
- var _a;
124
125
  const { transportCommonArgs } = this;
125
126
  if (typeof transportType === 'string') {
126
127
  const existing = this.tryGetTransport(transportType);
@@ -143,7 +144,7 @@ class DeviceList extends utils_1.TypedEmitter {
143
144
  else if (typeof transportType === 'function' && 'prototype' in transportType) {
144
145
  const transportInstance = new transportType(transportCommonArgs);
145
146
  if ((0, transport_1.isTransportInstance)(transportInstance)) {
146
- return (_a = this.tryGetTransport(transportInstance.name)) !== null && _a !== void 0 ? _a : transportInstance;
147
+ return this.tryGetTransport(transportInstance.name) ?? transportInstance;
147
148
  }
148
149
  }
149
150
  else if ((0, transport_1.isTransportInstance)(transportType)) {
@@ -158,7 +159,7 @@ class DeviceList extends utils_1.TypedEmitter {
158
159
  throw constants_1.ERRORS.TypedError('Runtime', `DeviceList.init: transports[] of unexpected type: ${transportType}`);
159
160
  }
160
161
  createTransports(transports) {
161
- const transportTypes = (transports === null || transports === void 0 ? void 0 : transports.length) ? transports : ['BridgeTransport'];
162
+ const transportTypes = transports?.length ? transports : ['BridgeTransport'];
162
163
  return transportTypes.map(this.getOrCreateTransport.bind(this));
163
164
  }
164
165
  onDeviceConnected(descriptor, transport) {
@@ -179,15 +180,15 @@ class DeviceList extends utils_1.TypedEmitter {
179
180
  }
180
181
  onDeviceDisconnected(descriptor, transport) {
181
182
  const device = this.devices.remove(descriptor.path, transport);
182
- device === null || device === void 0 ? void 0 : device.disconnect();
183
+ device?.disconnect();
183
184
  }
184
185
  onDeviceSessionChanged(descriptor, transport) {
185
186
  const device = this.devices.get(descriptor.path, transport);
186
- device === null || device === void 0 ? void 0 : device.updateDescriptor(descriptor);
187
+ device?.updateDescriptor(descriptor);
187
188
  }
188
189
  onDeviceRequestRelease(descriptor, transport) {
189
190
  const device = this.devices.get(descriptor.path, transport);
190
- device === null || device === void 0 ? void 0 : device.usedElsewhere();
191
+ device?.usedElsewhere();
191
192
  }
192
193
  async init(initParams = {}) {
193
194
  this.transports = this.createTransports(initParams.transports);
@@ -237,9 +238,12 @@ class DeviceList extends utils_1.TypedEmitter {
237
238
  this.emit(transport_1.TRANSPORT.START, getTransportInfo(transport));
238
239
  }
239
240
  }
241
+ if (transport && transport !== transports[0]) {
242
+ this.scheduleUpgradeCheck(apiType, initParams);
243
+ }
240
244
  }
241
245
  catch (error) {
242
- this.emit(transport_1.TRANSPORT.ERROR, { apiType, error: error === null || error === void 0 ? void 0 : error.message });
246
+ this.emit(transport_1.TRANSPORT.ERROR, { apiType, error: error?.message });
243
247
  if (initParams.transportReconnect && !abortSignal.aborted) {
244
248
  this.transportLock(apiType, 'Reconnecting', async (signal) => {
245
249
  await this.createReconnectDelay(signal);
@@ -249,9 +253,25 @@ class DeviceList extends utils_1.TypedEmitter {
249
253
  }
250
254
  }
251
255
  createReconnectDelay(signal) {
252
- const { promise, resolve } = (0, abortablePromise_1.abortablePromise)(signal);
253
- const timeout = setTimeout(resolve, 1000);
254
- return promise.finally(() => clearTimeout(timeout));
256
+ return (0, utils_1.resolveAfter)(1000, signal);
257
+ }
258
+ scheduleUpgradeCheck(apiType, initParams) {
259
+ clearTimeout(this.scheduledUpgradeChecks[apiType]);
260
+ this.scheduledUpgradeChecks[apiType] = setTimeout(async () => {
261
+ const transport = this.transport[apiType];
262
+ const transports = this.transports.filter(t => t.apiType === apiType);
263
+ if (!transport || transport === transports[0])
264
+ return;
265
+ for (const t of transports) {
266
+ if (t === transport)
267
+ break;
268
+ if (await t.ping()) {
269
+ this.transportLock(apiType, 'Upgrading', signal => this.createInitPromise(apiType, initParams, signal)).catch(() => { });
270
+ return;
271
+ }
272
+ }
273
+ this.scheduleUpgradeCheck(apiType, initParams);
274
+ }, 1000);
255
275
  }
256
276
  async selectTransport([transport, ...rest], signal) {
257
277
  if (signal.aborted)
@@ -324,7 +344,7 @@ class DeviceList extends utils_1.TypedEmitter {
324
344
  }
325
345
  getDeviceByStaticState(state) {
326
346
  const deviceId = state.split('@')[1].split(':')[0];
327
- return this.devices.all().find(d => { var _a; return ((_a = d.features) === null || _a === void 0 ? void 0 : _a.device_id) === deviceId; });
347
+ return this.devices.all().find(d => d.features?.device_id === deviceId);
328
348
  }
329
349
  async dispose() {
330
350
  this.removeAllListeners();
@@ -341,6 +361,7 @@ class DeviceList extends utils_1.TypedEmitter {
341
361
  await Promise.all(promises);
342
362
  }
343
363
  async stopTransport(transport) {
364
+ clearTimeout(this.scheduledUpgradeChecks[transport.apiType]);
344
365
  const devices = this.devices.clear(transport);
345
366
  devices.forEach(device => {
346
367
  this.emit(events_1.DEVICE.DISCONNECT, device);
@@ -349,7 +370,7 @@ class DeviceList extends utils_1.TypedEmitter {
349
370
  this.authPenaltyManager.remove(device);
350
371
  await device.dispose();
351
372
  }));
352
- transport === null || transport === void 0 ? void 0 : transport.stop();
373
+ transport?.stop();
353
374
  }
354
375
  async enumerate() {
355
376
  const promises = Object.values(this.transport).map(async (transport) => {
@@ -358,8 +379,7 @@ class DeviceList extends utils_1.TypedEmitter {
358
379
  return;
359
380
  }
360
381
  res.payload.forEach(d => {
361
- var _a;
362
- (_a = this.devices.get(d.path, transport)) === null || _a === void 0 ? void 0 : _a.updateDescriptor(d);
382
+ this.devices.get(d.path, transport)?.updateDescriptor(d);
363
383
  });
364
384
  });
365
385
  await Promise.all(promises);
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebextensionStateStorage = void 0;
4
4
  const connect_common_1 = require("@trezor/connect-common");
5
5
  class WebextensionStateStorage {
6
+ origin;
6
7
  constructor(origin) {
7
8
  this.origin = origin;
8
9
  }
9
10
  loadState(device) {
10
- var _a;
11
- if (!((_a = device.getState()) === null || _a === void 0 ? void 0 : _a.sessionId)) {
11
+ if (!device.getState()?.sessionId) {
12
12
  const { preferredDevice } = connect_common_1.storage.loadForOrigin(this.origin) || {};
13
- if ((preferredDevice === null || preferredDevice === void 0 ? void 0 : preferredDevice.internalState) &&
14
- (preferredDevice === null || preferredDevice === void 0 ? void 0 : preferredDevice.internalStateExpiration) &&
13
+ if (preferredDevice?.internalState &&
14
+ preferredDevice?.internalStateExpiration &&
15
15
  preferredDevice.internalStateExpiration > new Date().getTime()) {
16
16
  return { sessionId: preferredDevice.internalState };
17
17
  }
@@ -19,8 +19,7 @@ class WebextensionStateStorage {
19
19
  return undefined;
20
20
  }
21
21
  saveState(device, state) {
22
- var _a;
23
- const expirationDelay = Math.max(1000 * 60 * 15, (_a = device.features.auto_lock_delay_ms) !== null && _a !== void 0 ? _a : 0);
22
+ const expirationDelay = Math.max(1000 * 60 * 15, device.features.auto_lock_delay_ms ?? 0);
24
23
  connect_common_1.storage.saveForOrigin(store => ({
25
24
  ...store,
26
25
  preferredDevice: store.preferredDevice
@@ -4,7 +4,13 @@ exports.checkFirmwareRevision = void 0;
4
4
  const versionUtils_1 = require("@trezor/utils/lib/versionUtils");
5
5
  const downloadReleasesMetadata_1 = require("../data/downloadReleasesMetadata");
6
6
  const calculateRevisionForDevice_1 = require("./calculateRevisionForDevice");
7
- const NODE_FETCH_OFFLINE_ERROR_NAMES = ['FetchError', 'AbortError'];
7
+ const isNodeJSNetworkError = (e) => ['FetchError', 'AbortError'].includes(e.name);
8
+ const isReactNativeNetworkError = (e) => e.name === 'TypeError' && e.message.includes('Network request failed');
9
+ const isNetworkError = (e) => {
10
+ if (!(e instanceof Error))
11
+ return false;
12
+ return isNodeJSNetworkError(e) || isReactNativeNetworkError(e);
13
+ };
8
14
  const getOnlineReleaseMetadata = async ({ firmwareVersion, internalModel, }) => {
9
15
  const onlineReleases = await (0, downloadReleasesMetadata_1.downloadReleasesMetadata)({ internal_model: internalModel });
10
16
  return onlineReleases.find(onlineRelease => (0, versionUtils_1.isEqual)(onlineRelease.version, firmwareVersion));
@@ -30,7 +36,7 @@ const checkFirmwareRevision = async ({ firmwareVersion, internalModel, deviceRev
30
36
  firmwareVersion,
31
37
  internalModel,
32
38
  });
33
- if ((onlineRelease === null || onlineRelease === void 0 ? void 0 : onlineRelease.firmware_revision) === undefined) {
39
+ if (onlineRelease?.firmware_revision === undefined) {
34
40
  return failFirmwareRevisionCheck('firmware-version-unknown');
35
41
  }
36
42
  if (!doRevisionsMatch({
@@ -43,10 +49,9 @@ const checkFirmwareRevision = async ({ firmwareVersion, internalModel, deviceRev
43
49
  return { success: true };
44
50
  }
45
51
  catch (e) {
46
- if (NODE_FETCH_OFFLINE_ERROR_NAMES.includes(e.name)) {
47
- return failFirmwareRevisionCheck('cannot-perform-check-offline');
48
- }
49
- return failFirmwareRevisionCheck('other-error');
52
+ return isNetworkError(e)
53
+ ? failFirmwareRevisionCheck('cannot-perform-check-offline')
54
+ : failFirmwareRevisionCheck('other-error');
50
55
  }
51
56
  }
52
57
  if (!doRevisionsMatch({
@@ -22,13 +22,10 @@ const cancelPrompt = (device, expectResponse = true) => {
22
22
  };
23
23
  exports.cancelPrompt = cancelPrompt;
24
24
  const prompt = (event, ...[device, ...args]) => new Promise((resolve, reject) => {
25
- const cancelAndReject = (error) => (0, exports.cancelPrompt)(device).then(onCancel => {
26
- var _a;
27
- return reject(error ||
28
- new Error(onCancel.success
29
- ? (_a = onCancel.payload) === null || _a === void 0 ? void 0 : _a.message.message
30
- : onCancel.error));
31
- });
25
+ const cancelAndReject = (error) => (0, exports.cancelPrompt)(device).then(onCancel => reject(error ||
26
+ new Error(onCancel.success
27
+ ? onCancel.payload?.message.message
28
+ : onCancel.error)));
32
29
  if (device.listenerCount(event) > 0) {
33
30
  device.setCancelableAction(cancelAndReject);
34
31
  const callback = (...[response, error]) => {