@metamask-previews/account-tree-controller 5.0.1-preview-a0caca0c0 → 5.0.1-preview-17c76be24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/AccountTreeController-method-action-types.cjs +1 -1
  3. package/dist/AccountTreeController-method-action-types.cjs.map +1 -1
  4. package/dist/AccountTreeController-method-action-types.d.cts +1 -1
  5. package/dist/AccountTreeController-method-action-types.d.mts +1 -1
  6. package/dist/AccountTreeController-method-action-types.mjs +1 -1
  7. package/dist/AccountTreeController-method-action-types.mjs.map +1 -1
  8. package/dist/AccountTreeController.cjs +75 -47
  9. package/dist/AccountTreeController.cjs.map +1 -1
  10. package/dist/AccountTreeController.d.cts +1 -12
  11. package/dist/AccountTreeController.d.cts.map +1 -1
  12. package/dist/AccountTreeController.d.mts +1 -12
  13. package/dist/AccountTreeController.d.mts.map +1 -1
  14. package/dist/AccountTreeController.mjs +75 -47
  15. package/dist/AccountTreeController.mjs.map +1 -1
  16. package/dist/group.cjs.map +1 -1
  17. package/dist/group.d.cts +2 -0
  18. package/dist/group.d.cts.map +1 -1
  19. package/dist/group.d.mts +2 -0
  20. package/dist/group.d.mts.map +1 -1
  21. package/dist/group.mjs.map +1 -1
  22. package/dist/rules/entropy.cjs +1 -0
  23. package/dist/rules/entropy.cjs.map +1 -1
  24. package/dist/rules/entropy.d.cts.map +1 -1
  25. package/dist/rules/entropy.d.mts.map +1 -1
  26. package/dist/rules/entropy.mjs +1 -0
  27. package/dist/rules/entropy.mjs.map +1 -1
  28. package/dist/rules/keyring.cjs +1 -0
  29. package/dist/rules/keyring.cjs.map +1 -1
  30. package/dist/rules/keyring.d.cts.map +1 -1
  31. package/dist/rules/keyring.d.mts.map +1 -1
  32. package/dist/rules/keyring.mjs +1 -0
  33. package/dist/rules/keyring.mjs.map +1 -1
  34. package/dist/rules/snap.cjs +1 -0
  35. package/dist/rules/snap.cjs.map +1 -1
  36. package/dist/rules/snap.d.cts.map +1 -1
  37. package/dist/rules/snap.d.mts.map +1 -1
  38. package/dist/rules/snap.mjs +1 -0
  39. package/dist/rules/snap.mjs.map +1 -1
  40. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `lastSelected` (timestamp) to account group tree node metadata ([#8261](https://github.com/MetaMask/core/pull/8261))
13
+ - `group.metadata.lastSelected` is set to `Date.now()` whenever a group becomes the selected group, either via `setSelectedAccountGroup` or `AccountsController:selectedAccountChange`.
14
+ - The value is persisted in `accountGroupsMetadata` and restored on `init`/`reinit`.
15
+ - The value is not synchronize through backup and sync.
16
+ - Now consider `lastSelected` too when the controller needs to use the "default account group ID".
17
+
10
18
  ### Changed
11
19
 
12
20
  - **BREAKING**: Move `selectedAccountGroup` to top-level persisted state to prevent selected account group from reverting after app restart ([#8245](https://github.com/MetaMask/core/pull/8245))
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * This file is auto generated by `scripts/generate-method-action-types.ts`.
3
+ * This file is auto generated.
4
4
  * Do not edit manually.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1 @@
1
- {"version":3,"file":"AccountTreeController-method-action-types.cjs","sourceRoot":"","sources":["../src/AccountTreeController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AccountTreeController } from './AccountTreeController';\n\n/**\n * Gets the account wallet object from its ID.\n *\n * @param walletId - Account wallet ID.\n * @returns The account wallet object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountWalletObjectAction = {\n type: `AccountTreeController:getAccountWalletObject`;\n handler: AccountTreeController['getAccountWalletObject'];\n};\n\n/**\n * Gets all account wallet objects.\n *\n * @returns All account wallet objects.\n */\nexport type AccountTreeControllerGetAccountWalletObjectsAction = {\n type: `AccountTreeController:getAccountWalletObjects`;\n handler: AccountTreeController['getAccountWalletObjects'];\n};\n\n/**\n * Gets all underlying accounts from the currently selected account\n * group.\n *\n * It also support account selector, which allows to filter specific\n * accounts given some criterias (account type, address, scopes, etc...).\n *\n * @param selector - Optional account selector.\n * @returns Underlying accounts for the currently selected account (filtered\n * by the selector if provided).\n */\nexport type AccountTreeControllerGetAccountsFromSelectedAccountGroupAction = {\n type: `AccountTreeController:getAccountsFromSelectedAccountGroup`;\n handler: AccountTreeController['getAccountsFromSelectedAccountGroup'];\n};\n\n/**\n * Gets the account group object from its ID.\n *\n * @param groupId - Account group ID.\n * @returns The account group object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountGroupObjectAction = {\n type: `AccountTreeController:getAccountGroupObject`;\n handler: AccountTreeController['getAccountGroupObject'];\n};\n\n/**\n * Gets the account's context which contains its wallet ID, group ID, and sort order.\n *\n * @param accountId - Account ID.\n * @returns The account context if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountContextAction = {\n type: `AccountTreeController:getAccountContext`;\n handler: AccountTreeController['getAccountContext'];\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 */\nexport type AccountTreeControllerGetSelectedAccountGroupAction = {\n type: `AccountTreeController:getSelectedAccountGroup`;\n handler: AccountTreeController['getSelectedAccountGroup'];\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 */\nexport type AccountTreeControllerSetSelectedAccountGroupAction = {\n type: `AccountTreeController:setSelectedAccountGroup`;\n handler: AccountTreeController['setSelectedAccountGroup'];\n};\n\n/**\n * Sets a custom name for an account group.\n *\n * @param groupId - The account group ID.\n * @param name - The custom name to set.\n * @param autoHandleConflict - If true, automatically resolves name conflicts by adding a suffix. If false, throws on conflicts.\n * @throws If the account group ID is not found in the current tree.\n * @throws If the account group name already exists and autoHandleConflict is false.\n */\nexport type AccountTreeControllerSetAccountGroupNameAction = {\n type: `AccountTreeController:setAccountGroupName`;\n handler: AccountTreeController['setAccountGroupName'];\n};\n\n/**\n * Sets a custom name for an account wallet.\n *\n * @param walletId - The account wallet ID.\n * @param name - The custom name to set.\n * @throws If the account wallet ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountWalletNameAction = {\n type: `AccountTreeController:setAccountWalletName`;\n handler: AccountTreeController['setAccountWalletName'];\n};\n\n/**\n * Toggles the pinned state of an account group.\n *\n * @param groupId - The account group ID.\n * @param pinned - Whether the group should be pinned.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupPinnedAction = {\n type: `AccountTreeController:setAccountGroupPinned`;\n handler: AccountTreeController['setAccountGroupPinned'];\n};\n\n/**\n * Toggles the hidden state of an account group.\n *\n * @param groupId - The account group ID.\n * @param hidden - Whether the group should be hidden.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupHiddenAction = {\n type: `AccountTreeController:setAccountGroupHidden`;\n handler: AccountTreeController['setAccountGroupHidden'];\n};\n\n/**\n * Clears the controller state and resets to default values.\n * Also clears the backup and sync service state.\n */\nexport type AccountTreeControllerClearStateAction = {\n type: `AccountTreeController:clearState`;\n handler: AccountTreeController['clearState'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will perform a full sync, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If a full sync is already in progress, it will return the ongoing promise.\n *\n * @returns A promise that resolves when the sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAction = {\n type: `AccountTreeController:syncWithUserStorage`;\n handler: AccountTreeController['syncWithUserStorage'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will ensure at least one full sync is ran, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If the first ever full sync is already in progress, it will return the ongoing promise.\n * If the first ever full sync was previously completed, it will NOT start a new sync, and will resolve immediately.\n *\n * @returns A promise that resolves when the first ever full sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAtLeastOnceAction = {\n type: `AccountTreeController:syncWithUserStorageAtLeastOnce`;\n handler: AccountTreeController['syncWithUserStorageAtLeastOnce'];\n};\n\n/**\n * Union of all AccountTreeController action types.\n */\nexport type AccountTreeControllerMethodActions =\n | AccountTreeControllerGetAccountWalletObjectAction\n | AccountTreeControllerGetAccountWalletObjectsAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetAccountContextAction\n | AccountTreeControllerGetSelectedAccountGroupAction\n | AccountTreeControllerSetSelectedAccountGroupAction\n | AccountTreeControllerSetAccountGroupNameAction\n | AccountTreeControllerSetAccountWalletNameAction\n | AccountTreeControllerSetAccountGroupPinnedAction\n | AccountTreeControllerSetAccountGroupHiddenAction\n | AccountTreeControllerClearStateAction\n | AccountTreeControllerSyncWithUserStorageAction\n | AccountTreeControllerSyncWithUserStorageAtLeastOnceAction;\n"]}
1
+ {"version":3,"file":"AccountTreeController-method-action-types.cjs","sourceRoot":"","sources":["../src/AccountTreeController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AccountTreeController } from './AccountTreeController';\n\n/**\n * Gets the account wallet object from its ID.\n *\n * @param walletId - Account wallet ID.\n * @returns The account wallet object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountWalletObjectAction = {\n type: `AccountTreeController:getAccountWalletObject`;\n handler: AccountTreeController['getAccountWalletObject'];\n};\n\n/**\n * Gets all account wallet objects.\n *\n * @returns All account wallet objects.\n */\nexport type AccountTreeControllerGetAccountWalletObjectsAction = {\n type: `AccountTreeController:getAccountWalletObjects`;\n handler: AccountTreeController['getAccountWalletObjects'];\n};\n\n/**\n * Gets all underlying accounts from the currently selected account\n * group.\n *\n * It also support account selector, which allows to filter specific\n * accounts given some criterias (account type, address, scopes, etc...).\n *\n * @param selector - Optional account selector.\n * @returns Underlying accounts for the currently selected account (filtered\n * by the selector if provided).\n */\nexport type AccountTreeControllerGetAccountsFromSelectedAccountGroupAction = {\n type: `AccountTreeController:getAccountsFromSelectedAccountGroup`;\n handler: AccountTreeController['getAccountsFromSelectedAccountGroup'];\n};\n\n/**\n * Gets the account group object from its ID.\n *\n * @param groupId - Account group ID.\n * @returns The account group object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountGroupObjectAction = {\n type: `AccountTreeController:getAccountGroupObject`;\n handler: AccountTreeController['getAccountGroupObject'];\n};\n\n/**\n * Gets the account's context which contains its wallet ID, group ID, and sort order.\n *\n * @param accountId - Account ID.\n * @returns The account context if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountContextAction = {\n type: `AccountTreeController:getAccountContext`;\n handler: AccountTreeController['getAccountContext'];\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 */\nexport type AccountTreeControllerGetSelectedAccountGroupAction = {\n type: `AccountTreeController:getSelectedAccountGroup`;\n handler: AccountTreeController['getSelectedAccountGroup'];\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 */\nexport type AccountTreeControllerSetSelectedAccountGroupAction = {\n type: `AccountTreeController:setSelectedAccountGroup`;\n handler: AccountTreeController['setSelectedAccountGroup'];\n};\n\n/**\n * Sets a custom name for an account group.\n *\n * @param groupId - The account group ID.\n * @param name - The custom name to set.\n * @param autoHandleConflict - If true, automatically resolves name conflicts by adding a suffix. If false, throws on conflicts.\n * @throws If the account group ID is not found in the current tree.\n * @throws If the account group name already exists and autoHandleConflict is false.\n */\nexport type AccountTreeControllerSetAccountGroupNameAction = {\n type: `AccountTreeController:setAccountGroupName`;\n handler: AccountTreeController['setAccountGroupName'];\n};\n\n/**\n * Sets a custom name for an account wallet.\n *\n * @param walletId - The account wallet ID.\n * @param name - The custom name to set.\n * @throws If the account wallet ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountWalletNameAction = {\n type: `AccountTreeController:setAccountWalletName`;\n handler: AccountTreeController['setAccountWalletName'];\n};\n\n/**\n * Toggles the pinned state of an account group.\n *\n * @param groupId - The account group ID.\n * @param pinned - Whether the group should be pinned.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupPinnedAction = {\n type: `AccountTreeController:setAccountGroupPinned`;\n handler: AccountTreeController['setAccountGroupPinned'];\n};\n\n/**\n * Toggles the hidden state of an account group.\n *\n * @param groupId - The account group ID.\n * @param hidden - Whether the group should be hidden.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupHiddenAction = {\n type: `AccountTreeController:setAccountGroupHidden`;\n handler: AccountTreeController['setAccountGroupHidden'];\n};\n\n/**\n * Clears the controller state and resets to default values.\n * Also clears the backup and sync service state.\n */\nexport type AccountTreeControllerClearStateAction = {\n type: `AccountTreeController:clearState`;\n handler: AccountTreeController['clearState'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will perform a full sync, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If a full sync is already in progress, it will return the ongoing promise.\n *\n * @returns A promise that resolves when the sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAction = {\n type: `AccountTreeController:syncWithUserStorage`;\n handler: AccountTreeController['syncWithUserStorage'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will ensure at least one full sync is ran, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If the first ever full sync is already in progress, it will return the ongoing promise.\n * If the first ever full sync was previously completed, it will NOT start a new sync, and will resolve immediately.\n *\n * @returns A promise that resolves when the first ever full sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAtLeastOnceAction = {\n type: `AccountTreeController:syncWithUserStorageAtLeastOnce`;\n handler: AccountTreeController['syncWithUserStorageAtLeastOnce'];\n};\n\n/**\n * Union of all AccountTreeController action types.\n */\nexport type AccountTreeControllerMethodActions =\n | AccountTreeControllerGetAccountWalletObjectAction\n | AccountTreeControllerGetAccountWalletObjectsAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetAccountContextAction\n | AccountTreeControllerGetSelectedAccountGroupAction\n | AccountTreeControllerSetSelectedAccountGroupAction\n | AccountTreeControllerSetAccountGroupNameAction\n | AccountTreeControllerSetAccountWalletNameAction\n | AccountTreeControllerSetAccountGroupPinnedAction\n | AccountTreeControllerSetAccountGroupHiddenAction\n | AccountTreeControllerClearStateAction\n | AccountTreeControllerSyncWithUserStorageAction\n | AccountTreeControllerSyncWithUserStorageAtLeastOnceAction;\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file is auto generated by `scripts/generate-method-action-types.ts`.
2
+ * This file is auto generated.
3
3
  * Do not edit manually.
4
4
  */
5
5
  import type { AccountTreeController } from "./AccountTreeController.cjs";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file is auto generated by `scripts/generate-method-action-types.ts`.
2
+ * This file is auto generated.
3
3
  * Do not edit manually.
4
4
  */
5
5
  import type { AccountTreeController } from "./AccountTreeController.mjs";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file is auto generated by `scripts/generate-method-action-types.ts`.
2
+ * This file is auto generated.
3
3
  * Do not edit manually.
4
4
  */
5
5
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"AccountTreeController-method-action-types.mjs","sourceRoot":"","sources":["../src/AccountTreeController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AccountTreeController } from './AccountTreeController';\n\n/**\n * Gets the account wallet object from its ID.\n *\n * @param walletId - Account wallet ID.\n * @returns The account wallet object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountWalletObjectAction = {\n type: `AccountTreeController:getAccountWalletObject`;\n handler: AccountTreeController['getAccountWalletObject'];\n};\n\n/**\n * Gets all account wallet objects.\n *\n * @returns All account wallet objects.\n */\nexport type AccountTreeControllerGetAccountWalletObjectsAction = {\n type: `AccountTreeController:getAccountWalletObjects`;\n handler: AccountTreeController['getAccountWalletObjects'];\n};\n\n/**\n * Gets all underlying accounts from the currently selected account\n * group.\n *\n * It also support account selector, which allows to filter specific\n * accounts given some criterias (account type, address, scopes, etc...).\n *\n * @param selector - Optional account selector.\n * @returns Underlying accounts for the currently selected account (filtered\n * by the selector if provided).\n */\nexport type AccountTreeControllerGetAccountsFromSelectedAccountGroupAction = {\n type: `AccountTreeController:getAccountsFromSelectedAccountGroup`;\n handler: AccountTreeController['getAccountsFromSelectedAccountGroup'];\n};\n\n/**\n * Gets the account group object from its ID.\n *\n * @param groupId - Account group ID.\n * @returns The account group object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountGroupObjectAction = {\n type: `AccountTreeController:getAccountGroupObject`;\n handler: AccountTreeController['getAccountGroupObject'];\n};\n\n/**\n * Gets the account's context which contains its wallet ID, group ID, and sort order.\n *\n * @param accountId - Account ID.\n * @returns The account context if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountContextAction = {\n type: `AccountTreeController:getAccountContext`;\n handler: AccountTreeController['getAccountContext'];\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 */\nexport type AccountTreeControllerGetSelectedAccountGroupAction = {\n type: `AccountTreeController:getSelectedAccountGroup`;\n handler: AccountTreeController['getSelectedAccountGroup'];\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 */\nexport type AccountTreeControllerSetSelectedAccountGroupAction = {\n type: `AccountTreeController:setSelectedAccountGroup`;\n handler: AccountTreeController['setSelectedAccountGroup'];\n};\n\n/**\n * Sets a custom name for an account group.\n *\n * @param groupId - The account group ID.\n * @param name - The custom name to set.\n * @param autoHandleConflict - If true, automatically resolves name conflicts by adding a suffix. If false, throws on conflicts.\n * @throws If the account group ID is not found in the current tree.\n * @throws If the account group name already exists and autoHandleConflict is false.\n */\nexport type AccountTreeControllerSetAccountGroupNameAction = {\n type: `AccountTreeController:setAccountGroupName`;\n handler: AccountTreeController['setAccountGroupName'];\n};\n\n/**\n * Sets a custom name for an account wallet.\n *\n * @param walletId - The account wallet ID.\n * @param name - The custom name to set.\n * @throws If the account wallet ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountWalletNameAction = {\n type: `AccountTreeController:setAccountWalletName`;\n handler: AccountTreeController['setAccountWalletName'];\n};\n\n/**\n * Toggles the pinned state of an account group.\n *\n * @param groupId - The account group ID.\n * @param pinned - Whether the group should be pinned.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupPinnedAction = {\n type: `AccountTreeController:setAccountGroupPinned`;\n handler: AccountTreeController['setAccountGroupPinned'];\n};\n\n/**\n * Toggles the hidden state of an account group.\n *\n * @param groupId - The account group ID.\n * @param hidden - Whether the group should be hidden.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupHiddenAction = {\n type: `AccountTreeController:setAccountGroupHidden`;\n handler: AccountTreeController['setAccountGroupHidden'];\n};\n\n/**\n * Clears the controller state and resets to default values.\n * Also clears the backup and sync service state.\n */\nexport type AccountTreeControllerClearStateAction = {\n type: `AccountTreeController:clearState`;\n handler: AccountTreeController['clearState'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will perform a full sync, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If a full sync is already in progress, it will return the ongoing promise.\n *\n * @returns A promise that resolves when the sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAction = {\n type: `AccountTreeController:syncWithUserStorage`;\n handler: AccountTreeController['syncWithUserStorage'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will ensure at least one full sync is ran, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If the first ever full sync is already in progress, it will return the ongoing promise.\n * If the first ever full sync was previously completed, it will NOT start a new sync, and will resolve immediately.\n *\n * @returns A promise that resolves when the first ever full sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAtLeastOnceAction = {\n type: `AccountTreeController:syncWithUserStorageAtLeastOnce`;\n handler: AccountTreeController['syncWithUserStorageAtLeastOnce'];\n};\n\n/**\n * Union of all AccountTreeController action types.\n */\nexport type AccountTreeControllerMethodActions =\n | AccountTreeControllerGetAccountWalletObjectAction\n | AccountTreeControllerGetAccountWalletObjectsAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetAccountContextAction\n | AccountTreeControllerGetSelectedAccountGroupAction\n | AccountTreeControllerSetSelectedAccountGroupAction\n | AccountTreeControllerSetAccountGroupNameAction\n | AccountTreeControllerSetAccountWalletNameAction\n | AccountTreeControllerSetAccountGroupPinnedAction\n | AccountTreeControllerSetAccountGroupHiddenAction\n | AccountTreeControllerClearStateAction\n | AccountTreeControllerSyncWithUserStorageAction\n | AccountTreeControllerSyncWithUserStorageAtLeastOnceAction;\n"]}
1
+ {"version":3,"file":"AccountTreeController-method-action-types.mjs","sourceRoot":"","sources":["../src/AccountTreeController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AccountTreeController } from './AccountTreeController';\n\n/**\n * Gets the account wallet object from its ID.\n *\n * @param walletId - Account wallet ID.\n * @returns The account wallet object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountWalletObjectAction = {\n type: `AccountTreeController:getAccountWalletObject`;\n handler: AccountTreeController['getAccountWalletObject'];\n};\n\n/**\n * Gets all account wallet objects.\n *\n * @returns All account wallet objects.\n */\nexport type AccountTreeControllerGetAccountWalletObjectsAction = {\n type: `AccountTreeController:getAccountWalletObjects`;\n handler: AccountTreeController['getAccountWalletObjects'];\n};\n\n/**\n * Gets all underlying accounts from the currently selected account\n * group.\n *\n * It also support account selector, which allows to filter specific\n * accounts given some criterias (account type, address, scopes, etc...).\n *\n * @param selector - Optional account selector.\n * @returns Underlying accounts for the currently selected account (filtered\n * by the selector if provided).\n */\nexport type AccountTreeControllerGetAccountsFromSelectedAccountGroupAction = {\n type: `AccountTreeController:getAccountsFromSelectedAccountGroup`;\n handler: AccountTreeController['getAccountsFromSelectedAccountGroup'];\n};\n\n/**\n * Gets the account group object from its ID.\n *\n * @param groupId - Account group ID.\n * @returns The account group object if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountGroupObjectAction = {\n type: `AccountTreeController:getAccountGroupObject`;\n handler: AccountTreeController['getAccountGroupObject'];\n};\n\n/**\n * Gets the account's context which contains its wallet ID, group ID, and sort order.\n *\n * @param accountId - Account ID.\n * @returns The account context if found, undefined otherwise.\n */\nexport type AccountTreeControllerGetAccountContextAction = {\n type: `AccountTreeController:getAccountContext`;\n handler: AccountTreeController['getAccountContext'];\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 */\nexport type AccountTreeControllerGetSelectedAccountGroupAction = {\n type: `AccountTreeController:getSelectedAccountGroup`;\n handler: AccountTreeController['getSelectedAccountGroup'];\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 */\nexport type AccountTreeControllerSetSelectedAccountGroupAction = {\n type: `AccountTreeController:setSelectedAccountGroup`;\n handler: AccountTreeController['setSelectedAccountGroup'];\n};\n\n/**\n * Sets a custom name for an account group.\n *\n * @param groupId - The account group ID.\n * @param name - The custom name to set.\n * @param autoHandleConflict - If true, automatically resolves name conflicts by adding a suffix. If false, throws on conflicts.\n * @throws If the account group ID is not found in the current tree.\n * @throws If the account group name already exists and autoHandleConflict is false.\n */\nexport type AccountTreeControllerSetAccountGroupNameAction = {\n type: `AccountTreeController:setAccountGroupName`;\n handler: AccountTreeController['setAccountGroupName'];\n};\n\n/**\n * Sets a custom name for an account wallet.\n *\n * @param walletId - The account wallet ID.\n * @param name - The custom name to set.\n * @throws If the account wallet ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountWalletNameAction = {\n type: `AccountTreeController:setAccountWalletName`;\n handler: AccountTreeController['setAccountWalletName'];\n};\n\n/**\n * Toggles the pinned state of an account group.\n *\n * @param groupId - The account group ID.\n * @param pinned - Whether the group should be pinned.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupPinnedAction = {\n type: `AccountTreeController:setAccountGroupPinned`;\n handler: AccountTreeController['setAccountGroupPinned'];\n};\n\n/**\n * Toggles the hidden state of an account group.\n *\n * @param groupId - The account group ID.\n * @param hidden - Whether the group should be hidden.\n * @throws If the account group ID is not found in the current tree.\n */\nexport type AccountTreeControllerSetAccountGroupHiddenAction = {\n type: `AccountTreeController:setAccountGroupHidden`;\n handler: AccountTreeController['setAccountGroupHidden'];\n};\n\n/**\n * Clears the controller state and resets to default values.\n * Also clears the backup and sync service state.\n */\nexport type AccountTreeControllerClearStateAction = {\n type: `AccountTreeController:clearState`;\n handler: AccountTreeController['clearState'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will perform a full sync, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If a full sync is already in progress, it will return the ongoing promise.\n *\n * @returns A promise that resolves when the sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAction = {\n type: `AccountTreeController:syncWithUserStorage`;\n handler: AccountTreeController['syncWithUserStorage'];\n};\n\n/**\n * Bi-directionally syncs the account tree with user storage.\n * This will ensure at least one full sync is ran, including both pulling updates\n * from user storage and pushing local changes to user storage.\n * This also performs legacy account syncing if needed.\n *\n * IMPORTANT:\n * If the first ever full sync is already in progress, it will return the ongoing promise.\n * If the first ever full sync was previously completed, it will NOT start a new sync, and will resolve immediately.\n *\n * @returns A promise that resolves when the first ever full sync is complete.\n */\nexport type AccountTreeControllerSyncWithUserStorageAtLeastOnceAction = {\n type: `AccountTreeController:syncWithUserStorageAtLeastOnce`;\n handler: AccountTreeController['syncWithUserStorageAtLeastOnce'];\n};\n\n/**\n * Union of all AccountTreeController action types.\n */\nexport type AccountTreeControllerMethodActions =\n | AccountTreeControllerGetAccountWalletObjectAction\n | AccountTreeControllerGetAccountWalletObjectsAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetAccountContextAction\n | AccountTreeControllerGetSelectedAccountGroupAction\n | AccountTreeControllerSetSelectedAccountGroupAction\n | AccountTreeControllerSetAccountGroupNameAction\n | AccountTreeControllerSetAccountWalletNameAction\n | AccountTreeControllerSetAccountGroupPinnedAction\n | AccountTreeControllerSetAccountGroupHiddenAction\n | AccountTreeControllerClearStateAction\n | AccountTreeControllerSyncWithUserStorageAction\n | AccountTreeControllerSyncWithUserStorageAtLeastOnceAction;\n"]}
@@ -10,7 +10,7 @@ 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 _AccountTreeController_instances, _AccountTreeController_accountIdToContext, _AccountTreeController_groupIdToWalletId, _AccountTreeController_backupAndSyncService, _AccountTreeController_rules, _AccountTreeController_trace, _AccountTreeController_backupAndSyncConfig, _AccountTreeController_accountOrderCallbacks, _AccountTreeController_initialized, _AccountTreeController_getEntropyRule, _AccountTreeController_getSnapRule, _AccountTreeController_getKeyringRule, _AccountTreeController_applyAccountWalletMetadata, _AccountTreeController_getRuleForWallet, _AccountTreeController_getComputedAccountGroupName, _AccountTreeController_getDefaultAccountGroupName, _AccountTreeController_applyAccountGroupMetadata, _AccountTreeController_handleAccountsAdded, _AccountTreeController_handleAccountsRemoved, _AccountTreeController_pruneEmptyGroupAndWallet, _AccountTreeController_insert, _AccountTreeController_listAccounts, _AccountTreeController_assertAccountGroupExists, _AccountTreeController_assertAccountWalletExists, _AccountTreeController_assertAccountGroupNameIsUnique, _AccountTreeController_getDefaultSelectedAccountGroup, _AccountTreeController_handleSelectedAccountChange, _AccountTreeController_handleMultichainAccountWalletStatusChange, _AccountTreeController_getAccountGroup, _AccountTreeController_getDefaultAccountFromAccountGroupId, _AccountTreeController_getDefaultAccountGroupId, _AccountTreeController_resolveNameConflict, _AccountTreeController_createBackupAndSyncContext;
13
+ var _AccountTreeController_instances, _AccountTreeController_accountIdToContext, _AccountTreeController_groupIdToWalletId, _AccountTreeController_backupAndSyncService, _AccountTreeController_rules, _AccountTreeController_trace, _AccountTreeController_backupAndSyncConfig, _AccountTreeController_accountOrderCallbacks, _AccountTreeController_initialized, _AccountTreeController_getEntropyRule, _AccountTreeController_getSnapRule, _AccountTreeController_getKeyringRule, _AccountTreeController_applyAccountWalletMetadata, _AccountTreeController_getRuleForWallet, _AccountTreeController_getComputedAccountGroupName, _AccountTreeController_getDefaultAccountGroupName, _AccountTreeController_applyAccountGroupMetadata, _AccountTreeController_handleAccountsAdded, _AccountTreeController_handleAccountsRemoved, _AccountTreeController_pruneEmptyGroupAndWallet, _AccountTreeController_insert, _AccountTreeController_listAccounts, _AccountTreeController_assertAccountGroupExists, _AccountTreeController_assertAccountWalletExists, _AccountTreeController_assertAccountGroupNameIsUnique, _AccountTreeController_setSelectedAccountGroup, _AccountTreeController_getDefaultSelectedAccountGroup, _AccountTreeController_handleSelectedAccountChange, _AccountTreeController_handleMultichainAccountWalletStatusChange, _AccountTreeController_getAccountGroup, _AccountTreeController_getDefaultAccountFromAccountGroupId, _AccountTreeController_getDefaultAccountGroupId, _AccountTreeController_hasEvmAccount, _AccountTreeController_resolveNameConflict, _AccountTreeController_createBackupAndSyncContext;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.AccountTreeController = exports.getDefaultAccountTreeControllerState = exports.controllerName = void 0;
16
16
  const account_api_1 = require("@metamask/account-api");
@@ -248,8 +248,7 @@ class AccountTreeController extends base_controller_1.BaseController {
248
248
  previousSelectedAccountGroup === '') {
249
249
  // No group is selected yet OR group no longer exists, re-sync with the
250
250
  // AccountsController.
251
- state.selectedAccountGroup =
252
- __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultSelectedAccountGroup).call(this, wallets);
251
+ state.selectedAccountGroup = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultSelectedAccountGroup).call(this, state.accountTree.wallets);
253
252
  }
254
253
  });
255
254
  // We still compare the previous and new value, the previous one could have been
@@ -365,25 +364,7 @@ class AccountTreeController extends base_controller_1.BaseController {
365
364
  * @param groupId - The account group ID to select.
366
365
  */
367
366
  setSelectedAccountGroup(groupId) {
368
- const previousSelectedAccountGroup = this.state.selectedAccountGroup;
369
- // Idempotent check - if the same group is already selected, do nothing
370
- if (previousSelectedAccountGroup === groupId) {
371
- return;
372
- }
373
- // Find the first account in this group to select
374
- const accountToSelect = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultAccountFromAccountGroupId).call(this, groupId);
375
- if (!accountToSelect) {
376
- throw new Error(`No accounts found in group: ${groupId}`);
377
- }
378
- // Update our state first
379
- this.update((state) => {
380
- state.selectedAccountGroup = groupId;
381
- });
382
- (0, logger_1.projectLogger)(`Selected group is now: [${this.state.selectedAccountGroup}]`);
383
- this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup);
384
- // Update AccountsController - this will trigger selectedAccountChange event,
385
- // but our handler is idempotent so it won't cause infinite loop
386
- this.messenger.call('AccountsController:setSelectedAccount', accountToSelect);
367
+ __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_setSelectedAccountGroup).call(this, groupId);
387
368
  }
