@trezor/connect 9.5.0 → 9.5.1-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 +20 -8
- package/README.md +1 -1
- package/lib/api/bitcoin/BitcoinFees.d.ts +25 -0
- package/lib/api/bitcoin/{Fees.js → BitcoinFees.js} +8 -29
- package/lib/api/bitcoin/TransactionComposer.d.ts +2 -2
- package/lib/api/bitcoin/TransactionComposer.js +5 -5
- package/lib/api/bitcoin/index.d.ts +1 -1
- package/lib/api/bitcoin/index.js +1 -1
- package/lib/api/blockchainEstimateFee.js +15 -4
- package/lib/api/{bitcoin/Fees.d.ts → common/MiscFees.d.ts} +10 -11
- package/lib/api/common/MiscFees.js +46 -0
- package/lib/api/common/paramsValidator.js +1 -1
- package/lib/api/ethereum/EthereumFees.d.ts +24 -0
- package/lib/api/ethereum/EthereumFees.js +71 -0
- package/lib/api/ethereum/api/ethereumSignTypedData.d.ts +6 -0
- package/lib/api/ethereum/ethereumDefinitions.js +1 -3
- package/lib/api/getCoinInfo.d.ts +18 -0
- package/lib/api/solana/api/solanaComposeTransaction.d.ts +1 -2
- package/lib/api/solana/api/solanaComposeTransaction.js +2 -5
- package/lib/api/unlockPath.d.ts +1 -1
- package/lib/backend/Blockchain.d.ts +1 -0
- package/lib/core/AbstractMethod.js +1 -1
- package/lib/data/coinInfo.d.ts +66 -0
- package/lib/data/connectSettings.js +3 -0
- package/lib/data/defaultFeeLevels.js +1 -1
- package/lib/data/version.d.ts +1 -1
- package/lib/data/version.js +1 -1
- package/lib/device/Device.d.ts +3 -5
- package/lib/device/Device.js +25 -20
- package/lib/device/DeviceList.d.ts +6 -13
- package/lib/device/DeviceList.js +44 -174
- package/lib/device/TransportList.d.ts +9 -0
- package/lib/device/TransportList.js +50 -0
- package/lib/device/TransportManager.d.ts +34 -0
- package/lib/device/TransportManager.js +149 -0
- package/lib/device/checkFirmwareRevision.js +9 -5
- package/lib/types/api/solana/index.d.ts +1 -2
- package/lib/types/api/solana/index.js +1 -2
- package/lib/types/coinInfo.d.ts +36 -0
- package/lib/types/device.d.ts +6 -0
- package/lib/types/fees.d.ts +13 -0
- package/lib/types/fees.js +13 -1
- package/lib/types/settings.d.ts +3 -1
- package/lib/types/utils.d.ts +0 -1
- package/lib/types/utils.js +0 -3
- package/lib/utils/assets-browser.d.ts +4 -0
- package/lib/utils/assets-browser.js +11 -2
- package/package.json +15 -15
package/lib/data/coinInfo.d.ts
CHANGED
|
@@ -23,8 +23,14 @@ export declare const getBitcoinNetwork: (pathOrName: DerivationPath) => ({
|
|
|
23
23
|
};
|
|
24
24
|
decimals: number;
|
|
25
25
|
defaultFees: {
|
|
26
|
+
maxFeePerGas?: string | undefined;
|
|
27
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
28
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
29
|
+
minWaitTimeEstimate?: number | undefined;
|
|
26
30
|
feeLimit?: string | undefined;
|
|
27
31
|
feePerTx?: string | undefined;
|
|
32
|
+
baseFeePerGas?: string | undefined;
|
|
33
|
+
effectiveGasPrice?: string | undefined;
|
|
28
34
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
29
35
|
feePerUnit: string;
|
|
30
36
|
blocks: number;
|
|
@@ -83,8 +89,14 @@ export declare const getEthereumNetwork: (pathOrNetworkSymbol: DerivationPath) =
|
|
|
83
89
|
};
|
|
84
90
|
decimals: number;
|
|
85
91
|
defaultFees: {
|
|
92
|
+
maxFeePerGas?: string | undefined;
|
|
93
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
94
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
95
|
+
minWaitTimeEstimate?: number | undefined;
|
|
86
96
|
feeLimit?: string | undefined;
|
|
87
97
|
feePerTx?: string | undefined;
|
|
98
|
+
baseFeePerGas?: string | undefined;
|
|
99
|
+
effectiveGasPrice?: string | undefined;
|
|
88
100
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
89
101
|
feePerUnit: string;
|
|
90
102
|
blocks: number;
|
|
@@ -118,8 +130,14 @@ export declare const getMiscNetwork: (pathOrName: DerivationPath) => ({
|
|
|
118
130
|
};
|
|
119
131
|
decimals: number;
|
|
120
132
|
defaultFees: {
|
|
133
|
+
maxFeePerGas?: string | undefined;
|
|
134
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
135
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
136
|
+
minWaitTimeEstimate?: number | undefined;
|
|
121
137
|
feeLimit?: string | undefined;
|
|
122
138
|
feePerTx?: string | undefined;
|
|
139
|
+
baseFeePerGas?: string | undefined;
|
|
140
|
+
effectiveGasPrice?: string | undefined;
|
|
123
141
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
124
142
|
feePerUnit: string;
|
|
125
143
|
blocks: number;
|
|
@@ -177,8 +195,14 @@ export declare const fixCoinInfoNetwork: (ci: BitcoinNetworkInfo, path: number[]
|
|
|
177
195
|
};
|
|
178
196
|
decimals: number;
|
|
179
197
|
defaultFees: {
|
|
198
|
+
maxFeePerGas?: string | undefined;
|
|
199
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
200
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
201
|
+
minWaitTimeEstimate?: number | undefined;
|
|
180
202
|
feeLimit?: string | undefined;
|
|
181
203
|
feePerTx?: string | undefined;
|
|
204
|
+
baseFeePerGas?: string | undefined;
|
|
205
|
+
effectiveGasPrice?: string | undefined;
|
|
182
206
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
183
207
|
feePerUnit: string;
|
|
184
208
|
blocks: number;
|
|
@@ -237,8 +261,14 @@ export declare const getCoinInfoByHash: (hash: string, networkInfo: any) => {
|
|
|
237
261
|
};
|
|
238
262
|
decimals: number;
|
|
239
263
|
defaultFees: {
|
|
264
|
+
maxFeePerGas?: string | undefined;
|
|
265
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
266
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
267
|
+
minWaitTimeEstimate?: number | undefined;
|
|
240
268
|
feeLimit?: string | undefined;
|
|
241
269
|
feePerTx?: string | undefined;
|
|
270
|
+
baseFeePerGas?: string | undefined;
|
|
271
|
+
effectiveGasPrice?: string | undefined;
|
|
242
272
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
243
273
|
feePerUnit: string;
|
|
244
274
|
blocks: number;
|
|
@@ -297,8 +327,14 @@ export declare const getCoinInfo: (currency: string) => ({
|
|
|
297
327
|
};
|
|
298
328
|
decimals: number;
|
|
299
329
|
defaultFees: {
|
|
330
|
+
maxFeePerGas?: string | undefined;
|
|
331
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
332
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
333
|
+
minWaitTimeEstimate?: number | undefined;
|
|
300
334
|
feeLimit?: string | undefined;
|
|
301
335
|
feePerTx?: string | undefined;
|
|
336
|
+
baseFeePerGas?: string | undefined;
|
|
337
|
+
effectiveGasPrice?: string | undefined;
|
|
302
338
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
303
339
|
feePerUnit: string;
|
|
304
340
|
blocks: number;
|
|
@@ -356,8 +392,14 @@ export declare const getCoinInfo: (currency: string) => ({
|
|
|
356
392
|
};
|
|
357
393
|
decimals: number;
|
|
358
394
|
defaultFees: {
|
|
395
|
+
maxFeePerGas?: string | undefined;
|
|
396
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
397
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
398
|
+
minWaitTimeEstimate?: number | undefined;
|
|
359
399
|
feeLimit?: string | undefined;
|
|
360
400
|
feePerTx?: string | undefined;
|
|
401
|
+
baseFeePerGas?: string | undefined;
|
|
402
|
+
effectiveGasPrice?: string | undefined;
|
|
361
403
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
362
404
|
feePerUnit: string;
|
|
363
405
|
blocks: number;
|
|
@@ -390,8 +432,14 @@ export declare const getCoinInfo: (currency: string) => ({
|
|
|
390
432
|
};
|
|
391
433
|
decimals: number;
|
|
392
434
|
defaultFees: {
|
|
435
|
+
maxFeePerGas?: string | undefined;
|
|
436
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
437
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
438
|
+
minWaitTimeEstimate?: number | undefined;
|
|
393
439
|
feeLimit?: string | undefined;
|
|
394
440
|
feePerTx?: string | undefined;
|
|
441
|
+
baseFeePerGas?: string | undefined;
|
|
442
|
+
effectiveGasPrice?: string | undefined;
|
|
395
443
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
396
444
|
feePerUnit: string;
|
|
397
445
|
blocks: number;
|
|
@@ -434,8 +482,14 @@ export declare const getAllNetworks: () => (({
|
|
|
434
482
|
};
|
|
435
483
|
decimals: number;
|
|
436
484
|
defaultFees: {
|
|
485
|
+
maxFeePerGas?: string | undefined;
|
|
486
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
487
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
488
|
+
minWaitTimeEstimate?: number | undefined;
|
|
437
489
|
feeLimit?: string | undefined;
|
|
438
490
|
feePerTx?: string | undefined;
|
|
491
|
+
baseFeePerGas?: string | undefined;
|
|
492
|
+
effectiveGasPrice?: string | undefined;
|
|
439
493
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
440
494
|
feePerUnit: string;
|
|
441
495
|
blocks: number;
|
|
@@ -493,8 +547,14 @@ export declare const getAllNetworks: () => (({
|
|
|
493
547
|
};
|
|
494
548
|
decimals: number;
|
|
495
549
|
defaultFees: {
|
|
550
|
+
maxFeePerGas?: string | undefined;
|
|
551
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
552
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
553
|
+
minWaitTimeEstimate?: number | undefined;
|
|
496
554
|
feeLimit?: string | undefined;
|
|
497
555
|
feePerTx?: string | undefined;
|
|
556
|
+
baseFeePerGas?: string | undefined;
|
|
557
|
+
effectiveGasPrice?: string | undefined;
|
|
498
558
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
499
559
|
feePerUnit: string;
|
|
500
560
|
blocks: number;
|
|
@@ -527,8 +587,14 @@ export declare const getAllNetworks: () => (({
|
|
|
527
587
|
};
|
|
528
588
|
decimals: number;
|
|
529
589
|
defaultFees: {
|
|
590
|
+
maxFeePerGas?: string | undefined;
|
|
591
|
+
maxPriorityFeePerGas?: string | undefined;
|
|
592
|
+
maxWaitTimeEstimate?: number | undefined;
|
|
593
|
+
minWaitTimeEstimate?: number | undefined;
|
|
530
594
|
feeLimit?: string | undefined;
|
|
531
595
|
feePerTx?: string | undefined;
|
|
596
|
+
baseFeePerGas?: string | undefined;
|
|
597
|
+
effectiveGasPrice?: string | undefined;
|
|
532
598
|
label: "normal" | "custom" | "high" | "economy" | "low";
|
|
533
599
|
feePerUnit: string;
|
|
534
600
|
blocks: number;
|
|
@@ -124,6 +124,9 @@ const parseConnectSettings = (input = {}) => {
|
|
|
124
124
|
if (typeof input.enableFirmwareHashCheck === 'boolean') {
|
|
125
125
|
settings.enableFirmwareHashCheck = Boolean(input.enableFirmwareHashCheck);
|
|
126
126
|
}
|
|
127
|
+
if (typeof input.npmVersion === 'string') {
|
|
128
|
+
settings.npmVersion = input.npmVersion;
|
|
129
|
+
}
|
|
127
130
|
return settings;
|
|
128
131
|
};
|
|
129
132
|
exports.parseConnectSettings = parseConnectSettings;
|
|
@@ -29,7 +29,7 @@ const getEvmChainGweiGasPrice = (chain) => EVM_GAS_PRICE_PER_CHAIN_IN_GWEI[chain
|
|
|
29
29
|
const getBitcoinFeeLevels = (coin) => {
|
|
30
30
|
const defaultFees = coin.default_fee_b;
|
|
31
31
|
const shortcut = coin.shortcut.toLowerCase();
|
|
32
|
-
const keys =
|
|
32
|
+
const keys = (0, utils_1.typedObjectKeys)(defaultFees);
|
|
33
33
|
const levels = keys
|
|
34
34
|
.sort((levelA, levelB) => defaultFees[levelB] - defaultFees[levelA])
|
|
35
35
|
.map(level => {
|
package/lib/data/version.d.ts
CHANGED
package/lib/data/version.js
CHANGED
|
@@ -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.5.
|
|
4
|
+
exports.VERSION = '9.5.1-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
|
package/lib/device/Device.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ type RunOptions = {
|
|
|
15
15
|
skipFirmwareChecks?: boolean;
|
|
16
16
|
skipLanguageChecks?: boolean;
|
|
17
17
|
};
|
|
18
|
+
export declare const CANCEL_TIMEOUT = 1000;
|
|
18
19
|
export declare const GET_FEATURES_TIMEOUT = 3000;
|
|
19
20
|
export declare const GET_FEATURES_TIMEOUT_REACT_NATIVE = 20000;
|
|
20
21
|
export interface DeviceEvents {
|
|
@@ -39,6 +40,7 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
39
40
|
readonly transportPath: import("@trezor/transport/lib/types").PathPublic;
|
|
40
41
|
private readonly transportSessionOwner;
|
|
41
42
|
private readonly transportDescriptorType;
|
|
43
|
+
private readonly bluetoothProps;
|
|
42
44
|
private session;
|
|
43
45
|
private lastAcquiredHere;
|
|
44
46
|
private unreadableError?;
|
|
@@ -189,11 +191,7 @@ export declare class Device extends TypedEmitter<DeviceEvents> {
|
|
|
189
191
|
getUniquePath(): DeviceUniquePath;
|
|
190
192
|
isT1(): boolean;
|
|
191
193
|
hasUnexpectedMode(allow: string[], require: string[]): "ui-device_bootloader_mode" | "ui-device_not_in_bootloader_mode" | "ui-device_not_initialized" | "ui-device_seedless" | null;
|
|
192
|
-
dispose():
|
|
193
|
-
success: false;
|
|
194
|
-
error: "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";
|
|
195
|
-
message?: string;
|
|
196
|
-
} | undefined>;
|
|
194
|
+
dispose(): import("@trezor/transport/lib/types").AsyncResultWithTypedError<null, "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;
|
|
197
195
|
private getMode;
|
|
198
196
|
toMessageObject(): DeviceTyped;
|
|
199
197
|
}
|
package/lib/device/Device.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Device = exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = exports.GET_FEATURES_TIMEOUT = void 0;
|
|
3
|
+
exports.Device = exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = exports.GET_FEATURES_TIMEOUT = exports.CANCEL_TIMEOUT = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const protocol_1 = require("@trezor/protocol");
|
|
6
6
|
const transport_1 = require("@trezor/transport");
|
|
@@ -20,6 +20,7 @@ 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.CANCEL_TIMEOUT = 1_000;
|
|
23
24
|
exports.GET_FEATURES_TIMEOUT = 3_000;
|
|
24
25
|
exports.GET_FEATURES_TIMEOUT_REACT_NATIVE = 20_000;
|
|
25
26
|
const parseRunOptions = (options) => {
|
|
@@ -33,6 +34,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
33
34
|
transportPath;
|
|
34
35
|
transportSessionOwner;
|
|
35
36
|
transportDescriptorType;
|
|
37
|
+
bluetoothProps;
|
|
36
38
|
session;
|
|
37
39
|
lastAcquiredHere;
|
|
38
40
|
unreadableError;
|
|
@@ -89,6 +91,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
89
91
|
this.transportPath = descriptor.path;
|
|
90
92
|
this.transportSessionOwner = descriptor.sessionOwner;
|
|
91
93
|
this.transportDescriptorType = descriptor.type;
|
|
94
|
+
this.bluetoothProps = descriptor.id ? { id: descriptor.id } : undefined;
|
|
92
95
|
this.session = descriptor.session;
|
|
93
96
|
this.lastAcquiredHere = false;
|
|
94
97
|
this.firstRunPromise = (0, utils_1.createDeferred)();
|
|
@@ -326,16 +329,22 @@ class Device extends utils_1.TypedEmitter {
|
|
|
326
329
|
await this.initialize(!!options.useCardanoDerivation);
|
|
327
330
|
}
|
|
328
331
|
else {
|
|
329
|
-
const
|
|
332
|
+
const isNative = DataManager_1.DataManager.getSettings('env') === 'react-native';
|
|
333
|
+
const getFeaturesTimeout = isNative
|
|
330
334
|
? exports.GET_FEATURES_TIMEOUT_REACT_NATIVE
|
|
331
335
|
: exports.GET_FEATURES_TIMEOUT;
|
|
332
|
-
|
|
336
|
+
const cancelTimeout = isNative
|
|
337
|
+
? exports.GET_FEATURES_TIMEOUT_REACT_NATIVE
|
|
338
|
+
: exports.CANCEL_TIMEOUT;
|
|
339
|
+
if (['v1', 'bridge'].includes(this.protocol.name) &&
|
|
340
|
+
![0, 2].includes(this.transportDescriptorType)) {
|
|
333
341
|
_log.debug('sending a preventive cancel on the first encounter with the device');
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
342
|
+
await Promise.race([
|
|
343
|
+
this.getCommands()
|
|
344
|
+
.typedCall('Cancel', 'Failure', {})
|
|
345
|
+
.catch(() => { }),
|
|
346
|
+
new Promise((_, reject) => setTimeout(reject, cancelTimeout)),
|
|
347
|
+
]).catch(() => this.acquire());
|
|
339
348
|
}
|
|
340
349
|
let getFeaturesTimeoutId;
|
|
341
350
|
await Promise.race([
|
|
@@ -764,20 +773,14 @@ class Device extends utils_1.TypedEmitter {
|
|
|
764
773
|
}
|
|
765
774
|
return null;
|
|
766
775
|
}
|
|
767
|
-
|
|
776
|
+
dispose() {
|
|
768
777
|
this.removeAllListeners();
|
|
769
778
|
if (this.session && this.lastAcquiredHere) {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
path: this.transportPath,
|
|
776
|
-
onClose: true,
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
catch {
|
|
780
|
-
}
|
|
779
|
+
return this.transport.release({
|
|
780
|
+
session: this.session,
|
|
781
|
+
path: this.transportPath,
|
|
782
|
+
onClose: true,
|
|
783
|
+
});
|
|
781
784
|
}
|
|
782
785
|
}
|
|
783
786
|
getMode() {
|
|
@@ -808,6 +811,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
808
811
|
label: 'Unacquired device',
|
|
809
812
|
name: this.name,
|
|
810
813
|
transportSessionOwner: this.transportSessionOwner,
|
|
814
|
+
bluetoothProps: this.bluetoothProps,
|
|
811
815
|
};
|
|
812
816
|
}
|
|
813
817
|
const defaultLabel = 'My Trezor';
|
|
@@ -832,6 +836,7 @@ class Device extends utils_1.TypedEmitter {
|
|
|
832
836
|
unavailableCapabilities: this.unavailableCapabilities,
|
|
833
837
|
availableTranslations: this.availableTranslations,
|
|
834
838
|
authenticityChecks: this.authenticityChecks,
|
|
839
|
+
bluetoothProps: this.bluetoothProps,
|
|
835
840
|
};
|
|
836
841
|
}
|
|
837
842
|
}
|
|
@@ -28,13 +28,14 @@ type ConstructorParams = Pick<ConnectSettings, 'priority' | 'debug' | '_sessions
|
|
|
28
28
|
};
|
|
29
29
|
type InitParams = Pick<ConnectSettings, 'transports' | 'pendingTransportEvent' | 'transportReconnect'>;
|
|
30
30
|
export declare class DeviceList extends TypedEmitter<DeviceListEvents> implements IDeviceList {
|
|
31
|
-
private readonly
|
|
31
|
+
private readonly transportManagers;
|
|
32
32
|
private transports;
|
|
33
33
|
private readonly devices;
|
|
34
34
|
private deviceCounter;
|
|
35
35
|
private readonly handshakeLock;
|
|
36
36
|
private readonly authPenaltyManager;
|
|
37
|
-
private
|
|
37
|
+
private updateTransports;
|
|
38
|
+
private getConnectedTransports;
|
|
38
39
|
isConnected(): this is DeviceList;
|
|
39
40
|
pendingConnection(): Promise<void> | undefined;
|
|
40
41
|
getActiveTransports(): {
|
|
@@ -43,22 +44,14 @@ export declare class DeviceList extends TypedEmitter<DeviceListEvents> implement
|
|
|
43
44
|
version: string;
|
|
44
45
|
outdated: boolean;
|
|
45
46
|
}[];
|
|
46
|
-
private readonly locks;
|
|
47
|
-
private transportLock;
|
|
48
|
-
private readonly scheduledUpgradeChecks;
|
|
49
47
|
constructor({ messages, priority, debug, _sessionsBackgroundUrl, manifest, }: ConstructorParams);
|
|
50
|
-
private tryGetTransport;
|
|
51
|
-
private getOrCreateTransport;
|
|
52
|
-
private createTransports;
|
|
53
48
|
private onDeviceConnected;
|
|
54
49
|
private onDeviceDisconnected;
|
|
55
50
|
private onDeviceSessionChanged;
|
|
56
51
|
private onDeviceRequestRelease;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
private
|
|
60
|
-
private scheduleUpgradeCheck;
|
|
61
|
-
private selectTransport;
|
|
52
|
+
private getOrCreateTransportManager;
|
|
53
|
+
init({ transports, transportReconnect, pendingTransportEvent }?: InitParams): Promise<void>;
|
|
54
|
+
private startTransport;
|
|
62
55
|
private initializeTransport;
|
|
63
56
|
private waitForDevices;
|
|
64
57
|
getDeviceCount(): number;
|
package/lib/device/DeviceList.js
CHANGED
|
@@ -6,9 +6,9 @@ const utils_1 = require("@trezor/utils");
|
|
|
6
6
|
const constants_1 = require("../constants");
|
|
7
7
|
const events_1 = require("../events");
|
|
8
8
|
const Device_1 = require("./Device");
|
|
9
|
-
const transportInfo_1 = require("../data/transportInfo");
|
|
10
9
|
const types_1 = require("../types");
|
|
11
|
-
const
|
|
10
|
+
const TransportList_1 = require("./TransportList");
|
|
11
|
+
const TransportManager_1 = require("./TransportManager");
|
|
12
12
|
const debug_1 = require("../utils/debug");
|
|
13
13
|
const createAuthPenaltyManager = (priority) => {
|
|
14
14
|
const penalizedDevices = {};
|
|
@@ -67,100 +67,42 @@ const assertDeviceListConnected = deviceList => {
|
|
|
67
67
|
};
|
|
68
68
|
exports.assertDeviceListConnected = assertDeviceListConnected;
|
|
69
69
|
class DeviceList extends utils_1.TypedEmitter {
|
|
70
|
-
|
|
70
|
+
transportManagers = {};
|
|
71
71
|
transports = [];
|
|
72
72
|
devices = createDeviceCollection();
|
|
73
73
|
deviceCounter = Date.now();
|
|
74
74
|
handshakeLock;
|
|
75
75
|
authPenaltyManager;
|
|
76
|
-
|
|
76
|
+
updateTransports;
|
|
77
|
+
getConnectedTransports() {
|
|
78
|
+
return Object.values(this.transportManagers)
|
|
79
|
+
.map(manager => manager.get())
|
|
80
|
+
.filter(utils_1.isNotUndefined);
|
|
81
|
+
}
|
|
77
82
|
isConnected() {
|
|
78
|
-
return !!
|
|
83
|
+
return !!this.getConnectedTransports().length;
|
|
79
84
|
}
|
|
80
85
|
pendingConnection() {
|
|
81
|
-
const pending = Object.values(this.
|
|
82
|
-
.map(
|
|
86
|
+
const pending = Object.values(this.transportManagers)
|
|
87
|
+
.map(manager => manager.pending())
|
|
83
88
|
.filter(utils_1.isNotUndefined);
|
|
84
89
|
if (pending.length)
|
|
85
90
|
return Promise.all(pending).then(() => { });
|
|
86
91
|
}
|
|
87
92
|
getActiveTransports() {
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
locks = {};
|
|
91
|
-
async transportLock(apiType, abortMessage, action) {
|
|
92
|
-
const lock = this.locks[apiType] ?? (this.locks[apiType] = { sequence: 0 });
|
|
93
|
-
lock.abortMessage = abortMessage;
|
|
94
|
-
const sequence = ++lock.sequence;
|
|
95
|
-
while (lock.promise) {
|
|
96
|
-
lock.abort?.abort(new Error(abortMessage));
|
|
97
|
-
await lock.promise.catch(() => { });
|
|
98
|
-
}
|
|
99
|
-
if (sequence !== lock.sequence)
|
|
100
|
-
return Promise.reject(new Error(lock.abortMessage));
|
|
101
|
-
lock.abort = new AbortController();
|
|
102
|
-
lock.promise = action(lock.abort.signal).finally(() => {
|
|
103
|
-
delete lock.abort;
|
|
104
|
-
delete lock.promise;
|
|
105
|
-
});
|
|
106
|
-
return lock.promise;
|
|
93
|
+
return this.getConnectedTransports().map(getTransportInfo);
|
|
107
94
|
}
|
|
108
|
-
scheduledUpgradeChecks = {};
|
|
109
95
|
constructor({ messages, priority, debug, _sessionsBackgroundUrl, manifest, }) {
|
|
110
96
|
super();
|
|
111
97
|
const transportLogger = (0, debug_1.initLog)('@trezor/transport', debug);
|
|
112
98
|
this.handshakeLock = (0, utils_1.getSynchronize)();
|
|
113
99
|
this.authPenaltyManager = createAuthPenaltyManager(priority);
|
|
114
|
-
this.
|
|
100
|
+
this.updateTransports = (0, TransportList_1.createTransportList)({
|
|
115
101
|
messages,
|
|
116
102
|
logger: transportLogger,
|
|
117
103
|
sessionsBackgroundUrl: _sessionsBackgroundUrl,
|
|
118
104
|
id: manifest?.appUrl || 'unknown app',
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
tryGetTransport(name) {
|
|
122
|
-
return this.transports.find(t => t.name === name);
|
|
123
|
-
}
|
|
124
|
-
getOrCreateTransport(transportType) {
|
|
125
|
-
const { transportCommonArgs } = this;
|
|
126
|
-
if (typeof transportType === 'string') {
|
|
127
|
-
const existing = this.tryGetTransport(transportType);
|
|
128
|
-
if (existing)
|
|
129
|
-
return existing;
|
|
130
|
-
switch (transportType) {
|
|
131
|
-
case 'WebUsbTransport':
|
|
132
|
-
return new transport_1.WebUsbTransport(transportCommonArgs);
|
|
133
|
-
case 'NodeUsbTransport':
|
|
134
|
-
return new transport_1.NodeUsbTransport(transportCommonArgs);
|
|
135
|
-
case 'BridgeTransport':
|
|
136
|
-
return new transport_1.BridgeTransport({
|
|
137
|
-
latestVersion: (0, transportInfo_1.getBridgeInfo)().version.join('.'),
|
|
138
|
-
...transportCommonArgs,
|
|
139
|
-
});
|
|
140
|
-
case 'UdpTransport':
|
|
141
|
-
return new transport_1.UdpTransport(transportCommonArgs);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
else if (typeof transportType === 'function' && 'prototype' in transportType) {
|
|
145
|
-
const transportInstance = new transportType(transportCommonArgs);
|
|
146
|
-
if ((0, transport_1.isTransportInstance)(transportInstance)) {
|
|
147
|
-
return this.tryGetTransport(transportInstance.name) ?? transportInstance;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
else if ((0, transport_1.isTransportInstance)(transportType)) {
|
|
151
|
-
if (this.tryGetTransport(transportType.name)) {
|
|
152
|
-
return transportType;
|
|
153
|
-
}
|
|
154
|
-
if (!transportType.getMessage()) {
|
|
155
|
-
transportType.updateMessages(transportCommonArgs.messages);
|
|
156
|
-
}
|
|
157
|
-
return transportType;
|
|
158
|
-
}
|
|
159
|
-
throw constants_1.ERRORS.TypedError('Runtime', `DeviceList.init: transports[] of unexpected type: ${transportType}`);
|
|
160
|
-
}
|
|
161
|
-
createTransports(transports) {
|
|
162
|
-
const transportTypes = transports?.length ? transports : ['BridgeTransport'];
|
|
163
|
-
return transportTypes.map(this.getOrCreateTransport.bind(this));
|
|
105
|
+
});
|
|
164
106
|
}
|
|
165
107
|
onDeviceConnected(descriptor, transport) {
|
|
166
108
|
const id = (this.deviceCounter++).toString(16).slice(-8);
|
|
@@ -190,103 +132,41 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
190
132
|
const device = this.devices.get(descriptor.path, transport);
|
|
191
133
|
device?.usedElsewhere();
|
|
192
134
|
}
|
|
193
|
-
|
|
194
|
-
|
|
135
|
+
getOrCreateTransportManager(apiType) {
|
|
136
|
+
if (!this.transportManagers[apiType]) {
|
|
137
|
+
const manager = new TransportManager_1.TransportManager({
|
|
138
|
+
startTransport: this.startTransport.bind(this),
|
|
139
|
+
stopTransport: this.stopTransport.bind(this),
|
|
140
|
+
});
|
|
141
|
+
manager.on(transport_1.TRANSPORT.START, transport => this.emit(transport_1.TRANSPORT.START, getTransportInfo(transport)));
|
|
142
|
+
manager.on(transport_1.TRANSPORT.ERROR, error => this.emit(transport_1.TRANSPORT.ERROR, { apiType, error }));
|
|
143
|
+
this.transportManagers[apiType] = manager;
|
|
144
|
+
}
|
|
145
|
+
return this.transportManagers[apiType];
|
|
146
|
+
}
|
|
147
|
+
async init({ transports, transportReconnect, pendingTransportEvent } = {}) {
|
|
148
|
+
this.transports = this.updateTransports(this.transports, transports);
|
|
195
149
|
const promises = this.transports
|
|
196
150
|
.map(t => t.apiType)
|
|
197
|
-
.concat((0,
|
|
198
|
-
.concat((0, utils_2.typedObjectKeys)(this.locks))
|
|
151
|
+
.concat((0, utils_1.typedObjectKeys)(this.transportManagers))
|
|
199
152
|
.filter(utils_1.arrayDistinct)
|
|
200
|
-
.map(apiType => this.
|
|
153
|
+
.map(apiType => this.getOrCreateTransportManager(apiType).init({
|
|
154
|
+
transports: this.transports.filter(t => t.apiType === apiType),
|
|
155
|
+
transportReconnect,
|
|
156
|
+
pendingTransportEvent,
|
|
157
|
+
}));
|
|
201
158
|
await Promise.all(promises);
|
|
202
159
|
}
|
|
203
|
-
async
|
|
160
|
+
async startTransport(transport, pendingTransportEvent, signal) {
|
|
204
161
|
try {
|
|
205
|
-
|
|
206
|
-
const transport = transports.length
|
|
207
|
-
? await this.selectTransport(transports, abortSignal)
|
|
208
|
-
: undefined;
|
|
209
|
-
const oldTransport = this.transport[apiType];
|
|
210
|
-
if (oldTransport !== transport) {
|
|
211
|
-
if (oldTransport) {
|
|
212
|
-
delete this.transport[apiType];
|
|
213
|
-
await this.stopTransport(oldTransport);
|
|
214
|
-
if (!transport) {
|
|
215
|
-
this.emit(transport_1.TRANSPORT.ERROR, { apiType, error: 'Transport disabled' });
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (transport) {
|
|
219
|
-
try {
|
|
220
|
-
await this.initializeTransport(transport, initParams, abortSignal);
|
|
221
|
-
}
|
|
222
|
-
catch (error) {
|
|
223
|
-
await this.stopTransport(transport);
|
|
224
|
-
throw error;
|
|
225
|
-
}
|
|
226
|
-
transport.on(transport_1.TRANSPORT.ERROR, error => {
|
|
227
|
-
this.emit(transport_1.TRANSPORT.ERROR, { apiType, error });
|
|
228
|
-
this.transportLock(apiType, 'Transport error', async (signal) => {
|
|
229
|
-
delete this.transport[apiType];
|
|
230
|
-
await this.stopTransport(transport);
|
|
231
|
-
if (initParams.transportReconnect) {
|
|
232
|
-
await this.createReconnectDelay(signal);
|
|
233
|
-
await this.createInitPromise(apiType, initParams, signal);
|
|
234
|
-
}
|
|
235
|
-
}).catch(() => { });
|
|
236
|
-
});
|
|
237
|
-
this.transport[apiType] = transport;
|
|
238
|
-
this.emit(transport_1.TRANSPORT.START, getTransportInfo(transport));
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
if (transport && transport !== transports[0]) {
|
|
242
|
-
this.scheduleUpgradeCheck(apiType, initParams);
|
|
243
|
-
}
|
|
162
|
+
await this.initializeTransport(transport, pendingTransportEvent, signal);
|
|
244
163
|
}
|
|
245
|
-
catch (
|
|
246
|
-
this.
|
|
247
|
-
|
|
248
|
-
this.transportLock(apiType, 'Reconnecting', async (signal) => {
|
|
249
|
-
await this.createReconnectDelay(signal);
|
|
250
|
-
await this.createInitPromise(apiType, initParams, signal);
|
|
251
|
-
}).catch(() => { });
|
|
252
|
-
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
await this.stopTransport(transport);
|
|
166
|
+
throw err;
|
|
253
167
|
}
|
|
254
168
|
}
|
|
255
|
-
|
|
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);
|
|
275
|
-
}
|
|
276
|
-
async selectTransport([transport, ...rest], signal) {
|
|
277
|
-
if (signal.aborted)
|
|
278
|
-
throw new Error(signal.reason);
|
|
279
|
-
if (transport === this.transport[transport.apiType])
|
|
280
|
-
return transport;
|
|
281
|
-
const result = await transport.init({ signal });
|
|
282
|
-
if (result.success)
|
|
283
|
-
return transport;
|
|
284
|
-
else if (rest.length)
|
|
285
|
-
return this.selectTransport(rest, signal);
|
|
286
|
-
else
|
|
287
|
-
throw new Error(result.error);
|
|
288
|
-
}
|
|
289
|
-
async initializeTransport(transport, initParams, signal) {
|
|
169
|
+
async initializeTransport(transport, pendingTransportEvent, signal) {
|
|
290
170
|
transport.on(transport_1.TRANSPORT.DEVICE_CONNECTED, d => this.onDeviceConnected(d, transport));
|
|
291
171
|
transport.on(transport_1.TRANSPORT.DEVICE_DISCONNECTED, d => this.onDeviceDisconnected(d, transport));
|
|
292
172
|
transport.on(transport_1.TRANSPORT.DEVICE_SESSION_CHANGED, d => this.onDeviceSessionChanged(d, transport));
|
|
@@ -296,7 +176,7 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
296
176
|
throw new Error(enumerateResult.error);
|
|
297
177
|
}
|
|
298
178
|
const descriptors = enumerateResult.payload;
|
|
299
|
-
const waitForDevicesPromise =
|
|
179
|
+
const waitForDevicesPromise = pendingTransportEvent && descriptors.length
|
|
300
180
|
? this.waitForDevices(transport, descriptors, signal)
|
|
301
181
|
: Promise.resolve();
|
|
302
182
|
transport.handleDescriptorsChange(descriptors);
|
|
@@ -348,20 +228,10 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
348
228
|
}
|
|
349
229
|
async dispose() {
|
|
350
230
|
this.removeAllListeners();
|
|
351
|
-
const promises = (
|
|
352
|
-
.concat((0, utils_2.typedObjectKeys)(this.locks))
|
|
353
|
-
.filter(utils_1.arrayDistinct)
|
|
354
|
-
.map(apiType => this.transportLock(apiType, 'Disposing', async () => {
|
|
355
|
-
const transport = this.transport[apiType];
|
|
356
|
-
if (transport) {
|
|
357
|
-
delete this.transport[apiType];
|
|
358
|
-
await this.stopTransport(transport);
|
|
359
|
-
}
|
|
360
|
-
}));
|
|
231
|
+
const promises = Object.values(this.transportManagers).map(manager => manager.dispose());
|
|
361
232
|
await Promise.all(promises);
|
|
362
233
|
}
|
|
363
234
|
async stopTransport(transport) {
|
|
364
|
-
clearTimeout(this.scheduledUpgradeChecks[transport.apiType]);
|
|
365
235
|
const devices = this.devices.clear(transport);
|
|
366
236
|
devices.forEach(device => {
|
|
367
237
|
this.emit(events_1.DEVICE.DISCONNECT, device);
|
|
@@ -373,7 +243,7 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
373
243
|
transport?.stop();
|
|
374
244
|
}
|
|
375
245
|
async enumerate() {
|
|
376
|
-
const promises =
|
|
246
|
+
const promises = this.getConnectedTransports().map(async (transport) => {
|
|
377
247
|
const res = await transport.enumerate();
|
|
378
248
|
if (!res.success) {
|
|
379
249
|
return;
|