@ledgerhq/live-common 26.0.0 → 26.1.0-next.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/README.md +1 -1
- package/lib/__tests__/hw/getDeviceInfo.js +152 -0
- package/lib/__tests__/hw/getDeviceInfo.js.map +1 -1
- package/lib/api/Manager.d.ts +2 -1
- package/lib/api/Manager.d.ts.map +1 -1
- package/lib/api/Manager.js +37 -2
- package/lib/api/Manager.js.map +1 -1
- package/lib/ble/hooks/useBleDevicePairing.d.ts +18 -0
- package/lib/ble/hooks/useBleDevicePairing.d.ts.map +1 -0
- package/lib/ble/hooks/useBleDevicePairing.js +57 -0
- package/lib/ble/hooks/useBleDevicePairing.js.map +1 -0
- package/lib/ble/hooks/useBleDevicePairing.test.d.ts +2 -0
- package/lib/ble/hooks/useBleDevicePairing.test.d.ts.map +1 -0
- package/lib/ble/hooks/useBleDevicePairing.test.js +159 -0
- package/lib/ble/hooks/useBleDevicePairing.test.js.map +1 -0
- package/lib/ble/hooks/useBleDevicesScanning.d.ts +25 -0
- package/lib/ble/hooks/useBleDevicesScanning.d.ts.map +1 -0
- package/lib/ble/hooks/useBleDevicesScanning.js +117 -0
- package/lib/ble/hooks/useBleDevicesScanning.js.map +1 -0
- package/lib/ble/hooks/useBleDevicesScanning.test.d.ts +2 -0
- package/lib/ble/hooks/useBleDevicesScanning.test.d.ts.map +1 -0
- package/lib/ble/hooks/useBleDevicesScanning.test.js +281 -0
- package/lib/ble/hooks/useBleDevicesScanning.test.js.map +1 -0
- package/lib/ble/types.d.ts +21 -0
- package/lib/ble/types.d.ts.map +1 -0
- package/lib/ble/types.js +3 -0
- package/lib/ble/types.js.map +1 -0
- package/lib/errors.d.ts +2 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +4 -2
- package/lib/errors.js.map +1 -1
- package/lib/families/cardano/js-estimateMaxSpendable.d.ts.map +1 -1
- package/lib/families/cardano/js-estimateMaxSpendable.js +2 -0
- package/lib/families/cardano/js-estimateMaxSpendable.js.map +1 -1
- package/lib/families/cosmos/specs.js +2 -2
- package/lib/families/cosmos/specs.js.map +1 -1
- package/lib/families/elrond/specs.js +1 -1
- package/lib/families/elrond/specs.js.map +1 -1
- package/lib/families/polkadot/bridge.integration.test.js +3 -3
- package/lib/families/polkadot/bridge.integration.test.js.map +1 -1
- package/lib/families/polkadot/specs.d.ts.map +1 -1
- package/lib/families/polkadot/specs.js +4 -3
- package/lib/families/polkadot/specs.js.map +1 -1
- package/lib/featureFlags/provider.d.ts +5 -1
- package/lib/featureFlags/provider.d.ts.map +1 -1
- package/lib/featureFlags/provider.js +6 -4
- package/lib/featureFlags/provider.js.map +1 -1
- package/lib/featureFlags/useFeature.d.ts.map +1 -1
- package/lib/featureFlags/useFeature.js +3 -1
- package/lib/featureFlags/useFeature.js.map +1 -1
- package/lib/generated/account.d.ts.map +1 -1
- package/lib/generated/account.js.map +1 -1
- package/lib/generated/bridge/js.d.ts.map +1 -1
- package/lib/generated/bridge/js.js.map +1 -1
- package/lib/generated/bridge/mock.d.ts.map +1 -1
- package/lib/generated/bridge/mock.js.map +1 -1
- package/lib/generated/cli-transaction.d.ts.map +1 -1
- package/lib/generated/cli-transaction.js.map +1 -1
- package/lib/generated/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/generated/deviceTransactionConfig.js.map +1 -1
- package/lib/generated/exchange.d.ts.map +1 -1
- package/lib/generated/exchange.js.map +1 -1
- package/lib/generated/hw-getAddress.d.ts.map +1 -1
- package/lib/generated/hw-getAddress.js.map +1 -1
- package/lib/generated/hw-signMessage.d.ts.map +1 -1
- package/lib/generated/hw-signMessage.js.map +1 -1
- package/lib/generated/mock.d.ts.map +1 -1
- package/lib/generated/mock.js.map +1 -1
- package/lib/generated/platformAdapter.d.ts.map +1 -1
- package/lib/generated/platformAdapter.js.map +1 -1
- package/lib/generated/presync.d.ts.map +1 -1
- package/lib/generated/presync.js.map +1 -1
- package/lib/generated/specs.d.ts.map +1 -1
- package/lib/generated/specs.js.map +1 -1
- package/lib/generated/speculos-deviceActions.d.ts.map +1 -1
- package/lib/generated/speculos-deviceActions.js.map +1 -1
- package/lib/generated/transaction.d.ts.map +1 -1
- package/lib/generated/transaction.js.map +1 -1
- package/lib/generated/types.d.ts.map +1 -1
- package/lib/hw/actions/installLanguage.d.ts +21 -0
- package/lib/hw/actions/installLanguage.d.ts.map +1 -0
- package/lib/hw/actions/installLanguage.js +260 -0
- package/lib/hw/actions/installLanguage.js.map +1 -0
- package/lib/hw/attemptToQuitApp.d.ts +10 -0
- package/lib/hw/attemptToQuitApp.d.ts.map +1 -0
- package/lib/hw/attemptToQuitApp.js +22 -0
- package/lib/hw/attemptToQuitApp.js.map +1 -0
- package/lib/hw/connectManager.d.ts +2 -5
- package/lib/hw/connectManager.d.ts.map +1 -1
- package/lib/hw/connectManager.js +2 -14
- package/lib/hw/connectManager.js.map +1 -1
- package/lib/hw/getDeviceInfo.d.ts.map +1 -1
- package/lib/hw/getDeviceInfo.js +6 -3
- package/lib/hw/getDeviceInfo.js.map +1 -1
- package/lib/hw/getVersion.d.ts +3 -3
- package/lib/hw/getVersion.d.ts.map +1 -1
- package/lib/hw/getVersion.js +53 -5
- package/lib/hw/getVersion.js.map +1 -1
- package/lib/hw/installLanguage.d.ts +17 -0
- package/lib/hw/installLanguage.d.ts.map +1 -0
- package/lib/hw/installLanguage.js +173 -0
- package/lib/hw/installLanguage.js.map +1 -0
- package/lib/hw/uninstallLanguage.d.ts +15 -0
- package/lib/hw/uninstallLanguage.d.ts.map +1 -0
- package/lib/hw/uninstallLanguage.js +121 -0
- package/lib/hw/uninstallLanguage.js.map +1 -0
- package/lib/manager/hooks.d.ts +2 -1
- package/lib/manager/hooks.d.ts.map +1 -1
- package/lib/manager/hooks.js +13 -1
- package/lib/manager/hooks.js.map +1 -1
- package/lib/manager/index.d.ts +2 -1
- package/lib/manager/index.d.ts.map +1 -1
- package/lib/manager/index.js +16 -0
- package/lib/manager/index.js.map +1 -1
- package/lib/manager/localization.d.ts +3 -0
- package/lib/manager/localization.d.ts.map +1 -0
- package/lib/manager/localization.js +15 -0
- package/lib/manager/localization.js.map +1 -0
- package/lib/platform/react.d.ts.map +1 -1
- package/lib/platform/react.js +6 -3
- package/lib/platform/react.js.map +1 -1
- package/package.json +18 -18
- package/src/__tests__/hw/getDeviceInfo.ts +137 -0
- package/src/api/Manager.ts +50 -2
- package/src/ble/hooks/useBleDevicePairing.test.ts +91 -0
- package/src/ble/hooks/useBleDevicePairing.ts +51 -0
- package/src/ble/hooks/useBleDevicesScanning.test.ts +252 -0
- package/src/ble/hooks/useBleDevicesScanning.ts +147 -0
- package/src/ble/types.ts +42 -0
- package/src/errors.ts +9 -0
- package/src/families/cardano/js-estimateMaxSpendable.ts +2 -0
- package/src/families/cosmos/specs.ts +2 -2
- package/src/families/elrond/specs.ts +1 -1
- package/src/families/polkadot/bridge.integration.test.ts +3 -3
- package/src/families/polkadot/specs.ts +4 -3
- package/src/featureFlags/provider.tsx +11 -1
- package/src/featureFlags/useFeature.ts +6 -2
- package/src/generated/account.ts +0 -8
- package/src/generated/bridge/js.ts +0 -18
- package/src/generated/bridge/mock.ts +0 -8
- package/src/generated/cli-transaction.ts +0 -17
- package/src/generated/deviceTransactionConfig.ts +15 -31
- package/src/generated/exchange.ts +0 -5
- package/src/generated/hw-getAddress.ts +0 -18
- package/src/generated/hw-signMessage.ts +0 -3
- package/src/generated/mock.ts +0 -3
- package/src/generated/platformAdapter.ts +0 -4
- package/src/generated/presync.ts +0 -1
- package/src/generated/specs.ts +0 -17
- package/src/generated/speculos-deviceActions.ts +0 -17
- package/src/generated/transaction.ts +0 -18
- package/src/generated/types.ts +7 -4
- package/src/hw/actions/installLanguage.ts +343 -0
- package/src/hw/attemptToQuitApp.ts +32 -0
- package/src/hw/connectManager.ts +5 -26
- package/src/hw/getDeviceInfo.ts +6 -0
- package/src/hw/getVersion.ts +77 -3
- package/src/hw/installLanguage.ts +172 -0
- package/src/hw/uninstallLanguage.ts +127 -0
- package/src/manager/hooks.ts +21 -1
- package/src/manager/index.ts +16 -0
- package/src/manager/localization.ts +19 -0
- package/src/platform/react.ts +7 -3
package/src/generated/specs.ts
CHANGED
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
import algorand from "../families/algorand/specs";
|
|
2
|
-
|
|
3
2
|
import bitcoin from "../families/bitcoin/specs";
|
|
4
|
-
|
|
5
3
|
import cardano from "../families/cardano/specs";
|
|
6
|
-
|
|
7
4
|
import celo from "../families/celo/specs";
|
|
8
|
-
|
|
9
5
|
import cosmos from "../families/cosmos/specs";
|
|
10
|
-
|
|
11
6
|
import crypto_org from "../families/crypto_org/specs";
|
|
12
|
-
|
|
13
7
|
import elrond from "../families/elrond/specs";
|
|
14
|
-
|
|
15
8
|
import ethereum from "../families/ethereum/specs";
|
|
16
|
-
|
|
17
9
|
import filecoin from "../families/filecoin/specs";
|
|
18
|
-
|
|
19
10
|
import hedera from "../families/hedera/specs";
|
|
20
|
-
|
|
21
11
|
import osmosis from "../families/osmosis/specs";
|
|
22
|
-
|
|
23
12
|
import polkadot from "../families/polkadot/specs";
|
|
24
|
-
|
|
25
13
|
import ripple from "../families/ripple/specs";
|
|
26
|
-
|
|
27
14
|
import solana from "../families/solana/specs";
|
|
28
|
-
|
|
29
15
|
import stellar from "../families/stellar/specs";
|
|
30
|
-
|
|
31
16
|
import tezos from "../families/tezos/specs";
|
|
32
|
-
|
|
33
17
|
import tron from "../families/tron/specs";
|
|
34
18
|
|
|
35
|
-
|
|
36
19
|
export default {
|
|
37
20
|
algorand,
|
|
38
21
|
bitcoin,
|
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
import algorand from "../families/algorand/speculos-deviceActions";
|
|
2
|
-
|
|
3
2
|
import bitcoin from "../families/bitcoin/speculos-deviceActions";
|
|
4
|
-
|
|
5
3
|
import cardano from "../families/cardano/speculos-deviceActions";
|
|
6
|
-
|
|
7
4
|
import celo from "../families/celo/speculos-deviceActions";
|
|
8
|
-
|
|
9
5
|
import cosmos from "../families/cosmos/speculos-deviceActions";
|
|
10
|
-
|
|
11
6
|
import crypto_org from "../families/crypto_org/speculos-deviceActions";
|
|
12
|
-
|
|
13
7
|
import elrond from "../families/elrond/speculos-deviceActions";
|
|
14
|
-
|
|
15
8
|
import ethereum from "../families/ethereum/speculos-deviceActions";
|
|
16
|
-
|
|
17
9
|
import filecoin from "../families/filecoin/speculos-deviceActions";
|
|
18
|
-
|
|
19
10
|
import hedera from "../families/hedera/speculos-deviceActions";
|
|
20
|
-
|
|
21
11
|
import osmosis from "../families/osmosis/speculos-deviceActions";
|
|
22
|
-
|
|
23
12
|
import polkadot from "../families/polkadot/speculos-deviceActions";
|
|
24
|
-
|
|
25
13
|
import ripple from "../families/ripple/speculos-deviceActions";
|
|
26
|
-
|
|
27
14
|
import solana from "../families/solana/speculos-deviceActions";
|
|
28
|
-
|
|
29
15
|
import stellar from "../families/stellar/speculos-deviceActions";
|
|
30
|
-
|
|
31
16
|
import tezos from "../families/tezos/speculos-deviceActions";
|
|
32
|
-
|
|
33
17
|
import tron from "../families/tron/speculos-deviceActions";
|
|
34
18
|
|
|
35
|
-
|
|
36
19
|
export default {
|
|
37
20
|
algorand,
|
|
38
21
|
bitcoin,
|
|
@@ -1,40 +1,22 @@
|
|
|
1
1
|
import algorand from "../families/algorand/transaction";
|
|
2
|
-
|
|
3
2
|
import bitcoin from "../families/bitcoin/transaction";
|
|
4
|
-
|
|
5
3
|
import cardano from "../families/cardano/transaction";
|
|
6
|
-
|
|
7
4
|
import celo from "../families/celo/transaction";
|
|
8
|
-
|
|
9
5
|
import cosmos from "../families/cosmos/transaction";
|
|
10
|
-
|
|
11
6
|
import crypto_org from "../families/crypto_org/transaction";
|
|
12
|
-
|
|
13
7
|
import elrond from "../families/elrond/transaction";
|
|
14
|
-
|
|
15
8
|
import ethereum from "../families/ethereum/transaction";
|
|
16
|
-
|
|
17
9
|
import filecoin from "../families/filecoin/transaction";
|
|
18
|
-
|
|
19
10
|
import hedera from "../families/hedera/transaction";
|
|
20
|
-
|
|
21
11
|
import neo from "../families/neo/transaction";
|
|
22
|
-
|
|
23
12
|
import osmosis from "../families/osmosis/transaction";
|
|
24
|
-
|
|
25
13
|
import polkadot from "../families/polkadot/transaction";
|
|
26
|
-
|
|
27
14
|
import ripple from "../families/ripple/transaction";
|
|
28
|
-
|
|
29
15
|
import solana from "../families/solana/transaction";
|
|
30
|
-
|
|
31
16
|
import stellar from "../families/stellar/transaction";
|
|
32
|
-
|
|
33
17
|
import tezos from "../families/tezos/transaction";
|
|
34
|
-
|
|
35
18
|
import tron from "../families/tron/transaction";
|
|
36
19
|
|
|
37
|
-
|
|
38
20
|
export default {
|
|
39
21
|
algorand,
|
|
40
22
|
bitcoin,
|
package/src/generated/types.ts
CHANGED
|
@@ -89,7 +89,8 @@ export type Transaction =
|
|
|
89
89
|
| solanaTransaction
|
|
90
90
|
| stellarTransaction
|
|
91
91
|
| tezosTransaction
|
|
92
|
-
| tronTransaction
|
|
92
|
+
| tronTransaction;
|
|
93
|
+
|
|
93
94
|
export type TransactionRaw =
|
|
94
95
|
| algorandTransactionRaw
|
|
95
96
|
| bitcoinTransactionRaw
|
|
@@ -108,7 +109,8 @@ export type TransactionRaw =
|
|
|
108
109
|
| solanaTransactionRaw
|
|
109
110
|
| stellarTransactionRaw
|
|
110
111
|
| tezosTransactionRaw
|
|
111
|
-
| tronTransactionRaw
|
|
112
|
+
| tronTransactionRaw;
|
|
113
|
+
|
|
112
114
|
export type TransactionStatus =
|
|
113
115
|
| algorandTransactionStatus
|
|
114
116
|
| bitcoinTransactionStatus
|
|
@@ -127,7 +129,8 @@ export type TransactionStatus =
|
|
|
127
129
|
| solanaTransactionStatus
|
|
128
130
|
| stellarTransactionStatus
|
|
129
131
|
| tezosTransactionStatus
|
|
130
|
-
| tronTransactionStatus
|
|
132
|
+
| tronTransactionStatus;
|
|
133
|
+
|
|
131
134
|
export type TransactionStatusRaw =
|
|
132
135
|
| algorandTransactionStatusRaw
|
|
133
136
|
| bitcoinTransactionStatusRaw
|
|
@@ -146,4 +149,4 @@ export type TransactionStatusRaw =
|
|
|
146
149
|
| solanaTransactionStatusRaw
|
|
147
150
|
| stellarTransactionStatusRaw
|
|
148
151
|
| tezosTransactionStatusRaw
|
|
149
|
-
| tronTransactionStatusRaw
|
|
152
|
+
| tronTransactionStatusRaw;
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import {
|
|
2
|
+
concat,
|
|
3
|
+
of,
|
|
4
|
+
EMPTY,
|
|
5
|
+
interval,
|
|
6
|
+
Observable,
|
|
7
|
+
TimeoutError,
|
|
8
|
+
throwError,
|
|
9
|
+
} from "rxjs";
|
|
10
|
+
import {
|
|
11
|
+
scan,
|
|
12
|
+
debounce,
|
|
13
|
+
debounceTime,
|
|
14
|
+
catchError,
|
|
15
|
+
switchMap,
|
|
16
|
+
tap,
|
|
17
|
+
distinctUntilChanged,
|
|
18
|
+
timeout,
|
|
19
|
+
} from "rxjs/operators";
|
|
20
|
+
import { useEffect, useState } from "react";
|
|
21
|
+
import { log } from "@ledgerhq/logs";
|
|
22
|
+
import type { DeviceInfo } from "@ledgerhq/types-live";
|
|
23
|
+
import { useReplaySubject } from "../../observable";
|
|
24
|
+
import type {
|
|
25
|
+
InstallLanguageEvent,
|
|
26
|
+
InstallLanguageRequest,
|
|
27
|
+
} from "../installLanguage";
|
|
28
|
+
import type { Action, Device } from "./types";
|
|
29
|
+
import isEqual from "lodash/isEqual";
|
|
30
|
+
import { ConnectManagerTimeout } from "../../errors";
|
|
31
|
+
import { currentMode } from "./app";
|
|
32
|
+
import {
|
|
33
|
+
DisconnectedDevice,
|
|
34
|
+
DisconnectedDeviceDuringOperation,
|
|
35
|
+
} from "@ledgerhq/errors";
|
|
36
|
+
import { getDeviceModel } from "@ledgerhq/devices";
|
|
37
|
+
import { Language } from "@ledgerhq/types-live";
|
|
38
|
+
|
|
39
|
+
type State = {
|
|
40
|
+
isLoading: boolean;
|
|
41
|
+
requestQuitApp: boolean;
|
|
42
|
+
unresponsive: boolean;
|
|
43
|
+
languageInstallationRequested?: boolean;
|
|
44
|
+
installingLanguage?: boolean;
|
|
45
|
+
languageInstalled?: boolean;
|
|
46
|
+
device: Device | null | undefined;
|
|
47
|
+
deviceInfo: DeviceInfo | null | undefined;
|
|
48
|
+
error: Error | null | undefined;
|
|
49
|
+
progress?: number;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type InstallLanguageAction = Action<Language, State, boolean | undefined>;
|
|
53
|
+
|
|
54
|
+
const mapResult = ({ languageInstalled }: State) => languageInstalled;
|
|
55
|
+
|
|
56
|
+
type Event =
|
|
57
|
+
| InstallLanguageEvent
|
|
58
|
+
| {
|
|
59
|
+
type: "error";
|
|
60
|
+
error: Error;
|
|
61
|
+
}
|
|
62
|
+
| {
|
|
63
|
+
type: "deviceChange";
|
|
64
|
+
device: Device | null | undefined;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const getInitialState = (device?: Device | null | undefined): State => ({
|
|
68
|
+
isLoading: !!device,
|
|
69
|
+
requestQuitApp: false,
|
|
70
|
+
unresponsive: false,
|
|
71
|
+
device,
|
|
72
|
+
deviceInfo: null,
|
|
73
|
+
error: null,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const reducer = (state: State, e: Event): State => {
|
|
77
|
+
switch (e.type) {
|
|
78
|
+
case "unresponsiveDevice":
|
|
79
|
+
return { ...state, unresponsive: true, isLoading: false };
|
|
80
|
+
|
|
81
|
+
case "deviceChange":
|
|
82
|
+
return getInitialState(e.device);
|
|
83
|
+
|
|
84
|
+
case "error":
|
|
85
|
+
return {
|
|
86
|
+
...getInitialState(state.device),
|
|
87
|
+
error: e.error,
|
|
88
|
+
isLoading: false,
|
|
89
|
+
};
|
|
90
|
+
case "appDetected":
|
|
91
|
+
return {
|
|
92
|
+
...state,
|
|
93
|
+
unresponsive: false,
|
|
94
|
+
requestQuitApp: true,
|
|
95
|
+
isLoading: false,
|
|
96
|
+
};
|
|
97
|
+
case "devicePermissionRequested":
|
|
98
|
+
return {
|
|
99
|
+
...state,
|
|
100
|
+
unresponsive: false,
|
|
101
|
+
languageInstallationRequested: true,
|
|
102
|
+
isLoading: false,
|
|
103
|
+
};
|
|
104
|
+
case "languageInstalled":
|
|
105
|
+
return {
|
|
106
|
+
...state,
|
|
107
|
+
unresponsive: false,
|
|
108
|
+
languageInstallationRequested: false,
|
|
109
|
+
isLoading: false,
|
|
110
|
+
installingLanguage: false,
|
|
111
|
+
languageInstalled: true,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
case "progress":
|
|
115
|
+
return {
|
|
116
|
+
...state,
|
|
117
|
+
unresponsive: false,
|
|
118
|
+
languageInstallationRequested: false,
|
|
119
|
+
isLoading: false,
|
|
120
|
+
installingLanguage: true,
|
|
121
|
+
progress: e.progress,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const implementations = {
|
|
127
|
+
// in this paradigm, we know that deviceSubject is reflecting the device events
|
|
128
|
+
// so we just trust deviceSubject to reflect the device context (switch between apps, dashboard,...)
|
|
129
|
+
event: ({ deviceSubject, installLanguage, language }) =>
|
|
130
|
+
deviceSubject.pipe(
|
|
131
|
+
debounceTime(1000),
|
|
132
|
+
switchMap((d) => installLanguage(d, language))
|
|
133
|
+
),
|
|
134
|
+
// in this paradigm, we can't observe directly the device, so we have to poll it
|
|
135
|
+
polling: ({ deviceSubject, installLanguage, language }) =>
|
|
136
|
+
new Observable((o) => {
|
|
137
|
+
const POLLING = 2000;
|
|
138
|
+
const INIT_DEBOUNCE = 5000;
|
|
139
|
+
const DISCONNECT_DEBOUNCE = 5000;
|
|
140
|
+
const DEVICE_POLLING_TIMEOUT = 20000;
|
|
141
|
+
// this pattern allows to actually support events based (like if deviceSubject emits new device changes) but inside polling paradigm
|
|
142
|
+
let pollingOnDevice;
|
|
143
|
+
const sub = deviceSubject.subscribe((d) => {
|
|
144
|
+
if (d) {
|
|
145
|
+
pollingOnDevice = d;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
let initT: NodeJS.Timeout | null = setTimeout(() => {
|
|
149
|
+
// initial timeout to unset the device if it's still not connected
|
|
150
|
+
o.next({
|
|
151
|
+
type: "deviceChange",
|
|
152
|
+
device: null,
|
|
153
|
+
});
|
|
154
|
+
device = null;
|
|
155
|
+
log("actions-install-language-event/polling", "device init timeout");
|
|
156
|
+
}, INIT_DEBOUNCE);
|
|
157
|
+
let connectSub;
|
|
158
|
+
let loopT;
|
|
159
|
+
let disconnectT;
|
|
160
|
+
let device = null; // used as internal state for polling
|
|
161
|
+
|
|
162
|
+
let stopDevicePollingError = null;
|
|
163
|
+
|
|
164
|
+
function loop() {
|
|
165
|
+
stopDevicePollingError = null;
|
|
166
|
+
|
|
167
|
+
if (!pollingOnDevice) {
|
|
168
|
+
loopT = setTimeout(loop, POLLING);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
log("actions-install-language-event/polling", "polling loop");
|
|
173
|
+
connectSub = installLanguage(pollingOnDevice, language)
|
|
174
|
+
.pipe(
|
|
175
|
+
timeout(DEVICE_POLLING_TIMEOUT),
|
|
176
|
+
catchError((err) => {
|
|
177
|
+
const productName = getDeviceModel(
|
|
178
|
+
pollingOnDevice.modelId
|
|
179
|
+
).productName;
|
|
180
|
+
return err instanceof TimeoutError
|
|
181
|
+
? of({
|
|
182
|
+
type: "error",
|
|
183
|
+
error: new ConnectManagerTimeout(undefined, {
|
|
184
|
+
productName,
|
|
185
|
+
}) as Error,
|
|
186
|
+
})
|
|
187
|
+
: throwError(err);
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
.subscribe({
|
|
191
|
+
next: (event) => {
|
|
192
|
+
if (initT && device) {
|
|
193
|
+
clearTimeout(initT);
|
|
194
|
+
initT = null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (disconnectT) {
|
|
198
|
+
// any connect app event unschedule the disconnect debounced event
|
|
199
|
+
clearTimeout(disconnectT);
|
|
200
|
+
disconnectT = null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (event.type === "error" && event.error) {
|
|
204
|
+
if (
|
|
205
|
+
event.error instanceof DisconnectedDevice ||
|
|
206
|
+
event.error instanceof DisconnectedDeviceDuringOperation
|
|
207
|
+
) {
|
|
208
|
+
// disconnect on manager actions seems to trigger a type "error" instead of "disconnect"
|
|
209
|
+
// the disconnect event is delayed to debounce the reconnection that happens when switching apps
|
|
210
|
+
disconnectT = setTimeout(() => {
|
|
211
|
+
disconnectT = null;
|
|
212
|
+
// a disconnect will locally be remembered via locally setting device to null...
|
|
213
|
+
device = null;
|
|
214
|
+
o.next(event);
|
|
215
|
+
log(
|
|
216
|
+
"actions-install-language-event/polling",
|
|
217
|
+
"device disconnect timeout"
|
|
218
|
+
);
|
|
219
|
+
}, DISCONNECT_DEBOUNCE);
|
|
220
|
+
} else {
|
|
221
|
+
// These error events should stop polling
|
|
222
|
+
stopDevicePollingError = event.error;
|
|
223
|
+
|
|
224
|
+
// clear all potential polling loops
|
|
225
|
+
if (loopT) {
|
|
226
|
+
clearTimeout(loopT);
|
|
227
|
+
loopT = null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// send in the event for the UI immediately
|
|
231
|
+
o.next(event);
|
|
232
|
+
}
|
|
233
|
+
} else if (event.type === "unresponsiveDevice") {
|
|
234
|
+
return; // ignore unresponsive case which happens for polling
|
|
235
|
+
} else {
|
|
236
|
+
if (device !== pollingOnDevice) {
|
|
237
|
+
// ...but any time an event comes back, it means our device was responding and need to be set back on in polling context
|
|
238
|
+
device = pollingOnDevice;
|
|
239
|
+
o.next({
|
|
240
|
+
type: "deviceChange",
|
|
241
|
+
device,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
o.next(event);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
complete: () => {
|
|
249
|
+
// start a new polling if available
|
|
250
|
+
if (!stopDevicePollingError) loopT = setTimeout(loop, POLLING);
|
|
251
|
+
},
|
|
252
|
+
error: (e) => {
|
|
253
|
+
o.error(e);
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// delay a bit the first loop run in order to be async and wait pollingOnDevice
|
|
259
|
+
loopT = setTimeout(loop, 0);
|
|
260
|
+
return () => {
|
|
261
|
+
if (initT) clearTimeout(initT);
|
|
262
|
+
if (disconnectT) clearTimeout(disconnectT);
|
|
263
|
+
if (connectSub) connectSub.unsubscribe();
|
|
264
|
+
sub.unsubscribe();
|
|
265
|
+
clearTimeout(loopT);
|
|
266
|
+
};
|
|
267
|
+
}).pipe(distinctUntilChanged(isEqual)),
|
|
268
|
+
};
|
|
269
|
+
export const createAction = (
|
|
270
|
+
installLanuageExec: (
|
|
271
|
+
arg0: InstallLanguageRequest
|
|
272
|
+
) => Observable<InstallLanguageEvent>
|
|
273
|
+
): InstallLanguageAction => {
|
|
274
|
+
const installLanguage = (device, language: Language) => {
|
|
275
|
+
return concat(
|
|
276
|
+
of({
|
|
277
|
+
type: "deviceChange",
|
|
278
|
+
device,
|
|
279
|
+
}),
|
|
280
|
+
!device
|
|
281
|
+
? EMPTY
|
|
282
|
+
: installLanuageExec({
|
|
283
|
+
deviceId: device.deviceId,
|
|
284
|
+
language: language,
|
|
285
|
+
}).pipe(
|
|
286
|
+
catchError((error: Error) =>
|
|
287
|
+
of({
|
|
288
|
+
type: "error",
|
|
289
|
+
error,
|
|
290
|
+
})
|
|
291
|
+
)
|
|
292
|
+
)
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const useHook = (
|
|
297
|
+
device: Device | null | undefined,
|
|
298
|
+
language: Language
|
|
299
|
+
): State => {
|
|
300
|
+
const [state, setState] = useState(() => getInitialState(device));
|
|
301
|
+
const deviceSubject = useReplaySubject(device);
|
|
302
|
+
|
|
303
|
+
useEffect(() => {
|
|
304
|
+
if (state.languageInstalled) return;
|
|
305
|
+
|
|
306
|
+
const impl = implementations[currentMode]({
|
|
307
|
+
deviceSubject,
|
|
308
|
+
installLanguage,
|
|
309
|
+
language,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const sub = impl
|
|
313
|
+
.pipe(
|
|
314
|
+
// debounce a bit the connect/disconnect event that we don't need
|
|
315
|
+
tap((e: Event) => log("actions-install-language-event", e.type, e)),
|
|
316
|
+
// we gather all events with a reducer into the UI state
|
|
317
|
+
scan(reducer, getInitialState()),
|
|
318
|
+
// we debounce the UI state to not blink on the UI
|
|
319
|
+
debounce((s: State) => {
|
|
320
|
+
if (s.installingLanguage || s.languageInstallationRequested) {
|
|
321
|
+
return EMPTY;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// default debounce (to be tweak)
|
|
325
|
+
return interval(1500);
|
|
326
|
+
})
|
|
327
|
+
) // the state simply goes into a React state
|
|
328
|
+
.subscribe(setState);
|
|
329
|
+
return () => {
|
|
330
|
+
sub.unsubscribe();
|
|
331
|
+
};
|
|
332
|
+
}, [deviceSubject, language, state.languageInstalled]);
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
...state,
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
useHook,
|
|
341
|
+
mapResult,
|
|
342
|
+
};
|
|
343
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { from, Observable, of, throwError } from "rxjs";
|
|
2
|
+
import { catchError, concatMap } from "rxjs/operators";
|
|
3
|
+
import appSupportsQuitApp from "../appSupportsQuitApp";
|
|
4
|
+
import type { AppAndVersion } from "./connectApp";
|
|
5
|
+
import quitApp from "./quitApp";
|
|
6
|
+
|
|
7
|
+
export type AttemptToQuitAppEvent =
|
|
8
|
+
| {
|
|
9
|
+
type: "unresponsiveDevice";
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
type: "appDetected";
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const attemptToQuitApp = (
|
|
16
|
+
transport,
|
|
17
|
+
appAndVersion?: AppAndVersion
|
|
18
|
+
): Observable<AttemptToQuitAppEvent> =>
|
|
19
|
+
appAndVersion && appSupportsQuitApp(appAndVersion)
|
|
20
|
+
? from(quitApp(transport)).pipe(
|
|
21
|
+
concatMap(() =>
|
|
22
|
+
of(<AttemptToQuitAppEvent>{
|
|
23
|
+
type: "unresponsiveDevice",
|
|
24
|
+
})
|
|
25
|
+
),
|
|
26
|
+
catchError((e) => throwError(e))
|
|
27
|
+
)
|
|
28
|
+
: of({
|
|
29
|
+
type: "appDetected",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export default attemptToQuitApp;
|
package/src/hw/connectManager.ts
CHANGED
|
@@ -9,12 +9,12 @@ import { listApps } from "../apps/hw";
|
|
|
9
9
|
import { withDevice } from "./deviceAccess";
|
|
10
10
|
import getDeviceInfo from "./getDeviceInfo";
|
|
11
11
|
import getAppAndVersion from "./getAppAndVersion";
|
|
12
|
-
import appSupportsQuitApp from "../appSupportsQuitApp";
|
|
13
12
|
import { isDashboardName } from "./isDashboardName";
|
|
14
13
|
import { DeviceNotOnboarded } from "../errors";
|
|
15
|
-
|
|
16
|
-
import quitApp from "./quitApp";
|
|
14
|
+
|
|
17
15
|
import { DeviceInfo } from "@ledgerhq/types-live";
|
|
16
|
+
import attemptToQuitApp, { AttemptToQuitAppEvent } from "./attemptToQuitApp";
|
|
17
|
+
|
|
18
18
|
export type Input = {
|
|
19
19
|
devicePath: string;
|
|
20
20
|
managerRequest:
|
|
@@ -24,13 +24,9 @@ export type Input = {
|
|
|
24
24
|
| null
|
|
25
25
|
| undefined;
|
|
26
26
|
};
|
|
27
|
+
|
|
27
28
|
export type ConnectManagerEvent =
|
|
28
|
-
|
|
|
29
|
-
type: "appDetected";
|
|
30
|
-
}
|
|
31
|
-
| {
|
|
32
|
-
type: "unresponsiveDevice";
|
|
33
|
-
}
|
|
29
|
+
| AttemptToQuitAppEvent
|
|
34
30
|
| {
|
|
35
31
|
type: "osu";
|
|
36
32
|
deviceInfo: DeviceInfo;
|
|
@@ -45,23 +41,6 @@ export type ConnectManagerEvent =
|
|
|
45
41
|
}
|
|
46
42
|
| ListAppsEvent;
|
|
47
43
|
|
|
48
|
-
const attemptToQuitApp = (
|
|
49
|
-
transport,
|
|
50
|
-
appAndVersion?: AppAndVersion
|
|
51
|
-
): Observable<ConnectManagerEvent> =>
|
|
52
|
-
appAndVersion && appSupportsQuitApp(appAndVersion)
|
|
53
|
-
? from(quitApp(transport)).pipe(
|
|
54
|
-
concatMap(() =>
|
|
55
|
-
of(<ConnectManagerEvent>{
|
|
56
|
-
type: "unresponsiveDevice",
|
|
57
|
-
})
|
|
58
|
-
),
|
|
59
|
-
catchError((e) => throwError(e))
|
|
60
|
-
)
|
|
61
|
-
: of({
|
|
62
|
-
type: "appDetected",
|
|
63
|
-
});
|
|
64
|
-
|
|
65
44
|
const cmd = ({
|
|
66
45
|
devicePath,
|
|
67
46
|
managerRequest,
|
package/src/hw/getDeviceInfo.ts
CHANGED
|
@@ -59,6 +59,9 @@ export default async function getDeviceInfo(
|
|
|
59
59
|
mcuVersion,
|
|
60
60
|
mcuTargetId,
|
|
61
61
|
flags,
|
|
62
|
+
bootloaderVersion,
|
|
63
|
+
hardwareVersion,
|
|
64
|
+
languageId,
|
|
62
65
|
} = res;
|
|
63
66
|
const isOSU = rawVersion.includes("-osu");
|
|
64
67
|
const version = rawVersion.replace("-osu", "");
|
|
@@ -105,5 +108,8 @@ export default async function getDeviceInfo(
|
|
|
105
108
|
managerAllowed,
|
|
106
109
|
pinValidated,
|
|
107
110
|
onboarded,
|
|
111
|
+
bootloaderVersion,
|
|
112
|
+
hardwareVersion,
|
|
113
|
+
languageId,
|
|
108
114
|
};
|
|
109
115
|
}
|