388
369
  /**
389
370
  * Sets a custom name for an account group.
@@ -755,6 +736,16 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
755
736
  // If any accounts was previously hidden, then we consider the group to be hidden as well.
756
737
  group.metadata.hidden = isHidden;
757
738
  }
739
+ // Apply persisted lastSelected (plain number, not synced).
740
+ if (persistedGroupMetadata?.lastSelected !== undefined &&
741
+ persistedGroupMetadata.lastSelected >= 0) {
742
+ group.metadata.lastSelected = persistedGroupMetadata.lastSelected;
743
+ }
744
+ else {
745
+ // Automatiacally inject default value.
746
+ state.accountGroupsMetadata[groupId].lastSelected = 0;
747
+ group.metadata.lastSelected = 0;
748
+ }
758
749
  }, _AccountTreeController_handleAccountsAdded = function _AccountTreeController_handleAccountsAdded(accounts) {
759
750
  // We wait for the first `init` to be called to actually build up the tree and
760
751
  // mutate it. We expect the caller to first update the `AccountsController` state
@@ -878,7 +869,7 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
878
869
  accounts: [id],
879
870
  metadata: {
880
871
  name: '',
881
- ...{ pinned: false, hidden: false }, // Default UI states
872
+ ...{ pinned: false, hidden: false, lastSelected: 0 }, // Default UI states
882
873
  ...result.group.metadata, // Allow rules to override defaults
883
874
  },
884
875
  // We do need to type-cast since we're not narrowing `result` with
@@ -933,6 +924,41 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
933
924
  if (!(0, group_1.isAccountGroupNameUnique)(this.state, groupId, name)) {
934
925
  throw new Error('Account group name already exists');
935
926
  }
927
+ }, _AccountTreeController_setSelectedAccountGroup = function _AccountTreeController_setSelectedAccountGroup(groupId, forwardSelectedAccount = true) {
928
+ const previousSelectedAccountGroup = this.state.selectedAccountGroup;
929
+ // Idempotent check - if the same group is already selected, do nothing
930
+ if (previousSelectedAccountGroup === groupId) {
931
+ return;
932
+ }
933
+ // Find the first account in this group to select
934
+ const accountToSelect = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultAccountFromAccountGroupId).call(this, groupId);
935
+ if (!accountToSelect) {
936
+ throw new Error(`No accounts found in group: ${groupId}`);
937
+ }
938
+ this.update((state) => {
939
+ // Update our selected account group first.
940
+ state.selectedAccountGroup = groupId;
941
+ // Then update its associated metadata (lastSelected timestamp) to keep
942
+ // track of the most recently selected groups.
943
+ const now = Date.now();
944
+ /* istanbul ignore next */
945
+ if (!state.accountGroupsMetadata[groupId]) {
946
+ state.accountGroupsMetadata[groupId] = {};
947
+ }
948
+ state.accountGroupsMetadata[groupId].lastSelected = now;
949
+ const walletId = __classPrivateFieldGet(this, _AccountTreeController_groupIdToWalletId, "f").get(groupId);
950
+ if (walletId) {
951
+ state.accountTree.wallets[walletId].groups[groupId].metadata.lastSelected = now;
952
+ }
953
+ });
954
+ (0, logger_1.projectLogger)(`Selected group is now: [${this.state.selectedAccountGroup}]`);
955
+ this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup);
956
+ if (forwardSelectedAccount) {
957
+ // Update AccountsController - this will trigger selectedAccountChange event,
958
+ // but our handler is idempotent so it won't cause infinite loop
959
+ this.messenger.call('AccountsController:setSelectedAccount', accountToSelect);
960
+ (0, logger_1.projectLogger)(`Selected account is now: ${accountToSelect}`);
961
+ }
936
962
  }, _AccountTreeController_getDefaultSelectedAccountGroup = function _AccountTreeController_getDefaultSelectedAccountGroup(wallets) {
937
963
  const selectedAccount = this.messenger.call('AccountsController:getSelectedMultichainAccount');
938
964
  if (selectedAccount?.id) {
@@ -951,16 +977,9 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
951
977
  return;
952
978
  }
953
979
  const { groupId } = accountMapping;
954
- const previousSelectedAccountGroup = this.state.selectedAccountGroup;
955
- // Idempotent check - if the same group is already selected, do nothing
956
- if (previousSelectedAccountGroup === groupId) {
957
- return;
958
- }
959
- // Update selectedAccountGroup to match the selected account
960
- this.update((state) => {
961
- state.selectedAccountGroup = groupId;
962
- });
963
- this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup);
980
+ // Avoid infinite loop since this method is triggered by selected account change.
981
+ const forwardSelectedAccount = false;
982
+ __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_setSelectedAccountGroup).call(this, groupId, forwardSelectedAccount);
964
983
  }, _AccountTreeController_handleMultichainAccountWalletStatusChange = function _AccountTreeController_handleMultichainAccountWalletStatusChange(walletId, walletStatus) {
965
984
  this.update((state) => {
966
985
  const wallet = state.accountTree.wallets[walletId];
@@ -990,26 +1009,35 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
990
1009
  }
991
1010
  return undefined;
992
1011
  }, _AccountTreeController_getDefaultAccountGroupId = function _AccountTreeController_getDefaultAccountGroupId(wallets) {
993
- let candidate = '';
1012
+ let candidate;
994
1013
  for (const wallet of Object.values(wallets)) {
995
1014
  for (const group of Object.values(wallet.groups)) {
996
- // We only update the candidate with the first non-empty group, but still
997
- // try to find a group that contains an EVM account (the `candidate` is
998
- // our fallback).
999
- if (candidate === '' && group.accounts.length > 0) {
1000
- candidate = group.id;
1015
+ if (group.accounts.length === 0) {
1016
+ continue;
1001
1017
  }
1002
- for (const id of group.accounts) {
1003
- const account = this.messenger.call('AccountsController:getAccount', id);
1004
- if (account && (0, keyring_api_1.isEvmAccountType)(account.type)) {
1005
- // EVM accounts have a higher priority, so if we find any, we just
1006
- // use that group!
1007
- return group.id;
1008
- }
1018
+ if (!candidate) {
1019
+ candidate = group;
1020
+ continue;
1021
+ }
1022
+ if (group.metadata.lastSelected > candidate.metadata.lastSelected) {
1023
+ candidate = group;
1009
1024
  }
1025
+ else if (group.metadata.lastSelected === candidate.metadata.lastSelected &&
1026
+ __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasEvmAccount).call(this, group) &&
1027
+ !__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasEvmAccount).call(this, candidate)) {
1028
+ candidate = group;
1029
+ }
1030
+ }
1031
+ }
1032
+ return candidate?.id ?? '';
1033
+ }, _AccountTreeController_hasEvmAccount = function _AccountTreeController_hasEvmAccount(group) {
1034
+ for (const id of group.accounts) {
1035
+ const account = this.messenger.call('AccountsController:getAccount', id);
1036
+ if (account && (0, keyring_api_1.isEvmAccountType)(account.type)) {
1037
+ return true;
1010
1038
  }
1011
1039
  }
1012
- return candidate;
1040
+ return false;
1013
1041
  }, _AccountTreeController_resolveNameConflict = function _AccountTreeController_resolveNameConflict(wallet, groupId, name) {
1014
1042
  let suffix = 2;
1015
1043
  let candidateName = `${name} (${suffix})`;