@trezor/connect 9.4.5 → 9.4.6-beta.1

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/CHANGELOG.md CHANGED
@@ -1,15 +1,32 @@
1
- | Package | Stable | Canary |
2
- | :------------------------------: | :----: | :----: |
3
- | npm @trezor/connect | 9.4.5 | - |
4
- | npm @trezor/connect-web | 9.4.5 | - |
5
- | npm @trezor/connect-webextension | 9.4.5 | - |
1
+ | Package | Stable | Canary |
2
+ | :------------------------------: | :----: | :----------: |
3
+ | npm @trezor/connect | 9.4.5 | 9.4.6-beta.1 |
4
+ | npm @trezor/connect-web | 9.4.5 | 9.4.6-beta.1 |
5
+ | npm @trezor/connect-webextension | 9.4.5 | 9.4.6-beta.1 |
6
6
 
7
- | Deployment | Stable | Canary |
8
- | :----------------: | :----: | :----: |
9
- | connect.trezor.io/ | 9.4.5 | - |
7
+ | Deployment | Stable | Canary |
8
+ | :----------------: | :----: | :----------: |
9
+ | connect.trezor.io/ | 9.4.5 | 9.4.6-beta.1 |
10
10
 
11
11
  Use the persistent link [connect.trezor.io/9](https://connect.trezor.io/9/) to access the latest stable version of Connect Explorer.
12
12
 
13
+ # 9.4.6-beta.1
14
+
15
+ This release brings improvements and optimizations in Solana `getAccountInfo`. It moves security checks outside `getFeatures` that fixes some of the issues with device loading and communication in general.
16
+
17
+ ## Feature
18
+
19
+ - add apiType to transports (f057f33)
20
+ - add blocks to blockchainUnsubscribe (de01c1f)
21
+
22
+ ## Fixes
23
+
24
+ - move security checks outside getFeatures (e67810d)
25
+ - use new improved cloneObject function (ee85d6d)
26
+ - update device authenticity config (3689022)
27
+ - add missing transport names (ef9f731)
28
+ - solana optimized getAccountInfo (88b9c6d)
29
+
13
30
  # 9.4.5
14
31
 
15
32
  We’ve reverted the default setting for nVersion in Connect back to nVersion=1. Since this might be a breaking change we are going to implement it in Connect 10. (05af037)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @trezor/connect
2
2
 
3
- API version 9.4.5
3
+ API version 9.4.6-beta.1
4
4
 
5
5
  [![Build Status](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml/badge.svg)](https://github.com/trezor/trezor-suite/actions/workflows/test-connect.yml)
6
6
  [![NPM](https://img.shields.io/npm/v/@trezor/connect.svg)](https://www.npmjs.org/package/@trezor/connect)
@@ -4,6 +4,7 @@ type Params = {
4
4
  accounts: Payload<'blockchainUnsubscribe'>['accounts'];
5
5
  coinInfo: CoinInfo;
6
6
  identity?: string;
7
+ blocks: boolean;
7
8
  };
8
9
  export default class BlockchainUnsubscribe extends AbstractMethod<'blockchainUnsubscribe', Params> {
9
10
  init(): void;
@@ -7,11 +7,13 @@ const BlockchainLink_1 = require("../backend/BlockchainLink");
7
7
  const coinInfo_1 = require("../data/coinInfo");
8
8
  class BlockchainUnsubscribe extends AbstractMethod_1.AbstractMethod {
9
9
  init() {
10
+ var _a;
10
11
  this.useDevice = false;
11
12
  this.useUi = false;
12
13
  const { payload } = this;
13
14
  (0, paramsValidator_1.validateParams)(payload, [
14
15
  { name: 'accounts', type: 'array', allowEmpty: true },
16
+ { name: 'blocks', type: 'boolean' },
15
17
  { name: 'coin', type: 'string', required: true },
16
18
  { name: 'identity', type: 'string' },
17
19
  ]);
@@ -29,12 +31,19 @@ class BlockchainUnsubscribe extends AbstractMethod_1.AbstractMethod {
29
31
  accounts: payload.accounts,
30
32
  coinInfo,
31
33
  identity: payload.identity,
34
+ blocks: (_a = payload.blocks) !== null && _a !== void 0 ? _a : false,
32
35
  };
33
36
  }
34
37
  async run() {
35
38
  const backend = await (0, BlockchainLink_1.initBlockchain)(this.params.coinInfo, this.postMessage, this.params.identity);
36
39
  const { accounts } = this.params;
37
- return accounts ? backend.unsubscribeAccounts(accounts) : backend.unsubscribeAll();
40
+ if (this.params.blocks) {
41
+ return backend.unsubscribeBlocks();
42
+ }
43
+ if (accounts) {
44
+ return backend.unsubscribeAccounts(accounts);
45
+ }
46
+ return backend.unsubscribeAll();
38
47
  }
39
48
  }
40
49
  exports.default = BlockchainUnsubscribe;
@@ -28,50 +28,6 @@ export declare const validate: (tx: EosSDKTransaction) => {
28
28
  refund?: {
29
29
  owner: string;
30
30
  } | undefined;
31
- new_account?: {
32
- name: string;
33
- owner: {
34
- keys: {
35
- type?: number | undefined;
36
- address_n?: number[] | undefined;
37
- weight: number;
38
- key: string;
39
- }[];
40
- threshold: number;
41
- accounts: {
42
- weight: number;
43
- account: {
44
- permission: string;
45
- actor: string;
46
- };
47
- }[];
48
- waits: {
49
- weight: number;
50
- wait_sec: number;
51
- }[];
52
- };
53
- creator: string;
54
- active: {
55
- keys: {
56
- type?: number | undefined;
57
- address_n?: number[] | undefined;
58
- weight: number;
59
- key: string;
60
- }[];
61
- threshold: number;
62
- accounts: {
63
- weight: number;
64
- account: {
65
- permission: string;
66
- actor: string;
67
- };
68
- }[];
69
- waits: {
70
- weight: number;
71
- wait_sec: number;
72
- }[];
73
- };
74
- } | undefined;
75
31
  delegate?: {
76
32
  transfer: boolean;
77
33
  sender: string;
@@ -159,6 +115,50 @@ export declare const validate: (tx: EosSDKTransaction) => {
159
115
  account: string;
160
116
  code: string;
161
117
  } | undefined;
118
+ new_account?: {
119
+ name: string;
120
+ owner: {
121
+ keys: {
122
+ type?: number | undefined;
123
+ address_n?: number[] | undefined;
124
+ weight: number;
125
+ key: string;
126
+ }[];
127
+ threshold: number;
128
+ accounts: {
129
+ weight: number;
130
+ account: {
131
+ permission: string;
132
+ actor: string;
133
+ };
134
+ }[];
135
+ waits: {
136
+ weight: number;
137
+ wait_sec: number;
138
+ }[];
139
+ };
140
+ creator: string;
141
+ active: {
142
+ keys: {
143
+ type?: number | undefined;
144
+ address_n?: number[] | undefined;
145
+ weight: number;
146
+ key: string;
147
+ }[];
148
+ threshold: number;
149
+ accounts: {
150
+ weight: number;
151
+ account: {
152
+ permission: string;
153
+ actor: string;
154
+ };
155
+ }[];
156
+ waits: {
157
+ weight: number;
158
+ wait_sec: number;
159
+ }[];
160
+ };
161
+ } | undefined;
162
162
  common: {
163
163
  name: string;
164
164
  account: string;
@@ -208,6 +208,7 @@ class GetAccountInfo extends AbstractMethod_1.AbstractMethod {
208
208
  contractFilter: request.contractFilter,
209
209
  gap: request.gap,
210
210
  marker: request.marker,
211
+ tokenAccountsPubKeys: request.tokenAccountsPubKeys,
211
212
  });
212
213
  if (this.disposed)
213
214
  break;
@@ -18,20 +18,31 @@ export declare const createTx: (address_n: number[], branch: string, operation:
18
18
  source: Uint8Array;
19
19
  amount: string | number;
20
20
  fee: string | number;
21
+ gas_limit: number;
21
22
  destination: {
22
23
  hash: Uint8Array;
23
24
  tag: number;
24
25
  };
25
26
  counter: number;
26
- gas_limit: number;
27
27
  storage_limit: number;
28
28
  } | undefined;
29
+ proposal?: {
30
+ source: string;
31
+ period: number;
32
+ proposals: string[];
33
+ } | undefined;
34
+ ballot?: {
35
+ source: string;
36
+ period: number;
37
+ proposal: string;
38
+ ballot: PROTO.TezosBallotType;
39
+ } | undefined;
29
40
  reveal?: {
30
41
  source: Uint8Array;
31
42
  public_key: Uint8Array;
32
43
  fee: string | number;
33
- counter: number;
34
44
  gas_limit: number;
45
+ counter: number;
35
46
  storage_limit: number;
36
47
  } | undefined;
37
48
  origination?: {
@@ -42,29 +53,18 @@ export declare const createTx: (address_n: number[], branch: string, operation:
42
53
  source: Uint8Array;
43
54
  fee: string | number;
44
55
  script: string | number[];
45
- counter: number;
46
56
  gas_limit: number;
57
+ counter: number;
47
58
  storage_limit: number;
48
59
  balance: number;
49
60
  } | undefined;
50
61
  delegation?: {
51
62
  source: Uint8Array;
52
63
  fee: string | number;
53
- counter: number;
64
+ delegate: Uint8Array;
54
65
  gas_limit: number;
66
+ counter: number;
55
67
  storage_limit: number;
56
- delegate: Uint8Array;
57
- } | undefined;
58
- proposal?: {
59
- source: string;
60
- period: number;
61
- proposals: string[];
62
- } | undefined;
63
- ballot?: {
64
- source: string;
65
- period: number;
66
- proposal: string;
67
- ballot: PROTO.TezosBallotType;
68
68
  } | undefined;
69
69
  address_n: number[];
70
70
  branch: Uint8Array;
@@ -1,2 +1,5 @@
1
1
  export declare const FW_HASH_SUPPORTED_VERSIONS: string[];
2
+ export declare const HASH_CHECK_MAX_ATTEMPTS = 3;
3
+ export declare const HASH_CHECK_RETRIABLE_ERRORS: "other-error"[];
4
+ export declare const REVISION_CHECK_RETRIABLE_ERRORS: ("cannot-perform-check-offline" | "other-error")[];
2
5
  //# sourceMappingURL=firmware.d.ts.map
@@ -1,5 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FW_HASH_SUPPORTED_VERSIONS = void 0;
3
+ exports.REVISION_CHECK_RETRIABLE_ERRORS = exports.HASH_CHECK_RETRIABLE_ERRORS = exports.HASH_CHECK_MAX_ATTEMPTS = exports.FW_HASH_SUPPORTED_VERSIONS = void 0;
4
4
  exports.FW_HASH_SUPPORTED_VERSIONS = ['1.11.1', '2.5.1'];
5
+ exports.HASH_CHECK_MAX_ATTEMPTS = 3;
6
+ exports.HASH_CHECK_RETRIABLE_ERRORS = ['other-error'];
7
+ exports.REVISION_CHECK_RETRIABLE_ERRORS = [
8
+ 'cannot-perform-check-offline',
9
+ 'other-error',
10
+ ];
5
11
  //# sourceMappingURL=firmware.js.map
@@ -168,8 +168,10 @@ class AbstractMethod {
168
168
  const version = device.getVersion();
169
169
  if (!version)
170
170
  return;
171
- if (device.firmwareStatus === 'required' ||
172
- !utils_1.versionUtils.isNewerOrEqual(version, range.min)) {
171
+ if (this.name !== 'backupDevice' &&
172
+ this.name !== 'recoveryDevice' &&
173
+ (device.firmwareStatus === 'required' ||
174
+ !utils_1.versionUtils.isNewerOrEqual(version, range.min))) {
173
175
  return events_1.UI.FIRMWARE_OLD;
174
176
  }
175
177
  if (range.max !== '0' && utils_1.versionUtils.isNewer(version, range.max)) {
package/lib/core/index.js CHANGED
@@ -323,7 +323,7 @@ const onCall = async (context, message) => {
323
323
  return await onCallDevice(context, message, method);
324
324
  };
325
325
  const onCallDevice = async (context, message, method) => {
326
- var _a, _b;
326
+ var _a, _b, _c;
327
327
  const { deviceList, callMethods, getOverridePromise, setOverridePromise, sendCoreMessage } = context;
328
328
  const responseID = message.id;
329
329
  const { origin, env, useCoreInPopup } = DataManager_1.DataManager.getSettings();
@@ -437,7 +437,10 @@ const onCallDevice = async (context, message, method) => {
437
437
  }
438
438
  const response = messageResponse;
439
439
  if (response) {
440
- await device.cleanup();
440
+ const shouldReleaseSession = response.success ||
441
+ (!response.success &&
442
+ ((_c = response === null || response === void 0 ? void 0 : response.payload) === null || _c === void 0 ? void 0 : _c.error) !== 'device disconnected during action');
443
+ await device.cleanup(shouldReleaseSession);
441
444
  if (useCoreInPopup) {
442
445
  sendCoreMessage(response);
443
446
  }
@@ -72,6 +72,9 @@ exports.deviceAuthenticityConfig = {
72
72
  '04860857f8ceb107cf03cc6ef56523b5e440e2ed51933cc49ac8a498063f06ab891bdafd0a1655aa287b9ded8a898d9532ec9d6550db3bb524e7af3e474b013d87',
73
73
  '047962b89421e26daa51e0c368d6bbd7d49dcf972b0a6f148c115aedbba533e1574740dfa51c11992c276872ac2f11b3e0f54499c3347e83410142818ac4579b8e',
74
74
  '04bc9f1e23ceed59b3e7b6b760a41f1f37ccc252adb1186e4035ec3f46266656400c7cd4c7153c9dec581b655c9ba1f74878c84128e60a66eed46e251e2eaf065f',
75
+ '0424759a6f4f2bd7ba1c32830c4260248fab48549c7b53b373fcf7d2a881f8198cae63f3d80028596f5f78073251b022c3ff0a7273e2b63e8d2cda0556b416f3d3',
76
+ '04ca8ae9f668b58e0ca4f14a5681d60e8dba7404192c034256304bc26fc6f059ef50fbc9667b7df704ef5010c788534e2416451b282f49ce0f75c64b5e23faac8a',
77
+ '04f02f0ec41b2a19ce25b954f2a915035f45ce592f7d1f2252a41aa9dd7bcbb6a0be9442a3946ee9aa900c1201c595140999d445d912755bd75da070a1a2b7fac7',
75
78
  ],
76
79
  debug: {
77
80
  rootPubKeys: [],
@@ -107,6 +110,9 @@ exports.deviceAuthenticityConfig = {
107
110
  '042678d71fcf002a5c6781ecbb48ec99a67c797a2a7a0a2aac2a2aa66681ea4c6df180bf2110ce259cb128aa8a8e966ae1138964a0175de597674ae59b74feac87',
108
111
  '0452be582403337ee206509e88713ddc1e1aa7e8265de522988f6af7562c136ee62ea75ce320c713d7d6ed1ceefded828c3284ccdc7c89f1867336aff24566ef3f',
109
112
  '04b3117b4173d5792d75988fc5788cdc79a17a4a2168de1d5fd029c56da6da48fd6c4f557531a4a7af924816fc7a7b8cec451d2920c91be52930333e57a1ff2f03',
113
+ '040f69618522bcdc4f4dbc8705d45fae21cc6305dfa4c8244382b057f359fb6042b4888474176dbd921fef937ba9aa1f3800012f9d325be81d8db454b249107106',
114
+ '049d8c7af7ea30b6baabf692f69980c0a3d388fdfde905e46ce535b39915b8c6f2c07a643c7a046029d27f58643423cd5a798caa6df3ee11d5d5e9dfdc7a61ed16',
115
+ '04eddb271cbe838a96cab86fdd19dc2bdfb466ab7c62f1ef834554bc7c9e6c1136dc093b732d55d28346ba306f80cf6c1ba980402d762dba15457a9b3025223bd7',
110
116
  ],
111
117
  debug: {
112
118
  rootPubKeys: [
@@ -5,7 +5,7 @@ const assets_1 = require("../utils/assets");
5
5
  const firmwareUtils_1 = require("../utils/firmwareUtils");
6
6
  const downloadReleasesMetadata = async ({ internal_model, }) => {
7
7
  const url = `https://data.trezor.io/firmware/${internal_model.toLowerCase()}/releases.json`;
8
- const response = (await (0, assets_1.httpRequest)(url, 'json', { signal: AbortSignal.timeout(10000) }, true));
8
+ const response = await (0, assets_1.httpRequest)(url, 'json', { signal: AbortSignal.timeout(10000) }, true);
9
9
  if ((0, firmwareUtils_1.isValidReleases)(response)) {
10
10
  return response;
11
11
  }
@@ -7,6 +7,6 @@ export interface GetInfoProps {
7
7
  releases: FirmwareRelease[];
8
8
  }
9
9
  export declare const getInfo: ({ features, releases }: GetInfoProps) => ReleaseInfo | null;
10
- export declare const getFirmwareStatus: (features: Features) => "none" | "valid" | "outdated" | "required" | "unknown" | "custom";
10
+ export declare const getFirmwareStatus: (features: Features) => "valid" | "outdated" | "required" | "unknown" | "custom" | "none";
11
11
  export declare const getRelease: (features: Features) => ReleaseInfo | null;
12
12
  //# sourceMappingURL=firmwareInfo.d.ts.map
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "9.4.5";
1
+ export declare const VERSION = "9.4.6-beta.1";
2
2
  export declare const DEFAULT_DOMAIN: string;
3
3
  export declare const CONTENT_SCRIPT_VERSION = 1;
4
4
  export declare const DEEPLINK_VERSION = 1;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEEPLINK_VERSION = exports.CONTENT_SCRIPT_VERSION = exports.DEFAULT_DOMAIN = exports.VERSION = void 0;
4
- exports.VERSION = '9.4.5';
4
+ exports.VERSION = '9.4.6-beta.1';
5
5
  const versionN = exports.VERSION.split('.').map(s => parseInt(s, 10));
6
6
  const isBeta = exports.VERSION.includes('beta');
7
7
  exports.DEFAULT_DOMAIN = isBeta
@@ -5,7 +5,7 @@ import { type Transport, type Descriptor } from '@trezor/transport';
5
5
  import { DeviceCommands } from './DeviceCommands';
6
6
  import { PROTO } from '../constants';
7
7
  import { DEVICE, DeviceButtonRequestPayload, UiResponsePin, UiResponsePassphrase, UiResponseWord } from '../events';
8
- import { Device as DeviceTyped, DeviceFirmwareStatus, DeviceState, ReleaseInfo, UnavailableCapabilities, FirmwareType, VersionArray, FirmwareHashCheckResult, DeviceUniquePath } from '../types';
8
+ import { Device as DeviceTyped, DeviceFirmwareStatus, DeviceState, ReleaseInfo, UnavailableCapabilities, FirmwareType, VersionArray, DeviceUniquePath } from '../types';
9
9
  import { IStateStorage } from './StateStorage';
10
10
  import type { PromptCallback } from './prompts';
11
11
  export type RunOptions = {
@@ -128,10 +128,10 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
128
128
  constructor({ id, transport, descriptor, listener }: DeviceParams);
129
129
  private getSessionChangePromise;
130
130
  private waitAndCompareSession;
131
- acquire(): import("@trezor/transport/lib/types").AsyncResultWithTypedError<Session, "Network request failed" | "Wrong result type." | "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" | "descriptor not found" | "wrong previous session">;
131
+ acquire(): import("@trezor/transport/lib/types").AsyncResultWithTypedError<Session, "Network request failed" | "Wrong result type." | "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" | "descriptor not found" | "wrong previous session" | "LIBUSB_ERROR_ACCESS">;
132
132
  release(): Promise<import("@trezor/transport/lib/types").Success<null> | import("@trezor/transport/lib/types").ErrorGeneric<"session not found" | "Network request failed" | "Wrong result type." | "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" | "wrong previous session"> | undefined>;
133
133
  releaseTransportSession(): void;
134
- cleanup(): Promise<void>;
134
+ cleanup(release?: boolean): Promise<void>;
135
135
  handshake(delay?: number): Promise<void>;
136
136
  updateDescriptor(descriptor: Descriptor): Promise<void>;
137
137
  run(fn?: () => Promise<void>, options?: RunOptions): Promise<void>;
@@ -150,8 +150,10 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
150
150
  initialize(useCardanoDerivation: boolean): Promise<void>;
151
151
  initStorage(storage: IStateStorage): void;
152
152
  getFeatures(): Promise<void>;
153
- checkFirmwareHash(): Promise<FirmwareHashCheckResult | null>;
154
- checkFirmwareRevision(): Promise<void>;
153
+ private checkFirmwareHashWithRetries;
154
+ private checkFirmwareHash;
155
+ private checkFirmwareRevisionWithRetries;
156
+ private checkFirmwareRevision;
155
157
  changeLanguage({ language, binary, }: {
156
158
  language?: undefined;
157
159
  binary: ArrayBuffer;
@@ -153,10 +153,12 @@ class Device extends utils_1.TypedEmitter {
153
153
  releaseTransportSession() {
154
154
  this.keepTransportSession = false;
155
155
  }
156
- async cleanup() {
156
+ async cleanup(release = true) {
157
157
  this.eventNames().forEach(e => this.removeAllListeners(e));
158
158
  delete this.runPromise;
159
- await this.release();
159
+ if (release) {
160
+ await this.release();
161
+ }
160
162
  }
161
163
  async handshake(delay) {
162
164
  var _a;
@@ -172,20 +174,21 @@ class Device extends utils_1.TypedEmitter {
172
174
  await this.run();
173
175
  }
174
176
  catch (error) {
177
+ _log.warn(`device.run error.message: ${error.message}, code: ${error.code}`);
175
178
  if (error.code === 'Device_NotFound' ||
176
179
  error.message === transport_1.TRANSPORT_ERROR.DEVICE_NOT_FOUND ||
177
180
  error.message === transport_1.TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION ||
178
- error.message === transport_1.TRANSPORT_ERROR.UNEXPECTED_ERROR ||
179
181
  error.message === transport_1.TRANSPORT_ERROR.DESCRIPTOR_NOT_FOUND ||
180
182
  error.message === transport_1.TRANSPORT_ERROR.HTTP_ERROR) {
181
183
  }
182
- else if (error.message === transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS ||
183
- error.code === 'Device_UsedElsewhere') {
184
+ else if (error.message === transport_1.TRANSPORT_ERROR.UNEXPECTED_ERROR ||
185
+ error.message === transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS ||
186
+ error.code === 'Device_UsedElsewhere' ||
187
+ error.code === 'Device_InitializeFailed') {
184
188
  this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
185
189
  }
186
190
  else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
187
- ((_a = error.message) === null || _a === void 0 ? void 0 : _a.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE)) >= 0 ||
188
- error.code === 'Device_InitializeFailed') {
191
+ ((_a = error.message) === null || _a === void 0 ? void 0 : _a.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE)) >= 0) {
189
192
  this.unreadableError = error === null || error === void 0 ? void 0 : error.message;
190
193
  this.emitLifecycle(events_1.DEVICE.CONNECT_UNACQUIRED);
191
194
  }
@@ -286,7 +289,7 @@ class Device extends utils_1.TypedEmitter {
286
289
  }
287
290
  }
288
291
  async _runInner(fn, options) {
289
- var _a;
292
+ var _a, _b;
290
293
  if (this.releasePromise) {
291
294
  await this.releasePromise;
292
295
  }
@@ -311,6 +314,7 @@ class Device extends utils_1.TypedEmitter {
311
314
  }
312
315
  }
313
316
  catch (error) {
317
+ _log.warn('Device._runInner error: ', error.message);
314
318
  if (!this.inconsistent &&
315
319
  (error.message === 'GetFeatures timeout' || error.message === 'Unknown message')) {
316
320
  this.inconsistent = true;
@@ -324,6 +328,19 @@ class Device extends utils_1.TypedEmitter {
324
328
  return Promise.reject(constants_1.ERRORS.TypedError('Device_InitializeFailed', `Initialize failed: ${error.message}${error.code ? `, code: ${error.code}` : ''}`));
325
329
  }
326
330
  }
331
+ await this.checkFirmwareHashWithRetries();
332
+ await this.checkFirmwareRevisionWithRetries();
333
+ if (((_b = this.features) === null || _b === void 0 ? void 0 : _b.language) &&
334
+ !this.features.language_version_matches &&
335
+ this.atLeast('2.7.0')) {
336
+ _log.info('language version mismatch. silently updating...');
337
+ try {
338
+ await this.changeLanguage({ language: this.features.language });
339
+ }
340
+ catch (err) {
341
+ _log.error('change language failed silently', err);
342
+ }
343
+ }
327
344
  if (options.keepSession) {
328
345
  this.keepTransportSession = true;
329
346
  }
@@ -427,23 +444,25 @@ class Device extends utils_1.TypedEmitter {
427
444
  async getFeatures() {
428
445
  const { message } = await this.getCommands().typedCall('GetFeatures', 'Features', {});
429
446
  this._updateFeatures(message);
430
- if (this.authenticityChecks.firmwareHash === null) {
431
- this.authenticityChecks.firmwareHash = await this.checkFirmwareHash();
432
- }
433
- if (this.authenticityChecks.firmwareRevision === null ||
434
- (this.authenticityChecks.firmwareRevision.success === false &&
435
- ['cannot-perform-check-offline', 'other-error'].includes(this.authenticityChecks.firmwareRevision.error))) {
436
- await this.checkFirmwareRevision();
437
- }
438
- if (!this.features.language_version_matches &&
439
- this.features.language &&
440
- this.atLeast('2.7.0')) {
441
- _log.info('language version mismatch. silently updating...');
442
- try {
443
- await this.changeLanguage({ language: this.features.language });
444
- }
445
- catch (err) {
446
- _log.error('change language failed silently', err);
447
+ }
448
+ async checkFirmwareHashWithRetries() {
449
+ var _a;
450
+ const lastResult = this.authenticityChecks.firmwareHash;
451
+ const notDoneYet = lastResult === null;
452
+ const attemptsDone = (_a = lastResult === null || lastResult === void 0 ? void 0 : lastResult.attemptCount) !== null && _a !== void 0 ? _a : 0;
453
+ if (attemptsDone >= constants_1.FIRMWARE.HASH_CHECK_MAX_ATTEMPTS)
454
+ return;
455
+ const wasError = lastResult !== null && !lastResult.success;
456
+ const wasErrorRetriable = wasError && (0, utils_1.isArrayMember)(lastResult.error, constants_1.FIRMWARE.HASH_CHECK_RETRIABLE_ERRORS);
457
+ const lastErrorPayload = wasError ? lastResult === null || lastResult === void 0 ? void 0 : lastResult.errorPayload : null;
458
+ if (notDoneYet || wasErrorRetriable) {
459
+ const result = await this.checkFirmwareHash();
460
+ this.authenticityChecks.firmwareHash = result;
461
+ if (result === null)
462
+ return;
463
+ result.attemptCount = attemptsDone + 1;
464
+ if (result.success && lastErrorPayload) {
465
+ result.warningPayload = { lastErrorPayload, successOnAttempt: result.attemptCount };
447
466
  }
448
467
  }
449
468
  }
@@ -493,6 +512,15 @@ class Device extends utils_1.TypedEmitter {
493
512
  return createFailResult('other-error', errorPayload);
494
513
  }
495
514
  }
515
+ async checkFirmwareRevisionWithRetries() {
516
+ const lastResult = this.authenticityChecks.firmwareRevision;
517
+ const notDoneYet = lastResult === null;
518
+ const wasError = lastResult !== null && !lastResult.success;
519
+ const wasErrorRetriable = wasError && (0, utils_1.isArrayMember)(lastResult.error, constants_1.FIRMWARE.REVISION_CHECK_RETRIABLE_ERRORS);
520
+ if (notDoneYet || wasErrorRetriable) {
521
+ await this.checkFirmwareRevision();
522
+ }
523
+ }
496
524
  async checkFirmwareRevision() {
497
525
  const firmwareVersion = this.getVersion();
498
526
  if (!firmwareVersion || !this.features) {
@@ -57,7 +57,7 @@ export declare class DeviceList extends TypedEmitter<DeviceListEvents> implement
57
57
  getOnlyDevice(): Device | undefined;
58
58
  getDeviceByPath(path: DeviceUniquePath): Device | undefined;
59
59
  getDeviceByStaticState(state: StaticSessionId): Device | undefined;
60
- transportType(): "BridgeTransport" | "NodeUsbTransport" | "WebUsbTransport" | "UdpTransport";
60
+ transportType(): "BridgeTransport" | "NodeUsbTransport" | "WebUsbTransport" | "UdpTransport" | "NativeUsbTransport" | "BluetoothTransport";
61
61
  getTransportInfo(): TransportInfo;
62
62
  dispose(): Promise<void>;
63
63
  cleanup(): Promise<void>;
@@ -160,7 +160,10 @@ class DeviceList extends utils_1.TypedEmitter {
160
160
  createReconnectPromise(initParams) {
161
161
  const { promise, reject } = (0, promiseUtils_1.resolveAfter)(1000, initParams);
162
162
  this.rejectPending = reject;
163
- return promise.then(this.createInitPromise.bind(this)).finally(() => {
163
+ return promise
164
+ .then(this.createInitPromise.bind(this))
165
+ .catch(() => { })
166
+ .finally(() => {
164
167
  this.rejectPending = undefined;
165
168
  });
166
169
  }
@@ -4,6 +4,7 @@ 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
8
  const getOnlineReleaseMetadata = async ({ firmwareVersion, internalModel, }) => {
8
9
  const onlineReleases = await (0, downloadReleasesMetadata_1.downloadReleasesMetadata)({ internal_model: internalModel });
9
10
  return onlineReleases.find(onlineRelease => (0, versionUtils_1.isEqual)(onlineRelease.version, firmwareVersion));
@@ -42,7 +43,7 @@ const checkFirmwareRevision = async ({ firmwareVersion, internalModel, deviceRev
42
43
  return { success: true };
43
44
  }
44
45
  catch (e) {
45
- if (e.name === 'FetchError' && e.code === 'ENOTFOUND') {
46
+ if (NODE_FETCH_OFFLINE_ERROR_NAMES.includes(e.name)) {
46
47
  return failFirmwareRevisionCheck('cannot-perform-check-offline');
47
48
  }
48
49
  return failFirmwareRevisionCheck('other-error');
@@ -147,7 +147,7 @@ class CoreInModule {
147
147
  async call(params) {
148
148
  try {
149
149
  const { promiseId, promise } = this._messagePromises.create();
150
- const payload = (0, utils_1.cloneObjectCyclic)(params);
150
+ const payload = (0, utils_1.cloneObject)(params);
151
151
  this.handleCoreMessage({
152
152
  type: events_2.IFRAME.CALL,
153
153
  id: promiseId,
@@ -8,7 +8,7 @@ export declare const ApplySettings: import("@trezor/schema-utils").TObject<{
8
8
  passphrase_always_on_device: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TBoolean>;
9
9
  safety_checks: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils/lib/custom-types/keyof-enum").TKeyOfEnum<typeof PROTO.Enum_SafetyCheckLevel>>;
10
10
  auto_lock_delay_ms: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TNumber>;
11
- display_rotation: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils/lib/custom-types/keyof-enum").TKeyOfEnum<typeof PROTO.Enum_DisplayRotation>>;
11
+ display_rotation: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TUnion<[import("@trezor/schema-utils/lib/custom-types/keyof-enum").TKeyOfEnum<typeof PROTO.Enum_DisplayRotation>, import("@trezor/schema-utils").TEnum<typeof PROTO.Enum_DisplayRotation>]>>;
12
12
  experimental_features: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TBoolean>;
13
13
  hide_passphrase_from_host: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TBoolean>;
14
14
  haptic_feedback: import("@trezor/schema-utils").TOptional<import("@trezor/schema-utils").TBoolean>;
@@ -28,9 +28,12 @@ export type FirmwareRevisionCheckResult = {
28
28
  export type FirmwareHashCheckError = 'hash-mismatch' | 'check-skipped' | 'check-unsupported' | 'unknown-release' | 'other-error';
29
29
  export type FirmwareHashCheckResult = {
30
30
  success: true;
31
+ attemptCount?: number;
32
+ warningPayload?: unknown;
31
33
  } | {
32
34
  success: false;
33
35
  error: FirmwareHashCheckError;
36
+ attemptCount?: number;
34
37
  errorPayload?: unknown;
35
38
  };
36
39
  export type DeviceUniquePath = string & {
@@ -6,13 +6,14 @@ export interface Manifest {
6
6
  email: string;
7
7
  }
8
8
  export type Proxy = BlockchainSettings['proxy'];
9
+ type KnownTransport = Exclude<Transport['name'], 'NativeUsbTransport' | 'BluetoothTransport'>;
9
10
  export interface ConnectSettingsPublic {
10
11
  manifest?: Manifest;
11
12
  connectSrc?: string;
12
13
  debug?: boolean;
13
14
  popup?: boolean;
14
15
  transportReconnect?: boolean;
15
- transports?: (Transport['name'] | Transport | (new (...args: any[]) => Transport))[];
16
+ transports?: (KnownTransport | Transport | (new (...args: any[]) => Transport))[];
16
17
  pendingTransportEvent?: boolean;
17
18
  lazyLoad?: boolean;
18
19
  interactionTimeout?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trezor/connect",
3
- "version": "9.4.5",
3
+ "version": "9.4.6-beta.1",
4
4
  "author": "Trezor <info@trezor.io>",
5
5
  "homepage": "https://github.com/trezor/trezor-suite/tree/develop/packages/connect",
6
6
  "description": "High-level javascript interface for Trezor hardware wallet.",
@@ -72,15 +72,15 @@
72
72
  "@ethereumjs/common": "^4.4.0",
73
73
  "@ethereumjs/tx": "^5.4.0",
74
74
  "@fivebinaries/coin-selection": "2.2.1",
75
- "@trezor/blockchain-link": "2.3.4",
76
- "@trezor/blockchain-link-types": "1.2.3",
77
- "@trezor/connect-analytics": "1.2.3",
75
+ "@trezor/blockchain-link": "2.3.5-beta.1",
76
+ "@trezor/blockchain-link-types": "1.2.4-beta.1",
77
+ "@trezor/connect-analytics": "1.2.4-beta.1",
78
78
  "@trezor/connect-common": "0.2.5",
79
- "@trezor/protobuf": "1.2.5",
79
+ "@trezor/protobuf": "1.2.6-beta.1",
80
80
  "@trezor/protocol": "1.2.2",
81
81
  "@trezor/schema-utils": "1.2.3",
82
- "@trezor/transport": "1.3.5",
83
- "@trezor/utils": "9.2.4",
82
+ "@trezor/transport": "1.3.6-beta.1",
83
+ "@trezor/utils": "9.2.5-beta.1",
84
84
  "@trezor/utxo-lib": "2.2.4",
85
85
  "blakejs": "^1.2.1",
86
86
  "bs58": "^6.0.0",