@metamask-previews/account-tree-controller 0.6.0-preview-0cb117e2 → 0.6.0-preview-bd86fa14
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 +0 -16
- package/dist/AccountTreeController.cjs +40 -194
- package/dist/AccountTreeController.cjs.map +1 -1
- package/dist/AccountTreeController.d.cts +40 -31
- package/dist/AccountTreeController.d.cts.map +1 -1
- package/dist/AccountTreeController.d.mts +40 -31
- package/dist/AccountTreeController.d.mts.map +1 -1
- package/dist/AccountTreeController.mjs +38 -192
- package/dist/AccountTreeController.mjs.map +1 -1
- package/dist/AccountTreeGroup.cjs +35 -44
- package/dist/AccountTreeGroup.cjs.map +1 -1
- package/dist/AccountTreeGroup.d.cts +22 -15
- package/dist/AccountTreeGroup.d.cts.map +1 -1
- package/dist/AccountTreeGroup.d.mts +22 -15
- package/dist/AccountTreeGroup.d.mts.map +1 -1
- package/dist/AccountTreeGroup.mjs +33 -42
- package/dist/AccountTreeGroup.mjs.map +1 -1
- package/dist/AccountTreeWallet.cjs +26 -53
- package/dist/AccountTreeWallet.cjs.map +1 -1
- package/dist/AccountTreeWallet.d.cts +21 -26
- package/dist/AccountTreeWallet.d.cts.map +1 -1
- package/dist/AccountTreeWallet.d.mts +21 -26
- package/dist/AccountTreeWallet.d.mts.map +1 -1
- package/dist/AccountTreeWallet.mjs +25 -52
- package/dist/AccountTreeWallet.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/rules/EntropySourceWalletRule.cjs +100 -0
- package/dist/rules/EntropySourceWalletRule.cjs.map +1 -0
- package/dist/rules/EntropySourceWalletRule.d.cts +19 -0
- package/dist/rules/EntropySourceWalletRule.d.cts.map +1 -0
- package/dist/rules/EntropySourceWalletRule.d.mts +19 -0
- package/dist/rules/EntropySourceWalletRule.d.mts.map +1 -0
- package/dist/rules/EntropySourceWalletRule.mjs +95 -0
- package/dist/rules/EntropySourceWalletRule.mjs.map +1 -0
- package/dist/rules/KeyringWalletRule.cjs +99 -0
- package/dist/rules/KeyringWalletRule.cjs.map +1 -0
- package/dist/rules/KeyringWalletRule.d.cts +18 -0
- package/dist/rules/KeyringWalletRule.d.cts.map +1 -0
- package/dist/rules/KeyringWalletRule.d.mts +18 -0
- package/dist/rules/KeyringWalletRule.d.mts.map +1 -0
- package/dist/rules/KeyringWalletRule.mjs +94 -0
- package/dist/rules/KeyringWalletRule.mjs.map +1 -0
- package/dist/rules/SnapWalletRule.cjs +70 -0
- package/dist/rules/SnapWalletRule.cjs.map +1 -0
- package/dist/rules/SnapWalletRule.d.cts +10 -0
- package/dist/rules/SnapWalletRule.d.cts.map +1 -0
- package/dist/rules/SnapWalletRule.d.mts +10 -0
- package/dist/rules/SnapWalletRule.d.mts.map +1 -0
- package/dist/rules/SnapWalletRule.mjs +66 -0
- package/dist/rules/SnapWalletRule.mjs.map +1 -0
- package/dist/rules/WalletRule.cjs +13 -0
- package/dist/rules/WalletRule.cjs.map +1 -0
- package/dist/rules/WalletRule.d.cts +37 -0
- package/dist/rules/WalletRule.d.cts.map +1 -0
- package/dist/rules/WalletRule.d.mts +37 -0
- package/dist/rules/WalletRule.d.mts.map +1 -0
- package/dist/rules/WalletRule.mjs +9 -0
- package/dist/rules/WalletRule.mjs.map +1 -0
- package/dist/rules/index.cjs +21 -0
- package/dist/rules/index.cjs.map +1 -0
- package/dist/rules/index.d.cts +5 -0
- package/dist/rules/index.d.cts.map +1 -0
- package/dist/rules/index.d.mts +5 -0
- package/dist/rules/index.d.mts.map +1 -0
- package/dist/rules/index.mjs +5 -0
- package/dist/rules/index.mjs.map +1 -0
- package/dist/rules/utils.cjs +15 -0
- package/dist/rules/utils.cjs.map +1 -0
- package/dist/rules/utils.d.cts +11 -0
- package/dist/rules/utils.d.cts.map +1 -0
- package/dist/rules/utils.d.mts +11 -0
- package/dist/rules/utils.d.mts.map +1 -0
- package/dist/rules/utils.mjs +11 -0
- package/dist/rules/utils.mjs.map +1 -0
- package/package.json +3 -3
- package/dist/AccountTreeRule.cjs +0 -37
- package/dist/AccountTreeRule.cjs.map +0 -1
- package/dist/AccountTreeRule.d.cts +0 -53
- package/dist/AccountTreeRule.d.cts.map +0 -1
- package/dist/AccountTreeRule.d.mts +0 -53
- package/dist/AccountTreeRule.d.mts.map +0 -1
- package/dist/AccountTreeRule.mjs +0 -33
- package/dist/AccountTreeRule.mjs.map +0 -1
- package/dist/rules/entropy.cjs +0 -68
- package/dist/rules/entropy.cjs.map +0 -1
- package/dist/rules/entropy.d.cts +0 -13
- package/dist/rules/entropy.d.cts.map +0 -1
- package/dist/rules/entropy.d.mts +0 -13
- package/dist/rules/entropy.d.mts.map +0 -1
- package/dist/rules/entropy.mjs +0 -64
- package/dist/rules/entropy.mjs.map +0 -1
- package/dist/rules/keyring.cjs +0 -86
- package/dist/rules/keyring.cjs.map +0 -1
- package/dist/rules/keyring.d.cts +0 -21
- package/dist/rules/keyring.d.cts.map +0 -1
- package/dist/rules/keyring.d.mts +0 -21
- package/dist/rules/keyring.d.mts.map +0 -1
- package/dist/rules/keyring.mjs +0 -81
- package/dist/rules/keyring.mjs.map +0 -1
- package/dist/rules/snap.cjs +0 -58
- package/dist/rules/snap.cjs.map +0 -1
- package/dist/rules/snap.d.cts +0 -22
- package/dist/rules/snap.d.cts.map +0 -1
- package/dist/rules/snap.d.mts +0 -22
- package/dist/rules/snap.d.mts.map +0 -1
- package/dist/rules/snap.mjs +0 -54
- package/dist/rules/snap.mjs.map +0 -1
- package/dist/types.cjs +0 -3
- package/dist/types.cjs.map +0 -1
- package/dist/types.d.cts +0 -83
- package/dist/types.d.cts.map +0 -1
- package/dist/types.d.mts +0 -83
- package/dist/types.d.mts.map +0 -1
- package/dist/types.mjs +0 -2
- package/dist/types.mjs.map +0 -1
|
@@ -9,14 +9,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _AccountTreeController_instances,
|
|
13
|
-
import { AccountWalletCategory } from "@metamask/account-api";
|
|
12
|
+
var _AccountTreeController_instances, _AccountTreeController_reverse, _AccountTreeController_rules, _AccountTreeController_wallets, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_insert, _AccountTreeController_listAccounts;
|
|
14
13
|
import { BaseController } from "@metamask/base-controller";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
import { KeyringRule } from "./rules/keyring.mjs";
|
|
18
|
-
import { SnapRule } from "./rules/snap.mjs";
|
|
19
|
-
export const controllerName = 'AccountTreeController';
|
|
14
|
+
import { EntropySourceWalletRule, SnapWalletRule, KeyringWalletRule } from "./rules/index.mjs";
|
|
15
|
+
const controllerName = 'AccountTreeController';
|
|
20
16
|
const accountTreeControllerMetadata = {
|
|
21
17
|
accountTree: {
|
|
22
18
|
persist: false,
|
|
@@ -32,7 +28,6 @@ export function getDefaultAccountTreeControllerState() {
|
|
|
32
28
|
return {
|
|
33
29
|
accountTree: {
|
|
34
30
|
wallets: {},
|
|
35
|
-
selectedAccountGroup: '',
|
|
36
31
|
},
|
|
37
32
|
};
|
|
38
33
|
}
|
|
@@ -55,24 +50,20 @@ export class AccountTreeController extends BaseController {
|
|
|
55
50
|
},
|
|
56
51
|
});
|
|
57
52
|
_AccountTreeController_instances.add(this);
|
|
58
|
-
|
|
53
|
+
_AccountTreeController_reverse.set(this, void 0);
|
|
59
54
|
_AccountTreeController_rules.set(this, void 0);
|
|
60
|
-
|
|
55
|
+
_AccountTreeController_wallets.set(this, void 0);
|
|
56
|
+
__classPrivateFieldSet(this, _AccountTreeController_wallets, new Map(), "f");
|
|
61
57
|
// Reverse map to allow fast node access from an account ID.
|
|
62
|
-
__classPrivateFieldSet(this,
|
|
58
|
+
__classPrivateFieldSet(this, _AccountTreeController_reverse, new Map(), "f");
|
|
63
59
|
// Rules to apply to construct the wallets tree.
|
|
64
|
-
__classPrivateFieldSet(this, _AccountTreeController_categoryToRule, {
|
|
65
|
-
[AccountWalletCategory.Entropy]: new EntropyRule(this.messagingSystem),
|
|
66
|
-
[AccountWalletCategory.Snap]: new SnapRule(this.messagingSystem),
|
|
67
|
-
[AccountWalletCategory.Keyring]: new KeyringRule(this.messagingSystem),
|
|
68
|
-
}, "f");
|
|
69
60
|
__classPrivateFieldSet(this, _AccountTreeController_rules, [
|
|
70
61
|
// 1. We group by entropy-source
|
|
71
|
-
|
|
62
|
+
new EntropySourceWalletRule(this.messagingSystem),
|
|
72
63
|
// 2. We group by Snap ID
|
|
73
|
-
|
|
64
|
+
new SnapWalletRule(this.messagingSystem),
|
|
74
65
|
// 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)
|
|
75
|
-
|
|
66
|
+
new KeyringWalletRule(this.messagingSystem),
|
|
76
67
|
], "f");
|
|
77
68
|
this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => {
|
|
78
69
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountAdded).call(this, account);
|
|
@@ -80,10 +71,6 @@ export class AccountTreeController extends BaseController {
|
|
|
80
71
|
this.messagingSystem.subscribe('AccountsController:accountRemoved', (accountId) => {
|
|
81
72
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountRemoved).call(this, accountId);
|
|
82
73
|
});
|
|
83
|
-
this.messagingSystem.subscribe('AccountsController:selectedAccountChange', (account) => {
|
|
84
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleSelectedAccountChange).call(this, account);
|
|
85
|
-
});
|
|
86
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_registerMessageHandlers).call(this);
|
|
87
74
|
}
|
|
88
75
|
init() {
|
|
89
76
|
const wallets = {};
|
|
@@ -91,165 +78,62 @@ export class AccountTreeController extends BaseController {
|
|
|
91
78
|
for (const account of __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_listAccounts).call(this)) {
|
|
92
79
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, wallets, account);
|
|
93
80
|
}
|
|
94
|
-
// Once we have the account tree, we can compute the name.
|
|
95
|
-
for (const wallet of Object.values(wallets)) {
|
|
96
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_renameAccountWalletIfNeeded).call(this, wallet);
|
|
97
|
-
for (const group of Object.values(wallet.groups)) {
|
|
98
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_renameAccountGroupIfNeeded).call(this, wallet, group);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
81
|
this.update((state) => {
|
|
102
82
|
state.accountTree.wallets = wallets;
|
|
103
|
-
if (state.accountTree.selectedAccountGroup === '') {
|
|
104
|
-
// No group is selected yet, re-sync with the AccountsController.
|
|
105
|
-
state.accountTree.selectedAccountGroup =
|
|
106
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultSelectedAccountGroup).call(this, wallets);
|
|
107
|
-
}
|
|
108
83
|
});
|
|
109
84
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (!wallet) {
|
|
113
|
-
return undefined;
|
|
114
|
-
}
|
|
115
|
-
return new AccountTreeWallet({ messenger: this.messagingSystem, wallet });
|
|
85
|
+
getWallet(id) {
|
|
86
|
+
return __classPrivateFieldGet(this, _AccountTreeController_wallets, "f").get(id);
|
|
116
87
|
}
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
return new AccountTreeWallet({ messenger: this.messagingSystem, wallet });
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Gets the currently selected account group ID.
|
|
124
|
-
*
|
|
125
|
-
* @returns The selected account group ID or empty string if none selected.
|
|
126
|
-
*/
|
|
127
|
-
getSelectedAccountGroup() {
|
|
128
|
-
return this.state.accountTree.selectedAccountGroup;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Sets the selected account group and updates the AccountsController selectedAccount accordingly.
|
|
132
|
-
*
|
|
133
|
-
* @param groupId - The account group ID to select.
|
|
134
|
-
*/
|
|
135
|
-
setSelectedAccountGroup(groupId) {
|
|
136
|
-
const currentSelectedGroup = this.state.accountTree.selectedAccountGroup;
|
|
137
|
-
// Idempotent check - if the same group is already selected, do nothing
|
|
138
|
-
if (currentSelectedGroup === groupId) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// Find the first account in this group to select
|
|
142
|
-
const accountToSelect = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getFirstAccountInGroup).call(this, groupId);
|
|
143
|
-
if (!accountToSelect) {
|
|
144
|
-
throw new Error(`No accounts found in group: ${groupId}`);
|
|
145
|
-
}
|
|
146
|
-
// Update our state first
|
|
147
|
-
this.update((state) => {
|
|
148
|
-
state.accountTree.selectedAccountGroup = groupId;
|
|
149
|
-
});
|
|
150
|
-
// Update AccountsController - this will trigger selectedAccountChange event,
|
|
151
|
-
// but our handler is idempotent so it won't cause infinite loop
|
|
152
|
-
this.messagingSystem.call('AccountsController:setSelectedAccount', accountToSelect);
|
|
88
|
+
getWallets() {
|
|
89
|
+
return Array.from(__classPrivateFieldGet(this, _AccountTreeController_wallets, "f").values());
|
|
153
90
|
}
|
|
154
91
|
}
|
|
155
|
-
|
|
156
|
-
const selectedAccount = this.messagingSystem.call('AccountsController:getSelectedAccount');
|
|
157
|
-
if (selectedAccount && selectedAccount.id) {
|
|
158
|
-
const accountMapping = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(selectedAccount.id);
|
|
159
|
-
if (accountMapping) {
|
|
160
|
-
const { groupId } = accountMapping;
|
|
161
|
-
return groupId;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// Default to the first non-empty group in case of errors.
|
|
165
|
-
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_findFirstNonEmptyGroup).call(this, wallets);
|
|
166
|
-
}, _AccountTreeController_renameAccountWalletIfNeeded = function _AccountTreeController_renameAccountWalletIfNeeded(wallet) {
|
|
167
|
-
if (wallet.metadata.name) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const rule = __classPrivateFieldGet(this, _AccountTreeController_categoryToRule, "f")[wallet.metadata.type];
|
|
171
|
-
wallet.metadata.name = rule.getDefaultAccountWalletName(wallet);
|
|
172
|
-
}, _AccountTreeController_renameAccountGroupIfNeeded = function _AccountTreeController_renameAccountGroupIfNeeded(wallet, group) {
|
|
173
|
-
if (group.metadata.name) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const rule = __classPrivateFieldGet(this, _AccountTreeController_categoryToRule, "f")[wallet.metadata.type];
|
|
177
|
-
group.metadata.name = rule.getDefaultAccountGroupName(group);
|
|
178
|
-
}, _AccountTreeController_handleAccountAdded = function _AccountTreeController_handleAccountAdded(account) {
|
|
92
|
+
_AccountTreeController_reverse = new WeakMap(), _AccountTreeController_rules = new WeakMap(), _AccountTreeController_wallets = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_handleAccountAdded = function _AccountTreeController_handleAccountAdded(account) {
|
|
179
93
|
this.update((state) => {
|
|
180
94
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, state.accountTree.wallets, account);
|
|
181
|
-
const context = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(account.id);
|
|
182
|
-
if (context) {
|
|
183
|
-
const { walletId, groupId } = context;
|
|
184
|
-
const wallet = state.accountTree.wallets[walletId];
|
|
185
|
-
if (wallet) {
|
|
186
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_renameAccountWalletIfNeeded).call(this, wallet);
|
|
187
|
-
const group = wallet.groups[groupId];
|
|
188
|
-
if (group) {
|
|
189
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_renameAccountGroupIfNeeded).call(this, wallet, group);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
95
|
});
|
|
194
96
|
}, _AccountTreeController_handleAccountRemoved = function _AccountTreeController_handleAccountRemoved(accountId) {
|
|
195
|
-
const
|
|
196
|
-
if (
|
|
197
|
-
const { walletId, groupId } =
|
|
97
|
+
const found = __classPrivateFieldGet(this, _AccountTreeController_reverse, "f").get(accountId);
|
|
98
|
+
if (found) {
|
|
99
|
+
const { walletId, groupId } = found;
|
|
198
100
|
this.update((state) => {
|
|
199
101
|
const { accounts } = state.accountTree.wallets[walletId].groups[groupId];
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
accounts.splice(index, 1);
|
|
204
|
-
// Check if we need to update selectedAccountGroup after removal
|
|
205
|
-
if (state.accountTree.selectedAccountGroup === groupId &&
|
|
206
|
-
accounts.length === 0) {
|
|
207
|
-
// The currently selected group is now empty, find a new group to select
|
|
208
|
-
state.accountTree.selectedAccountGroup =
|
|
209
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_findFirstNonEmptyGroup).call(this, state.accountTree.wallets);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
102
|
+
const index = accounts.indexOf(accountId);
|
|
103
|
+
if (index !== -1) {
|
|
104
|
+
accounts.splice(index, 1);
|
|
212
105
|
}
|
|
213
106
|
});
|
|
214
|
-
// Clear reverse-mapping for that account.
|
|
215
|
-
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").delete(accountId);
|
|
216
107
|
}
|
|
217
108
|
}, _AccountTreeController_insert = function _AccountTreeController_insert(wallets, account) {
|
|
218
109
|
for (const rule of __classPrivateFieldGet(this, _AccountTreeController_rules, "f")) {
|
|
219
|
-
const
|
|
220
|
-
if (!
|
|
110
|
+
const match = rule.match(account);
|
|
111
|
+
if (!match) {
|
|
221
112
|
// No match for that rule, we go to the next one.
|
|
222
113
|
continue;
|
|
223
114
|
}
|
|
115
|
+
const { wallet, group } = match;
|
|
116
|
+
// Update in-memory wallet/group instances.
|
|
117
|
+
__classPrivateFieldGet(this, _AccountTreeController_wallets, "f").set(wallet.id, wallet);
|
|
224
118
|
// Update controller's state.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
119
|
+
if (!wallets[wallet.id]) {
|
|
120
|
+
wallets[wallet.id] = {
|
|
121
|
+
id: wallet.id,
|
|
122
|
+
groups: {
|
|
123
|
+
[group.id]: {
|
|
124
|
+
id: group.id,
|
|
125
|
+
accounts: [],
|
|
126
|
+
metadata: { name: group.getDefaultName() },
|
|
127
|
+
},
|
|
234
128
|
},
|
|
235
|
-
};
|
|
236
|
-
wallet = wallets[walletId];
|
|
237
|
-
}
|
|
238
|
-
const groupId = result.group.id;
|
|
239
|
-
let group = wallet.groups[groupId];
|
|
240
|
-
if (!group) {
|
|
241
|
-
wallet.groups[groupId] = {
|
|
242
|
-
id: groupId,
|
|
243
|
-
accounts: [],
|
|
244
129
|
metadata: {
|
|
245
|
-
name:
|
|
130
|
+
name: wallet.getDefaultName(),
|
|
246
131
|
},
|
|
247
132
|
};
|
|
248
|
-
group = wallet.groups[groupId];
|
|
249
133
|
}
|
|
250
|
-
group.accounts.push(account.id);
|
|
134
|
+
wallets[wallet.id].groups[group.id].accounts.push(account.id);
|
|
251
135
|
// Update the reverse mapping for this account.
|
|
252
|
-
__classPrivateFieldGet(this,
|
|
136
|
+
__classPrivateFieldGet(this, _AccountTreeController_reverse, "f").set(account.id, {
|
|
253
137
|
walletId: wallet.id,
|
|
254
138
|
groupId: group.id,
|
|
255
139
|
});
|
|
@@ -257,43 +141,5 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
257
141
|
}
|
|
258
142
|
}, _AccountTreeController_listAccounts = function _AccountTreeController_listAccounts() {
|
|
259
143
|
return this.messagingSystem.call('AccountsController:listMultichainAccounts');
|
|
260
|
-
}, _AccountTreeController_handleSelectedAccountChange = function _AccountTreeController_handleSelectedAccountChange(account) {
|
|
261
|
-
const accountMapping = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(account.id);
|
|
262
|
-
if (!accountMapping) {
|
|
263
|
-
// Account not in tree yet, might be during initialization
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const { groupId } = accountMapping;
|
|
267
|
-
const currentSelectedGroup = this.state.accountTree.selectedAccountGroup;
|
|
268
|
-
// Idempotent check - if the same group is already selected, do nothing
|
|
269
|
-
if (currentSelectedGroup === groupId) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
// Update selectedAccountGroup to match the selected account
|
|
273
|
-
this.update((state) => {
|
|
274
|
-
state.accountTree.selectedAccountGroup = groupId;
|
|
275
|
-
});
|
|
276
|
-
}, _AccountTreeController_getFirstAccountInGroup = function _AccountTreeController_getFirstAccountInGroup(groupId) {
|
|
277
|
-
for (const wallet of Object.values(this.state.accountTree.wallets)) {
|
|
278
|
-
if (wallet.groups[groupId]) {
|
|
279
|
-
const group = wallet.groups[groupId];
|
|
280
|
-
if (group && group.accounts.length > 0) {
|
|
281
|
-
return group.accounts[0];
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return undefined;
|
|
286
|
-
}, _AccountTreeController_findFirstNonEmptyGroup = function _AccountTreeController_findFirstNonEmptyGroup(wallets) {
|
|
287
|
-
for (const wallet of Object.values(wallets)) {
|
|
288
|
-
for (const group of Object.values(wallet.groups)) {
|
|
289
|
-
if (group.accounts.length > 0) {
|
|
290
|
-
return group.id;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return '';
|
|
295
|
-
}, _AccountTreeController_registerMessageHandlers = function _AccountTreeController_registerMessageHandlers() {
|
|
296
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:getSelectedAccountGroup`, this.getSelectedAccountGroup.bind(this));
|
|
297
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:setSelectedAccountGroup`, this.setSelectedAccountGroup.bind(this));
|
|
298
144
|
};
|
|
299
145
|
//# sourceMappingURL=AccountTreeController.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTreeController.mjs","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport { AccountWalletCategory } from '@metamask/account-api';\nimport type { AccountId } from '@metamask/accounts-controller';\nimport type { StateMetadata } from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport type { AccountTreeRule } from './AccountTreeRule';\nimport { AccountTreeWallet } from './AccountTreeWallet';\nimport { EntropyRule } from './rules/entropy';\nimport { KeyringRule } from './rules/keyring';\nimport { SnapRule } from './rules/snap';\nimport type {\n AccountGroupObject,\n AccountTreeControllerMessenger,\n AccountTreeControllerState,\n AccountWalletObject,\n} from './types';\n\nexport const controllerName = 'AccountTreeController';\n\nconst accountTreeControllerMetadata: StateMetadata<AccountTreeControllerState> =\n {\n accountTree: {\n persist: false, // We do re-recompute this state everytime.\n anonymous: false,\n },\n };\n\n/**\n * Gets default state of the `AccountTreeController`.\n *\n * @returns The default state of the `AccountTreeController`.\n */\nexport function getDefaultAccountTreeControllerState(): AccountTreeControllerState {\n return {\n accountTree: {\n wallets: {},\n selectedAccountGroup: '',\n },\n };\n}\n\n/**\n * Context for an account.\n */\nexport type AccountContext = {\n /**\n * Wallet ID associated to that account.\n */\n walletId: AccountWalletId;\n\n /**\n * Account group ID associated to that account.\n */\n groupId: AccountGroupId;\n};\n\nexport class AccountTreeController extends BaseController<\n typeof controllerName,\n AccountTreeControllerState,\n AccountTreeControllerMessenger\n> {\n readonly #accountIdToContext: Map<AccountId, AccountContext>;\n\n readonly #rules: AccountTreeRule[];\n\n readonly #categoryToRule: Record<AccountWalletCategory, AccountTreeRule>;\n\n /**\n * Constructor for AccountTreeController.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger object.\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AccountTreeControllerMessenger;\n state?: Partial<AccountTreeControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: accountTreeControllerMetadata,\n state: {\n ...getDefaultAccountTreeControllerState(),\n ...state,\n },\n });\n\n // Reverse map to allow fast node access from an account ID.\n this.#accountIdToContext = new Map();\n\n // Rules to apply to construct the wallets tree.\n this.#categoryToRule = {\n [AccountWalletCategory.Entropy]: new EntropyRule(this.messagingSystem),\n [AccountWalletCategory.Snap]: new SnapRule(this.messagingSystem),\n [AccountWalletCategory.Keyring]: new KeyringRule(this.messagingSystem),\n } as const;\n this.#rules = [\n // 1. We group by entropy-source\n this.#categoryToRule[AccountWalletCategory.Entropy],\n // 2. We group by Snap ID\n this.#categoryToRule[AccountWalletCategory.Snap],\n // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)\n this.#categoryToRule[AccountWalletCategory.Keyring],\n ];\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account) => {\n this.#handleAccountAdded(account);\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (accountId) => {\n this.#handleAccountRemoved(accountId);\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => {\n this.#handleSelectedAccountChange(account);\n },\n );\n\n this.#registerMessageHandlers();\n }\n\n init() {\n const wallets: AccountTreeControllerState['accountTree']['wallets'] = {};\n\n // For now, we always re-compute all wallets, we do not re-use the existing state.\n for (const account of this.#listAccounts()) {\n this.#insert(wallets, account);\n }\n\n // Once we have the account tree, we can compute the name.\n for (const wallet of Object.values(wallets)) {\n this.#renameAccountWalletIfNeeded(wallet);\n\n for (const group of Object.values(wallet.groups)) {\n this.#renameAccountGroupIfNeeded(wallet, group);\n }\n }\n\n this.update((state) => {\n state.accountTree.wallets = wallets;\n\n if (state.accountTree.selectedAccountGroup === '') {\n // No group is selected yet, re-sync with the AccountsController.\n state.accountTree.selectedAccountGroup =\n this.#getDefaultSelectedAccountGroup(wallets);\n }\n });\n }\n\n /**\n * Initializes the selectedAccountGroup based on the currently selected account from AccountsController.\n *\n * @param wallets - Wallets object to use for fallback logic\n * @returns The default selected account group ID or empty string if none selected.\n */\n #getDefaultSelectedAccountGroup(wallets: {\n [walletId: AccountWalletId]: AccountWalletObject;\n }): AccountGroupId | '' {\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n if (selectedAccount && selectedAccount.id) {\n const accountMapping = this.#accountIdToContext.get(selectedAccount.id);\n if (accountMapping) {\n const { groupId } = accountMapping;\n\n return groupId;\n }\n }\n\n // Default to the first non-empty group in case of errors.\n return this.#findFirstNonEmptyGroup(wallets);\n }\n\n #renameAccountWalletIfNeeded(wallet: AccountWalletObject) {\n if (wallet.metadata.name) {\n return;\n }\n\n const rule = this.#categoryToRule[wallet.metadata.type];\n wallet.metadata.name = rule.getDefaultAccountWalletName(wallet);\n }\n\n #renameAccountGroupIfNeeded(\n wallet: AccountWalletObject,\n group: AccountGroupObject,\n ) {\n if (group.metadata.name) {\n return;\n }\n\n const rule = this.#categoryToRule[wallet.metadata.type];\n group.metadata.name = rule.getDefaultAccountGroupName(group);\n }\n\n getAccountWallet(walletId: AccountWalletId): AccountTreeWallet | undefined {\n const wallet = this.state.accountTree.wallets[walletId];\n if (!wallet) {\n return undefined;\n }\n\n return new AccountTreeWallet({ messenger: this.messagingSystem, wallet });\n }\n\n getAccountWallets(): AccountTreeWallet[] {\n return Object.values(this.state.accountTree.wallets).map((wallet) => {\n return new AccountTreeWallet({ messenger: this.messagingSystem, wallet });\n });\n }\n\n #handleAccountAdded(account: InternalAccount) {\n this.update((state) => {\n this.#insert(state.accountTree.wallets, account);\n\n const context = this.#accountIdToContext.get(account.id);\n if (context) {\n const { walletId, groupId } = context;\n\n const wallet = state.accountTree.wallets[walletId];\n if (wallet) {\n this.#renameAccountWalletIfNeeded(wallet);\n\n const group = wallet.groups[groupId];\n if (group) {\n this.#renameAccountGroupIfNeeded(wallet, group);\n }\n }\n }\n });\n }\n\n #handleAccountRemoved(accountId: AccountId) {\n const context = this.#accountIdToContext.get(accountId);\n\n if (context) {\n const { walletId, groupId } = context;\n\n this.update((state) => {\n const { accounts } =\n state.accountTree.wallets[walletId].groups[groupId];\n\n if (accounts) {\n const index = accounts.indexOf(accountId);\n if (index !== -1) {\n accounts.splice(index, 1);\n\n // Check if we need to update selectedAccountGroup after removal\n if (\n state.accountTree.selectedAccountGroup === groupId &&\n accounts.length === 0\n ) {\n // The currently selected group is now empty, find a new group to select\n state.accountTree.selectedAccountGroup =\n this.#findFirstNonEmptyGroup(state.accountTree.wallets);\n }\n }\n }\n });\n\n // Clear reverse-mapping for that account.\n this.#accountIdToContext.delete(accountId);\n }\n }\n\n #insert(\n wallets: AccountTreeControllerState['accountTree']['wallets'],\n account: InternalAccount,\n ) {\n for (const rule of this.#rules) {\n const result = rule.match(account);\n\n if (!result) {\n // No match for that rule, we go to the next one.\n continue;\n }\n\n // Update controller's state.\n const walletId = result.wallet.id;\n let wallet = wallets[walletId];\n if (!wallet) {\n wallets[walletId] = {\n id: walletId,\n groups: {},\n metadata: {\n name: '', // Will get updated later.\n ...result.wallet.metadata,\n },\n };\n wallet = wallets[walletId];\n }\n\n const groupId = result.group.id;\n let group = wallet.groups[groupId];\n if (!group) {\n wallet.groups[groupId] = {\n id: groupId,\n accounts: [],\n metadata: {\n name: '', // Will get updated later.\n },\n };\n group = wallet.groups[groupId];\n }\n\n group.accounts.push(account.id);\n\n // Update the reverse mapping for this account.\n this.#accountIdToContext.set(account.id, {\n walletId: wallet.id,\n groupId: group.id,\n });\n\n return;\n }\n }\n\n #listAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Gets the currently selected account group ID.\n *\n * @returns The selected account group ID or empty string if none selected.\n */\n getSelectedAccountGroup(): AccountGroupId | '' {\n return this.state.accountTree.selectedAccountGroup;\n }\n\n /**\n * Sets the selected account group and updates the AccountsController selectedAccount accordingly.\n *\n * @param groupId - The account group ID to select.\n */\n setSelectedAccountGroup(groupId: AccountGroupId): void {\n const currentSelectedGroup = this.state.accountTree.selectedAccountGroup;\n\n // Idempotent check - if the same group is already selected, do nothing\n if (currentSelectedGroup === groupId) {\n return;\n }\n\n // Find the first account in this group to select\n const accountToSelect = this.#getFirstAccountInGroup(groupId);\n if (!accountToSelect) {\n throw new Error(`No accounts found in group: ${groupId}`);\n }\n\n // Update our state first\n this.update((state) => {\n state.accountTree.selectedAccountGroup = groupId;\n });\n\n // Update AccountsController - this will trigger selectedAccountChange event,\n // but our handler is idempotent so it won't cause infinite loop\n this.messagingSystem.call(\n 'AccountsController:setSelectedAccount',\n accountToSelect,\n );\n }\n\n /**\n * Handles selected account change from AccountsController.\n * Updates selectedAccountGroup to match the selected account.\n *\n * @param account - The newly selected account.\n */\n #handleSelectedAccountChange(account: InternalAccount): void {\n const accountMapping = this.#accountIdToContext.get(account.id);\n if (!accountMapping) {\n // Account not in tree yet, might be during initialization\n return;\n }\n\n const { groupId } = accountMapping;\n const currentSelectedGroup = this.state.accountTree.selectedAccountGroup;\n\n // Idempotent check - if the same group is already selected, do nothing\n if (currentSelectedGroup === groupId) {\n return;\n }\n\n // Update selectedAccountGroup to match the selected account\n this.update((state) => {\n state.accountTree.selectedAccountGroup = groupId;\n });\n }\n\n /**\n * Gets the first account ID in the specified group.\n *\n * @param groupId - The account group ID.\n * @returns The first account ID in the group, or undefined if no accounts found.\n */\n #getFirstAccountInGroup(groupId: AccountGroupId): AccountId | undefined {\n for (const wallet of Object.values(this.state.accountTree.wallets)) {\n if (wallet.groups[groupId]) {\n const group = wallet.groups[groupId];\n if (group && group.accounts.length > 0) {\n return group.accounts[0];\n }\n }\n }\n return undefined;\n }\n\n /**\n * Finds the first non-empty group in the given wallets object.\n *\n * @param wallets - The wallets object to search.\n * @returns The ID of the first non-empty group, or an empty string if no groups are found.\n */\n #findFirstNonEmptyGroup(wallets: {\n [walletId: AccountWalletId]: AccountWalletObject;\n }): AccountGroupId | '' {\n for (const wallet of Object.values(wallets)) {\n for (const group of Object.values(wallet.groups)) {\n if (group.accounts.length > 0) {\n return group.id;\n }\n }\n }\n return '';\n }\n\n /**\n * Registers message handlers for the AccountTreeController.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:getSelectedAccountGroup`,\n this.getSelectedAccountGroup.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:setSelectedAccountGroup`,\n this.setSelectedAccountGroup.bind(this),\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccountTreeController.mjs","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type { StateMetadata } from '@metamask/base-controller';\nimport {\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n BaseController,\n} from '@metamask/base-controller';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\n\nimport type { AccountTreeWallet } from './AccountTreeWallet';\nimport type { WalletRule } from './rules';\nimport {\n EntropySourceWalletRule,\n SnapWalletRule,\n KeyringWalletRule,\n} from './rules';\n\nconst controllerName = 'AccountTreeController';\n\ntype AccountReverseMapping = {\n walletId: AccountWalletId;\n groupId: AccountGroupId;\n};\n\n// Do not export this one, we just use it to have a common type interface between group and wallet metadata.\ntype Metadata = {\n name: string;\n};\n\nexport type AccountWalletMetadata = Metadata;\n\nexport type AccountGroupMetadata = Metadata;\n\nexport type AccountGroupObject = {\n id: AccountGroupId;\n // Blockchain Accounts:\n accounts: AccountId[];\n metadata: AccountGroupMetadata;\n};\n\nexport type AccountWalletObject = {\n id: AccountWalletId;\n // Account groups OR Multichain accounts (once available).\n groups: {\n [groupId: AccountGroupId]: AccountGroupObject;\n };\n metadata: AccountWalletMetadata;\n};\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n };\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerListMultichainAccountsAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap;\n\nexport type AccountTreeControllerActions = never;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent;\n\nexport type AccountTreeControllerEvents = AccountTreeControllerStateChangeEvent;\n\nexport type AccountTreeControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\nconst accountTreeControllerMetadata: StateMetadata<AccountTreeControllerState> =\n {\n accountTree: {\n persist: false, // We do re-recompute this state everytime.\n anonymous: false,\n },\n };\n\n/**\n * Gets default state of the `AccountTreeController`.\n *\n * @returns The default state of the `AccountTreeController`.\n */\nexport function getDefaultAccountTreeControllerState(): AccountTreeControllerState {\n return {\n accountTree: {\n wallets: {},\n },\n };\n}\n\nexport class AccountTreeController extends BaseController<\n typeof controllerName,\n AccountTreeControllerState,\n AccountTreeControllerMessenger\n> {\n readonly #reverse: Map<AccountId, AccountReverseMapping>;\n\n readonly #rules: WalletRule[];\n\n readonly #wallets: Map<AccountWalletId, AccountTreeWallet>;\n\n /**\n * Constructor for AccountTreeController.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger object.\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AccountTreeControllerMessenger;\n state?: Partial<AccountTreeControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: accountTreeControllerMetadata,\n state: {\n ...getDefaultAccountTreeControllerState(),\n ...state,\n },\n });\n this.#wallets = new Map();\n\n // Reverse map to allow fast node access from an account ID.\n this.#reverse = new Map();\n\n // Rules to apply to construct the wallets tree.\n this.#rules = [\n // 1. We group by entropy-source\n new EntropySourceWalletRule(this.messagingSystem),\n // 2. We group by Snap ID\n new SnapWalletRule(this.messagingSystem),\n // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)\n new KeyringWalletRule(this.messagingSystem),\n ];\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account) => {\n this.#handleAccountAdded(account);\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (accountId) => {\n this.#handleAccountRemoved(accountId);\n },\n );\n }\n\n init() {\n const wallets = {};\n\n // For now, we always re-compute all wallets, we do not re-use the existing state.\n for (const account of this.#listAccounts()) {\n this.#insert(wallets, account);\n }\n\n this.update((state) => {\n state.accountTree.wallets = wallets;\n });\n }\n\n getWallet(id: AccountWalletId): AccountTreeWallet | undefined {\n return this.#wallets.get(id);\n }\n\n getWallets(): AccountTreeWallet[] {\n return Array.from(this.#wallets.values());\n }\n\n #handleAccountAdded(account: InternalAccount) {\n this.update((state) => {\n this.#insert(state.accountTree.wallets, account);\n });\n }\n\n #handleAccountRemoved(accountId: AccountId) {\n const found = this.#reverse.get(accountId);\n\n if (found) {\n const { walletId, groupId } = found;\n this.update((state) => {\n const { accounts } =\n state.accountTree.wallets[walletId].groups[groupId];\n\n const index = accounts.indexOf(accountId);\n if (index !== -1) {\n accounts.splice(index, 1);\n }\n });\n }\n }\n\n #insert(\n wallets: { [walletId: AccountWalletId]: AccountWalletObject },\n account: InternalAccount,\n ) {\n for (const rule of this.#rules) {\n const match = rule.match(account);\n\n if (!match) {\n // No match for that rule, we go to the next one.\n continue;\n }\n\n const { wallet, group } = match;\n\n // Update in-memory wallet/group instances.\n this.#wallets.set(wallet.id, wallet);\n\n // Update controller's state.\n if (!wallets[wallet.id]) {\n wallets[wallet.id] = {\n id: wallet.id,\n groups: {\n [group.id]: {\n id: group.id,\n accounts: [],\n metadata: { name: group.getDefaultName() },\n },\n },\n metadata: {\n name: wallet.getDefaultName(),\n },\n };\n }\n wallets[wallet.id].groups[group.id].accounts.push(account.id);\n\n // Update the reverse mapping for this account.\n this.#reverse.set(account.id, {\n walletId: wallet.id,\n groupId: group.id,\n });\n\n return;\n }\n }\n\n #listAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n}\n"]}
|
|
@@ -10,58 +10,49 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var
|
|
13
|
+
var _MutableAccountTreeGroup_accounts;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.
|
|
15
|
+
exports.MutableAccountTreeGroup = exports.DEFAULT_ACCOUNT_GROUP_NAME = void 0;
|
|
16
|
+
const account_api_1 = require("@metamask/account-api");
|
|
16
17
|
exports.DEFAULT_ACCOUNT_GROUP_NAME = 'Default';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
__classPrivateFieldSet(this, _AccountTreeGroup_messenger, messenger, "f");
|
|
27
|
-
__classPrivateFieldSet(this, _AccountTreeGroup_group, group, "f");
|
|
28
|
-
__classPrivateFieldSet(this, _AccountTreeGroup_wallet, wallet, "f");
|
|
29
|
-
}
|
|
30
|
-
get id() {
|
|
31
|
-
return __classPrivateFieldGet(this, _AccountTreeGroup_group, "f").id;
|
|
32
|
-
}
|
|
33
|
-
get wallet() {
|
|
34
|
-
return __classPrivateFieldGet(this, _AccountTreeGroup_wallet, "f");
|
|
35
|
-
}
|
|
36
|
-
get name() {
|
|
37
|
-
return __classPrivateFieldGet(this, _AccountTreeGroup_group, "f").metadata.name;
|
|
18
|
+
// This class is meant to be used internally by every rules. It exposes mutable operations
|
|
19
|
+
// which should not leak outside of this package.
|
|
20
|
+
class MutableAccountTreeGroup {
|
|
21
|
+
constructor(messenger, wallet, id) {
|
|
22
|
+
_MutableAccountTreeGroup_accounts.set(this, void 0);
|
|
23
|
+
this.id = (0, account_api_1.toAccountGroupId)(wallet.id, id);
|
|
24
|
+
this.wallet = wallet;
|
|
25
|
+
this.messenger = messenger;
|
|
26
|
+
__classPrivateFieldSet(this, _MutableAccountTreeGroup_accounts, new Set(), "f");
|
|
38
27
|
}
|
|
39
28
|
getAccountIds() {
|
|
40
|
-
return __classPrivateFieldGet(this,
|
|
29
|
+
return Array.from(__classPrivateFieldGet(this, _MutableAccountTreeGroup_accounts, "f")); // FIXME: Should we force the copy here?
|
|
30
|
+
}
|
|
31
|
+
getAccounts() {
|
|
32
|
+
const accounts = [];
|
|
33
|
+
for (const id of __classPrivateFieldGet(this, _MutableAccountTreeGroup_accounts, "f")) {
|
|
34
|
+
const account = this.getAccount(id);
|
|
35
|
+
// FIXME: I'm really not sure we should skip those but... We could be
|
|
36
|
+
// "de-sync" with the AccountsController and might have some dangling
|
|
37
|
+
// account IDs.
|
|
38
|
+
if (!account) {
|
|
39
|
+
console.warn(`! Unable to get account: "${id}"`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
accounts.push(account);
|
|
43
|
+
}
|
|
44
|
+
return accounts;
|
|
41
45
|
}
|
|
42
46
|
getAccount(id) {
|
|
43
|
-
return
|
|
47
|
+
return this.messenger.call('AccountsController:getAccount', id);
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
addAccount(account) {
|
|
50
|
+
__classPrivateFieldGet(this, _MutableAccountTreeGroup_accounts, "f").add(account.id);
|
|
47
51
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (accountIds.length === 0) {
|
|
51
|
-
throw new Error('Group contains no account');
|
|
52
|
-
}
|
|
53
|
-
if (accountIds.length > 1) {
|
|
54
|
-
throw new Error('Group contains more than 1 account');
|
|
55
|
-
}
|
|
56
|
-
return __classPrivateFieldGet(this, _AccountTreeGroup_instances, "m", _AccountTreeGroup_getAccount).call(this, accountIds[0]);
|
|
52
|
+
getDefaultName() {
|
|
53
|
+
return exports.DEFAULT_ACCOUNT_GROUP_NAME;
|
|
57
54
|
}
|
|
58
55
|
}
|
|
59
|
-
exports.
|
|
60
|
-
|
|
61
|
-
const account = this.getAccount(id);
|
|
62
|
-
if (!account) {
|
|
63
|
-
throw new Error(`Unable to get account with ID: "${id}"`);
|
|
64
|
-
}
|
|
65
|
-
return account;
|
|
66
|
-
};
|
|
56
|
+
exports.MutableAccountTreeGroup = MutableAccountTreeGroup;
|
|
57
|
+
_MutableAccountTreeGroup_accounts = new WeakMap();
|
|
67
58
|
//# sourceMappingURL=AccountTreeGroup.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTreeGroup.cjs","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"AccountTreeGroup.cjs","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,uDAK+B;AAKlB,QAAA,0BAA0B,GAAW,SAAS,CAAC;AAiB5D,0FAA0F;AAC1F,iDAAiD;AACjD,MAAa,uBAAuB;IASlC,YACE,SAAyC,EACzC,MAAsC,EACtC,EAAU;QALH,oDAA0B;QAOjC,IAAI,CAAC,EAAE,GAAG,IAAA,8BAAgB,EAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,uBAAA,IAAI,qCAAa,IAAI,GAAG,EAAE,MAAA,CAAC;IAC7B,CAAC;IAED,aAAa;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,uBAAA,IAAI,yCAAU,CAAC,CAAC,CAAC,wCAAwC;IAC7E,CAAC;IAED,WAAW;QACT,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,KAAK,MAAM,EAAE,IAAI,uBAAA,IAAI,yCAAU,EAAE;YAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAEpC,qEAAqE;YACrE,qEAAqE;YACrE,eAAe;YACf,IAAI,CAAC,OAAO,EAAE;gBACZ,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;gBACjD,SAAS;aACV;YACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SACxB;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,EAAa;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,UAAU,CAAC,OAAwB;QACjC,uBAAA,IAAI,yCAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,cAAc;QACZ,OAAO,kCAA0B,CAAC;IACpC,CAAC;CACF;AAtDD,0DAsDC","sourcesContent":["import {\n toAccountGroupId,\n type AccountGroup,\n type AccountGroupId,\n type AccountWallet,\n} from '@metamask/account-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport type { AccountTreeControllerMessenger } from 'src';\n\nexport const DEFAULT_ACCOUNT_GROUP_NAME: string = 'Default';\n\n/**\n * Account group coming from the {@link AccountTreeController}.\n */\nexport type AccountTreeGroup = {\n /**\n * Account IDs for that account group.\n */\n getAccountIds(): AccountId[];\n\n /**\n * Gets the default name for that account group.\n */\n getDefaultName(): string;\n} & AccountGroup<InternalAccount>;\n\n// This class is meant to be used internally by every rules. It exposes mutable operations\n// which should not leak outside of this package.\nexport class MutableAccountTreeGroup implements AccountTreeGroup {\n readonly id: AccountGroupId;\n\n readonly wallet: AccountWallet<InternalAccount>;\n\n readonly messenger: AccountTreeControllerMessenger;\n\n readonly #accounts: Set<AccountId>;\n\n constructor(\n messenger: AccountTreeControllerMessenger,\n wallet: AccountWallet<InternalAccount>,\n id: string,\n ) {\n this.id = toAccountGroupId(wallet.id, id);\n this.wallet = wallet;\n this.messenger = messenger;\n\n this.#accounts = new Set();\n }\n\n getAccountIds(): AccountId[] {\n return Array.from(this.#accounts); // FIXME: Should we force the copy here?\n }\n\n getAccounts(): InternalAccount[] {\n const accounts = [];\n\n for (const id of this.#accounts) {\n const account = this.getAccount(id);\n\n // FIXME: I'm really not sure we should skip those but... We could be\n // \"de-sync\" with the AccountsController and might have some dangling\n // account IDs.\n if (!account) {\n console.warn(`! Unable to get account: \"${id}\"`);\n continue;\n }\n accounts.push(account);\n }\n return accounts;\n }\n\n getAccount(id: AccountId): InternalAccount | undefined {\n return this.messenger.call('AccountsController:getAccount', id);\n }\n\n addAccount(account: InternalAccount) {\n this.#accounts.add(account.id);\n }\n\n getDefaultName(): string {\n return DEFAULT_ACCOUNT_GROUP_NAME;\n }\n}\n"]}
|
|
@@ -1,24 +1,31 @@
|
|
|
1
|
-
import { type AccountGroup, type AccountGroupId } from "@metamask/account-api";
|
|
1
|
+
import { type AccountGroup, type AccountGroupId, type AccountWallet } from "@metamask/account-api";
|
|
2
2
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { AccountId } from "@metamask/keyring-utils";
|
|
4
|
+
import type { AccountTreeControllerMessenger } from "src";
|
|
5
5
|
export declare const DEFAULT_ACCOUNT_GROUP_NAME: string;
|
|
6
6
|
/**
|
|
7
7
|
* Account group coming from the {@link AccountTreeController}.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export type AccountTreeGroup = {
|
|
10
|
+
/**
|
|
11
|
+
* Account IDs for that account group.
|
|
12
|
+
*/
|
|
13
|
+
getAccountIds(): AccountId[];
|
|
14
|
+
/**
|
|
15
|
+
* Gets the default name for that account group.
|
|
16
|
+
*/
|
|
17
|
+
getDefaultName(): string;
|
|
18
|
+
} & AccountGroup<InternalAccount>;
|
|
19
|
+
export declare class MutableAccountTreeGroup implements AccountTreeGroup {
|
|
10
20
|
#private;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
get id(): AccountGroupId;
|
|
17
|
-
get wallet(): AccountTreeWallet;
|
|
18
|
-
get name(): string;
|
|
19
|
-
getAccountIds(): InternalAccount['id'][];
|
|
20
|
-
getAccount(id: string): InternalAccount | undefined;
|
|
21
|
+
readonly id: AccountGroupId;
|
|
22
|
+
readonly wallet: AccountWallet<InternalAccount>;
|
|
23
|
+
readonly messenger: AccountTreeControllerMessenger;
|
|
24
|
+
constructor(messenger: AccountTreeControllerMessenger, wallet: AccountWallet<InternalAccount>, id: string);
|
|
25
|
+
getAccountIds(): AccountId[];
|
|
21
26
|
getAccounts(): InternalAccount[];
|
|
22
|
-
|
|
27
|
+
getAccount(id: AccountId): InternalAccount | undefined;
|
|
28
|
+
addAccount(account: InternalAccount): void;
|
|
29
|
+
getDefaultName(): string;
|
|
23
30
|
}
|
|
24
31
|
//# sourceMappingURL=AccountTreeGroup.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTreeGroup.d.cts","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"AccountTreeGroup.d.cts","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AACzD,OAAO,KAAK,EAAE,8BAA8B,EAAE,YAAY;AAE1D,eAAO,MAAM,0BAA0B,EAAE,MAAkB,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,aAAa,IAAI,SAAS,EAAE,CAAC;IAE7B;;OAEG;IACH,cAAc,IAAI,MAAM,CAAC;CAC1B,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAIlC,qBAAa,uBAAwB,YAAW,gBAAgB;;IAC9D,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAE5B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAEhD,QAAQ,CAAC,SAAS,EAAE,8BAA8B,CAAC;gBAKjD,SAAS,EAAE,8BAA8B,EACzC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,EACtC,EAAE,EAAE,MAAM;IASZ,aAAa,IAAI,SAAS,EAAE;IAI5B,WAAW,IAAI,eAAe,EAAE;IAkBhC,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS;IAItD,UAAU,CAAC,OAAO,EAAE,eAAe;IAInC,cAAc,IAAI,MAAM;CAGzB"}
|
|
@@ -1,24 +1,31 @@
|
|
|
1
|
-
import { type AccountGroup, type AccountGroupId } from "@metamask/account-api";
|
|
1
|
+
import { type AccountGroup, type AccountGroupId, type AccountWallet } from "@metamask/account-api";
|
|
2
2
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { AccountId } from "@metamask/keyring-utils";
|
|
4
|
+
import type { AccountTreeControllerMessenger } from "src";
|
|
5
5
|
export declare const DEFAULT_ACCOUNT_GROUP_NAME: string;
|
|
6
6
|
/**
|
|
7
7
|
* Account group coming from the {@link AccountTreeController}.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export type AccountTreeGroup = {
|
|
10
|
+
/**
|
|
11
|
+
* Account IDs for that account group.
|
|
12
|
+
*/
|
|
13
|
+
getAccountIds(): AccountId[];
|
|
14
|
+
/**
|
|
15
|
+
* Gets the default name for that account group.
|
|
16
|
+
*/
|
|
17
|
+
getDefaultName(): string;
|
|
18
|
+
} & AccountGroup<InternalAccount>;
|
|
19
|
+
export declare class MutableAccountTreeGroup implements AccountTreeGroup {
|
|
10
20
|
#private;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
get id(): AccountGroupId;
|
|
17
|
-
get wallet(): AccountTreeWallet;
|
|
18
|
-
get name(): string;
|
|
19
|
-
getAccountIds(): InternalAccount['id'][];
|
|
20
|
-
getAccount(id: string): InternalAccount | undefined;
|
|
21
|
+
readonly id: AccountGroupId;
|
|
22
|
+
readonly wallet: AccountWallet<InternalAccount>;
|
|
23
|
+
readonly messenger: AccountTreeControllerMessenger;
|
|
24
|
+
constructor(messenger: AccountTreeControllerMessenger, wallet: AccountWallet<InternalAccount>, id: string);
|
|
25
|
+
getAccountIds(): AccountId[];
|
|
21
26
|
getAccounts(): InternalAccount[];
|
|
22
|
-
|
|
27
|
+
getAccount(id: AccountId): InternalAccount | undefined;
|
|
28
|
+
addAccount(account: InternalAccount): void;
|
|
29
|
+
getDefaultName(): string;
|
|
23
30
|
}
|
|
24
31
|
//# sourceMappingURL=AccountTreeGroup.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTreeGroup.d.mts","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"AccountTreeGroup.d.mts","sourceRoot":"","sources":["../src/AccountTreeGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AACzD,OAAO,KAAK,EAAE,8BAA8B,EAAE,YAAY;AAE1D,eAAO,MAAM,0BAA0B,EAAE,MAAkB,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,aAAa,IAAI,SAAS,EAAE,CAAC;IAE7B;;OAEG;IACH,cAAc,IAAI,MAAM,CAAC;CAC1B,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAIlC,qBAAa,uBAAwB,YAAW,gBAAgB;;IAC9D,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAE5B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAEhD,QAAQ,CAAC,SAAS,EAAE,8BAA8B,CAAC;gBAKjD,SAAS,EAAE,8BAA8B,EACzC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,EACtC,EAAE,EAAE,MAAM;IASZ,aAAa,IAAI,SAAS,EAAE;IAI5B,WAAW,IAAI,eAAe,EAAE;IAkBhC,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS;IAItD,UAAU,CAAC,OAAO,EAAE,eAAe;IAInC,cAAc,IAAI,MAAM;CAGzB"}
|