@metamask/profile-sync-controller 19.0.0 → 21.0.0

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 (186) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/dist/controllers/authentication/AuthenticationController.cjs +21 -9
  3. package/dist/controllers/authentication/AuthenticationController.cjs.map +1 -1
  4. package/dist/controllers/authentication/AuthenticationController.d.cts +10 -3
  5. package/dist/controllers/authentication/AuthenticationController.d.cts.map +1 -1
  6. package/dist/controllers/authentication/AuthenticationController.d.mts +10 -3
  7. package/dist/controllers/authentication/AuthenticationController.d.mts.map +1 -1
  8. package/dist/controllers/authentication/AuthenticationController.mjs +21 -9
  9. package/dist/controllers/authentication/AuthenticationController.mjs.map +1 -1
  10. package/dist/controllers/user-storage/UserStorageController.cjs +24 -47
  11. package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
  12. package/dist/controllers/user-storage/UserStorageController.d.cts +16 -49
  13. package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
  14. package/dist/controllers/user-storage/UserStorageController.d.mts +16 -49
  15. package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
  16. package/dist/controllers/user-storage/UserStorageController.mjs +24 -47
  17. package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
  18. package/dist/controllers/user-storage/account-syncing/controller-integration.cjs +185 -166
  19. package/dist/controllers/user-storage/account-syncing/controller-integration.cjs.map +1 -1
  20. package/dist/controllers/user-storage/account-syncing/controller-integration.d.cts +3 -0
  21. package/dist/controllers/user-storage/account-syncing/controller-integration.d.cts.map +1 -1
  22. package/dist/controllers/user-storage/account-syncing/controller-integration.d.mts +3 -0
  23. package/dist/controllers/user-storage/account-syncing/controller-integration.d.mts.map +1 -1
  24. package/dist/controllers/user-storage/account-syncing/controller-integration.mjs +185 -166
  25. package/dist/controllers/user-storage/account-syncing/controller-integration.mjs.map +1 -1
  26. package/dist/controllers/user-storage/account-syncing/types.cjs.map +1 -1
  27. package/dist/controllers/user-storage/account-syncing/types.d.cts +2 -0
  28. package/dist/controllers/user-storage/account-syncing/types.d.cts.map +1 -1
  29. package/dist/controllers/user-storage/account-syncing/types.d.mts +2 -0
  30. package/dist/controllers/user-storage/account-syncing/types.d.mts.map +1 -1
  31. package/dist/controllers/user-storage/account-syncing/types.mjs.map +1 -1
  32. package/dist/controllers/user-storage/constants.cjs +14 -1
  33. package/dist/controllers/user-storage/constants.cjs.map +1 -1
  34. package/dist/controllers/user-storage/constants.d.cts +11 -0
  35. package/dist/controllers/user-storage/constants.d.cts.map +1 -1
  36. package/dist/controllers/user-storage/constants.d.mts +11 -0
  37. package/dist/controllers/user-storage/constants.d.mts.map +1 -1
  38. package/dist/controllers/user-storage/constants.mjs +13 -0
  39. package/dist/controllers/user-storage/constants.mjs.map +1 -1
  40. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs +227 -162
  41. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs.map +1 -1
  42. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts +3 -0
  43. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts.map +1 -1
  44. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts +3 -0
  45. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts.map +1 -1
  46. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs +227 -162
  47. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs.map +1 -1
  48. package/dist/controllers/user-storage/contact-syncing/types.cjs.map +1 -1
  49. package/dist/controllers/user-storage/contact-syncing/types.d.cts +2 -0
  50. package/dist/controllers/user-storage/contact-syncing/types.d.cts.map +1 -1
  51. package/dist/controllers/user-storage/contact-syncing/types.d.mts +2 -0
  52. package/dist/controllers/user-storage/contact-syncing/types.d.mts.map +1 -1
  53. package/dist/controllers/user-storage/contact-syncing/types.mjs.map +1 -1
  54. package/dist/controllers/user-storage/mocks/mockResponses.cjs +1 -1
  55. package/dist/controllers/user-storage/mocks/mockResponses.cjs.map +1 -1
  56. package/dist/controllers/user-storage/mocks/mockResponses.d.cts +9 -9
  57. package/dist/controllers/user-storage/mocks/mockResponses.d.cts.map +1 -1
  58. package/dist/controllers/user-storage/mocks/mockResponses.d.mts +9 -9
  59. package/dist/controllers/user-storage/mocks/mockResponses.d.mts.map +1 -1
  60. package/dist/controllers/user-storage/mocks/mockResponses.mjs +1 -1
  61. package/dist/controllers/user-storage/mocks/mockResponses.mjs.map +1 -1
  62. package/dist/controllers/user-storage/types.cjs.map +1 -1
  63. package/dist/controllers/user-storage/types.d.cts +3 -3
  64. package/dist/controllers/user-storage/types.d.cts.map +1 -1
  65. package/dist/controllers/user-storage/types.d.mts +3 -3
  66. package/dist/controllers/user-storage/types.d.mts.map +1 -1
  67. package/dist/controllers/user-storage/types.mjs.map +1 -1
  68. package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs +4 -0
  69. package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs.map +1 -1
  70. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.cts +2 -1
  71. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.cts.map +1 -1
  72. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.mts +2 -1
  73. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.mts.map +1 -1
  74. package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs +5 -1
  75. package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs.map +1 -1
  76. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs +4 -0
  77. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs.map +1 -1
  78. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts +2 -1
  79. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts.map +1 -1
  80. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts +2 -1
  81. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts.map +1 -1
  82. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs +5 -1
  83. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs.map +1 -1
  84. package/dist/sdk/authentication-jwt-bearer/services.cjs +33 -1
  85. package/dist/sdk/authentication-jwt-bearer/services.cjs.map +1 -1
  86. package/dist/sdk/authentication-jwt-bearer/services.d.cts +10 -1
  87. package/dist/sdk/authentication-jwt-bearer/services.d.cts.map +1 -1
  88. package/dist/sdk/authentication-jwt-bearer/services.d.mts +10 -1
  89. package/dist/sdk/authentication-jwt-bearer/services.d.mts.map +1 -1
  90. package/dist/sdk/authentication-jwt-bearer/services.mjs +30 -0
  91. package/dist/sdk/authentication-jwt-bearer/services.mjs.map +1 -1
  92. package/dist/sdk/authentication-jwt-bearer/types.cjs.map +1 -1
  93. package/dist/sdk/authentication-jwt-bearer/types.d.cts +11 -0
  94. package/dist/sdk/authentication-jwt-bearer/types.d.cts.map +1 -1
  95. package/dist/sdk/authentication-jwt-bearer/types.d.mts +11 -0
  96. package/dist/sdk/authentication-jwt-bearer/types.d.mts.map +1 -1
  97. package/dist/sdk/authentication-jwt-bearer/types.mjs.map +1 -1
  98. package/dist/sdk/authentication.cjs +3 -0
  99. package/dist/sdk/authentication.cjs.map +1 -1
  100. package/dist/sdk/authentication.d.cts +2 -1
  101. package/dist/sdk/authentication.d.cts.map +1 -1
  102. package/dist/sdk/authentication.d.mts +2 -1
  103. package/dist/sdk/authentication.d.mts.map +1 -1
  104. package/dist/sdk/authentication.mjs +3 -0
  105. package/dist/sdk/authentication.mjs.map +1 -1
  106. package/dist/sdk/mocks/auth.cjs +22 -1
  107. package/dist/sdk/mocks/auth.cjs.map +1 -1
  108. package/dist/sdk/mocks/auth.d.cts +13 -0
  109. package/dist/sdk/mocks/auth.d.cts.map +1 -1
  110. package/dist/sdk/mocks/auth.d.mts +13 -0
  111. package/dist/sdk/mocks/auth.d.mts.map +1 -1
  112. package/dist/sdk/mocks/auth.mjs +23 -2
  113. package/dist/sdk/mocks/auth.mjs.map +1 -1
  114. package/dist/sdk/user-storage.cjs +3 -9
  115. package/dist/sdk/user-storage.cjs.map +1 -1
  116. package/dist/sdk/user-storage.d.cts +0 -1
  117. package/dist/sdk/user-storage.d.cts.map +1 -1
  118. package/dist/sdk/user-storage.d.mts +0 -1
  119. package/dist/sdk/user-storage.d.mts.map +1 -1
  120. package/dist/sdk/user-storage.mjs +3 -9
  121. package/dist/sdk/user-storage.mjs.map +1 -1
  122. package/dist/shared/storage-schema.cjs +9 -32
  123. package/dist/shared/storage-schema.cjs.map +1 -1
  124. package/dist/shared/storage-schema.d.cts +10 -42
  125. package/dist/shared/storage-schema.d.cts.map +1 -1
  126. package/dist/shared/storage-schema.d.mts +10 -42
  127. package/dist/shared/storage-schema.d.mts.map +1 -1
  128. package/dist/shared/storage-schema.mjs +8 -31
  129. package/dist/shared/storage-schema.mjs.map +1 -1
  130. package/package.json +6 -8
  131. package/dist/controllers/user-storage/network-syncing/add-network-utils.cjs +0 -36
  132. package/dist/controllers/user-storage/network-syncing/add-network-utils.cjs.map +0 -1
  133. package/dist/controllers/user-storage/network-syncing/add-network-utils.d.cts +0 -22
  134. package/dist/controllers/user-storage/network-syncing/add-network-utils.d.cts.map +0 -1
  135. package/dist/controllers/user-storage/network-syncing/add-network-utils.d.mts +0 -22
  136. package/dist/controllers/user-storage/network-syncing/add-network-utils.d.mts.map +0 -1
  137. package/dist/controllers/user-storage/network-syncing/add-network-utils.mjs +0 -31
  138. package/dist/controllers/user-storage/network-syncing/add-network-utils.mjs.map +0 -1
  139. package/dist/controllers/user-storage/network-syncing/controller-integration.cjs +0 -193
  140. package/dist/controllers/user-storage/network-syncing/controller-integration.cjs.map +0 -1
  141. package/dist/controllers/user-storage/network-syncing/controller-integration.d.cts +0 -57
  142. package/dist/controllers/user-storage/network-syncing/controller-integration.d.cts.map +0 -1
  143. package/dist/controllers/user-storage/network-syncing/controller-integration.d.mts +0 -57
  144. package/dist/controllers/user-storage/network-syncing/controller-integration.d.mts.map +0 -1
  145. package/dist/controllers/user-storage/network-syncing/controller-integration.mjs +0 -191
  146. package/dist/controllers/user-storage/network-syncing/controller-integration.mjs.map +0 -1
  147. package/dist/controllers/user-storage/network-syncing/services.cjs +0 -79
  148. package/dist/controllers/user-storage/network-syncing/services.cjs.map +0 -1
  149. package/dist/controllers/user-storage/network-syncing/services.d.cts +0 -34
  150. package/dist/controllers/user-storage/network-syncing/services.d.cts.map +0 -1
  151. package/dist/controllers/user-storage/network-syncing/services.d.mts +0 -34
  152. package/dist/controllers/user-storage/network-syncing/services.d.mts.map +0 -1
  153. package/dist/controllers/user-storage/network-syncing/services.mjs +0 -73
  154. package/dist/controllers/user-storage/network-syncing/services.mjs.map +0 -1
  155. package/dist/controllers/user-storage/network-syncing/sync-all.cjs +0 -153
  156. package/dist/controllers/user-storage/network-syncing/sync-all.cjs.map +0 -1
  157. package/dist/controllers/user-storage/network-syncing/sync-all.d.cts +0 -32
  158. package/dist/controllers/user-storage/network-syncing/sync-all.d.cts.map +0 -1
  159. package/dist/controllers/user-storage/network-syncing/sync-all.d.mts +0 -32
  160. package/dist/controllers/user-storage/network-syncing/sync-all.d.mts.map +0 -1
  161. package/dist/controllers/user-storage/network-syncing/sync-all.mjs +0 -145
  162. package/dist/controllers/user-storage/network-syncing/sync-all.mjs.map +0 -1
  163. package/dist/controllers/user-storage/network-syncing/sync-mutations.cjs +0 -28
  164. package/dist/controllers/user-storage/network-syncing/sync-mutations.cjs.map +0 -1
  165. package/dist/controllers/user-storage/network-syncing/sync-mutations.d.cts +0 -17
  166. package/dist/controllers/user-storage/network-syncing/sync-mutations.d.cts.map +0 -1
  167. package/dist/controllers/user-storage/network-syncing/sync-mutations.d.mts +0 -17
  168. package/dist/controllers/user-storage/network-syncing/sync-mutations.d.mts.map +0 -1
  169. package/dist/controllers/user-storage/network-syncing/sync-mutations.mjs +0 -22
  170. package/dist/controllers/user-storage/network-syncing/sync-mutations.mjs.map +0 -1
  171. package/dist/controllers/user-storage/network-syncing/types.cjs +0 -16
  172. package/dist/controllers/user-storage/network-syncing/types.cjs.map +0 -1
  173. package/dist/controllers/user-storage/network-syncing/types.d.cts +0 -15
  174. package/dist/controllers/user-storage/network-syncing/types.d.cts.map +0 -1
  175. package/dist/controllers/user-storage/network-syncing/types.d.mts +0 -15
  176. package/dist/controllers/user-storage/network-syncing/types.d.mts.map +0 -1
  177. package/dist/controllers/user-storage/network-syncing/types.mjs +0 -11
  178. package/dist/controllers/user-storage/network-syncing/types.mjs.map +0 -1
  179. package/dist/controllers/user-storage/network-syncing/update-network-utils.cjs +0 -129
  180. package/dist/controllers/user-storage/network-syncing/update-network-utils.cjs.map +0 -1
  181. package/dist/controllers/user-storage/network-syncing/update-network-utils.d.cts +0 -59
  182. package/dist/controllers/user-storage/network-syncing/update-network-utils.d.cts.map +0 -1
  183. package/dist/controllers/user-storage/network-syncing/update-network-utils.d.mts +0 -59
  184. package/dist/controllers/user-storage/network-syncing/update-network-utils.d.mts.map +0 -1
  185. package/dist/controllers/user-storage/network-syncing/update-network-utils.mjs +0 -122
  186. package/dist/controllers/user-storage/network-syncing/update-network-utils.mjs.map +0 -1
@@ -2,32 +2,41 @@ import { KeyringTypes } from "@metamask/keyring-controller";
2
2
  import { canPerformAccountSyncing, getInternalAccountsList, getUserStorageAccountsList } from "./sync-utils.mjs";
3
3
  import { isNameDefaultAccountName, mapInternalAccountToUserStorageAccount } from "./utils.mjs";
4
4
  import { USER_STORAGE_FEATURE_NAMES } from "../../../shared/storage-schema.mjs";
5
+ import { TraceName } from "../constants.mjs";
5
6
  /**
6
7
  * Saves an individual internal account to the user storage.
7
8
  *
8
9
  * @param internalAccount - The internal account to save
9
10
  * @param options - parameters used for saving the internal account
11
+ * @returns Promise that resolves when the account is saved
10
12
  */
11
13
  export async function saveInternalAccountToUserStorage(internalAccount, options) {
12
- const { getUserStorageControllerInstance } = options;
13
- if (!canPerformAccountSyncing(options) ||
14
- internalAccount.metadata.keyring.type !== String(KeyringTypes.hd) // sync only EVM accounts until we support multichain accounts
15
- ) {
16
- return;
17
- }
18
- // properties of `options` are (wrongly?) typed as `Json` and eslint crashes if we try to interpret it as such and call a `?.toString()` on it.
19
- // but we know this is a string?, so we can safely cast it
20
- const entropySourceId = internalAccount.options.entropySource;
21
- try {
22
- // Map the internal account to the user storage account schema
23
- const mappedAccount = mapInternalAccountToUserStorageAccount(internalAccount);
24
- await getUserStorageControllerInstance().performSetStorage(`${USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`, JSON.stringify(mappedAccount), entropySourceId);
25
- }
26
- catch (e) {
27
- // istanbul ignore next
28
- const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
29
- throw new Error(`UserStorageController - failed to save account to user storage - ${errorMessage}`);
14
+ const { trace } = options;
15
+ const saveAccount = async () => {
16
+ const { getUserStorageControllerInstance } = options;
17
+ if (!canPerformAccountSyncing(options) ||
18
+ internalAccount.metadata.keyring.type !== String(KeyringTypes.hd) // sync only EVM accounts until we support multichain accounts
19
+ ) {
20
+ return;
21
+ }
22
+ // properties of `options` are (wrongly?) typed as `Json` and eslint crashes if we try to interpret it as such and call a `?.toString()` on it.
23
+ // but we know this is a string?, so we can safely cast it
24
+ const entropySourceId = internalAccount.options?.entropySource;
25
+ try {
26
+ // Map the internal account to the user storage account schema
27
+ const mappedAccount = mapInternalAccountToUserStorageAccount(internalAccount);
28
+ await getUserStorageControllerInstance().performSetStorage(`${USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`, JSON.stringify(mappedAccount), entropySourceId);
29
+ }
30
+ catch (e) {
31
+ // istanbul ignore next
32
+ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
33
+ throw new Error(`UserStorageController - failed to save account to user storage - ${errorMessage}`);
34
+ }
35
+ };
36
+ if (trace) {
37
+ return await trace({ name: TraceName.AccountSyncSaveIndividual }, saveAccount);
30
38
  }
39
+ return await saveAccount();
31
40
  }
32
41
  /**
33
42
  * Saves the list of internal accounts to the user storage.
@@ -35,6 +44,7 @@ export async function saveInternalAccountToUserStorage(internalAccount, options)
35
44
  * @param options - parameters used for saving the list of internal accounts
36
45
  * @param entropySourceId - The entropy source ID used to derive the key,
37
46
  * when multiple sources are available (Multi-SRP).
47
+ * @returns Promise that resolves when all accounts are saved
38
48
  */
39
49
  export async function saveInternalAccountsListToUserStorage(options, entropySourceId) {
40
50
  const { getUserStorageControllerInstance } = options;
@@ -56,173 +66,182 @@ export async function saveInternalAccountsListToUserStorage(options, entropySour
56
66
  * @param config - parameters used for syncing the internal accounts list with the user storage accounts list
57
67
  * @param options - parameters used for syncing the internal accounts list with the user storage accounts list
58
68
  * @param entropySourceId - The entropy source ID used to derive the key,
69
+ * @returns Promise that resolves when synchronization is complete
59
70
  */
60
71
  export async function syncInternalAccountsWithUserStorage(config, options, entropySourceId) {
61
- if (!canPerformAccountSyncing(options)) {
62
- return;
63
- }
64
- const { maxNumberOfAccountsToAdd = Infinity, onAccountAdded, onAccountNameUpdated, onAccountSyncErroneousSituation, } = config;
65
- const { getMessenger, getUserStorageControllerInstance } = options;
66
- try {
67
- await getUserStorageControllerInstance().setIsAccountSyncingInProgress(true);
68
- const userStorageAccountsList = await getUserStorageAccountsList(options, entropySourceId);
69
- if (!userStorageAccountsList || !userStorageAccountsList.length) {
70
- await saveInternalAccountsListToUserStorage(options, entropySourceId);
72
+ const { trace } = options;
73
+ const performAccountSync = async () => {
74
+ if (!canPerformAccountSyncing(options)) {
71
75
  return;
72
76
  }
73
- // Keep a record if erroneous situations are found during the sync
74
- // This is done so we can send the context to Sentry in case of an erroneous situation
75
- let erroneousSituationsFound = false;
76
- // Prepare an array of internal accounts to be saved to the user storage
77
- const internalAccountsToBeSavedToUserStorage = [];
78
- // Compare internal accounts list with user storage accounts list
79
- // First step: compare lengths
80
- const internalAccountsList = await getInternalAccountsList(options, entropySourceId);
81
- if (!internalAccountsList || !internalAccountsList.length) {
82
- throw new Error(`Failed to get internal accounts list`);
83
- }
84
- const hasMoreUserStorageAccountsThanInternalAccounts = userStorageAccountsList.length > internalAccountsList.length;
85
- // We don't want to remove existing accounts for a user
86
- // so we only add new accounts if the user has more accounts in user storage than internal accounts
87
- if (hasMoreUserStorageAccountsThanInternalAccounts) {
88
- const numberOfAccountsToAdd = Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -
89
- internalAccountsList.length;
90
- // Create new accounts to match the user storage accounts list
91
- await getMessenger().call('KeyringController:withKeyring', {
92
- id: entropySourceId,
93
- }, async ({ keyring }) => {
94
- await keyring.addAccounts(numberOfAccountsToAdd);
95
- });
96
- // TODO: below code is kept for analytics but should probably be re-thought
97
- for (let i = 0; i < numberOfAccountsToAdd; i++) {
98
- onAccountAdded?.();
77
+ const { maxNumberOfAccountsToAdd = Infinity, onAccountAdded, onAccountNameUpdated, onAccountSyncErroneousSituation, } = config;
78
+ const { getMessenger, getUserStorageControllerInstance } = options;
79
+ try {
80
+ await getUserStorageControllerInstance().setIsAccountSyncingInProgress(true);
81
+ const userStorageAccountsList = await getUserStorageAccountsList(options, entropySourceId);
82
+ if (!userStorageAccountsList || !userStorageAccountsList.length) {
83
+ await saveInternalAccountsListToUserStorage(options, entropySourceId);
84
+ return;
99
85
  }
100
- }
101
- // Second step: compare account names
102
- // Get the internal accounts list again since new accounts might have been added in the previous step
103
- const refreshedInternalAccountsList = await getInternalAccountsList(options, entropySourceId);
104
- const newlyAddedAccounts = refreshedInternalAccountsList.filter((account) => !internalAccountsList.find((a) => a.address === account.address));
105
- for (const internalAccount of refreshedInternalAccountsList) {
106
- const userStorageAccount = userStorageAccountsList.find((account) => account.a === internalAccount.address);
107
- // If the account is not present in user storage
108
- // istanbul ignore next
109
- if (!userStorageAccount) {
110
- // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account
111
- if (newlyAddedAccounts.includes(internalAccount)) {
112
- erroneousSituationsFound = true;
113
- onAccountSyncErroneousSituation?.('An account was added to the internal accounts list but was not present in the user storage accounts list', {
114
- internalAccount,
115
- userStorageAccount,
116
- newlyAddedAccounts,
117
- userStorageAccountsList,
118
- internalAccountsList,
119
- refreshedInternalAccountsList,
120
- internalAccountsToBeSavedToUserStorage,
121
- });
122
- continue;
86
+ // Keep a record if erroneous situations are found during the sync
87
+ // This is done so we can send the context to Sentry in case of an erroneous situation
88
+ let erroneousSituationsFound = false;
89
+ // Prepare an array of internal accounts to be saved to the user storage
90
+ const internalAccountsToBeSavedToUserStorage = [];
91
+ // Compare internal accounts list with user storage accounts list
92
+ // First step: compare lengths
93
+ const internalAccountsList = await getInternalAccountsList(options, entropySourceId);
94
+ if (!internalAccountsList || !internalAccountsList.length) {
95
+ throw new Error(`Failed to get internal accounts list`);
96
+ }
97
+ const hasMoreUserStorageAccountsThanInternalAccounts = userStorageAccountsList.length > internalAccountsList.length;
98
+ // We don't want to remove existing accounts for a user
99
+ // so we only add new accounts if the user has more accounts in user storage than internal accounts
100
+ if (hasMoreUserStorageAccountsThanInternalAccounts) {
101
+ const numberOfAccountsToAdd = Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -
102
+ internalAccountsList.length;
103
+ // Create new accounts to match the user storage accounts list
104
+ await getMessenger().call('KeyringController:withKeyring', {
105
+ id: entropySourceId,
106
+ }, async ({ keyring }) => {
107
+ await keyring.addAccounts(numberOfAccountsToAdd);
108
+ });
109
+ // TODO: below code is kept for analytics but should probably be re-thought
110
+ for (let i = 0; i < numberOfAccountsToAdd; i++) {
111
+ onAccountAdded?.();
123
112
  }
124
- // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage
125
- internalAccountsToBeSavedToUserStorage.push(internalAccount);
126
- continue;
127
113
  }
128
- // From this point on, we know that the account is present in
129
- // both the internal accounts list and the user storage accounts list
130
- // One or both accounts have default names
131
- const isInternalAccountNameDefault = isNameDefaultAccountName(internalAccount.metadata.name);
132
- const isUserStorageAccountNameDefault = isNameDefaultAccountName(userStorageAccount.n);
133
- // Internal account has default name
134
- if (isInternalAccountNameDefault) {
135
- if (!isUserStorageAccountNameDefault) {
114
+ // Second step: compare account names
115
+ // Get the internal accounts list again since new accounts might have been added in the previous step
116
+ const refreshedInternalAccountsList = await getInternalAccountsList(options, entropySourceId);
117
+ const newlyAddedAccounts = refreshedInternalAccountsList.filter((account) => !internalAccountsList.find((a) => a.address === account.address));
118
+ for (const internalAccount of refreshedInternalAccountsList) {
119
+ const userStorageAccount = userStorageAccountsList.find((account) => account.a === internalAccount.address);
120
+ // If the account is not present in user storage
121
+ // istanbul ignore next
122
+ if (!userStorageAccount) {
123
+ // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account
124
+ if (newlyAddedAccounts.includes(internalAccount)) {
125
+ erroneousSituationsFound = true;
126
+ onAccountSyncErroneousSituation?.('An account was added to the internal accounts list but was not present in the user storage accounts list', {
127
+ internalAccount,
128
+ userStorageAccount,
129
+ newlyAddedAccounts,
130
+ userStorageAccountsList,
131
+ internalAccountsList,
132
+ refreshedInternalAccountsList,
133
+ internalAccountsToBeSavedToUserStorage,
134
+ });
135
+ continue;
136
+ }
137
+ // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage
138
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
139
+ continue;
140
+ }
141
+ // From this point on, we know that the account is present in
142
+ // both the internal accounts list and the user storage accounts list
143
+ // One or both accounts have default names
144
+ const isInternalAccountNameDefault = isNameDefaultAccountName(internalAccount.metadata.name);
145
+ const isUserStorageAccountNameDefault = isNameDefaultAccountName(userStorageAccount.n);
146
+ // Internal account has default name
147
+ if (isInternalAccountNameDefault) {
148
+ if (!isUserStorageAccountNameDefault) {
149
+ getMessenger().call('AccountsController:updateAccountMetadata', internalAccount.id, {
150
+ name: userStorageAccount.n,
151
+ });
152
+ onAccountNameUpdated?.();
153
+ }
154
+ continue;
155
+ }
156
+ // Internal account has custom name but user storage account has default name
157
+ if (isUserStorageAccountNameDefault) {
158
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
159
+ continue;
160
+ }
161
+ // Both accounts have custom names
162
+ // User storage account has a nameLastUpdatedAt timestamp
163
+ // Note: not storing the undefined checks in constants to act as a type guard
164
+ if (userStorageAccount.nlu !== undefined) {
165
+ if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
166
+ const isInternalAccountNameNewer = internalAccount.metadata.nameLastUpdatedAt >
167
+ userStorageAccount.nlu;
168
+ if (isInternalAccountNameNewer) {
169
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
170
+ continue;
171
+ }
172
+ }
136
173
  getMessenger().call('AccountsController:updateAccountMetadata', internalAccount.id, {
137
174
  name: userStorageAccount.n,
175
+ nameLastUpdatedAt: userStorageAccount.nlu,
138
176
  });
139
- onAccountNameUpdated?.();
177
+ const areInternalAndUserStorageAccountNamesEqual = internalAccount.metadata.name === userStorageAccount.n;
178
+ if (!areInternalAndUserStorageAccountNamesEqual) {
179
+ onAccountNameUpdated?.();
180
+ }
181
+ continue;
182
+ }
183
+ else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
184
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
185
+ continue;
140
186
  }
141
- continue;
142
187
  }
143
- // Internal account has custom name but user storage account has default name
144
- if (isUserStorageAccountNameDefault) {
145
- internalAccountsToBeSavedToUserStorage.push(internalAccount);
146
- continue;
188
+ // Save the internal accounts list to the user storage
189
+ if (internalAccountsToBeSavedToUserStorage.length) {
190
+ await getUserStorageControllerInstance().performBatchSetStorage(USER_STORAGE_FEATURE_NAMES.accounts, internalAccountsToBeSavedToUserStorage.map((account) => [
191
+ account.address,
192
+ JSON.stringify(mapInternalAccountToUserStorageAccount(account)),
193
+ ]), entropySourceId);
147
194
  }
148
- // Both accounts have custom names
149
- // User storage account has a nameLastUpdatedAt timestamp
150
- // Note: not storing the undefined checks in constants to act as a type guard
151
- if (userStorageAccount.nlu !== undefined) {
152
- if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
153
- const isInternalAccountNameNewer = internalAccount.metadata.nameLastUpdatedAt > userStorageAccount.nlu;
154
- if (isInternalAccountNameNewer) {
155
- internalAccountsToBeSavedToUserStorage.push(internalAccount);
156
- continue;
157
- }
158
- }
159
- getMessenger().call('AccountsController:updateAccountMetadata', internalAccount.id, {
160
- name: userStorageAccount.n,
161
- nameLastUpdatedAt: userStorageAccount.nlu,
195
+ // In case we have corrupted user storage with accounts that don't exist in the internal accounts list
196
+ // Delete those accounts from the user storage
197
+ const userStorageAccountsToBeDeleted = userStorageAccountsList.filter((account) => !refreshedInternalAccountsList.find((a) => a.address === account.a));
198
+ if (userStorageAccountsToBeDeleted.length) {
199
+ await getUserStorageControllerInstance().performBatchDeleteStorage(USER_STORAGE_FEATURE_NAMES.accounts, userStorageAccountsToBeDeleted.map((account) => account.a), entropySourceId);
200
+ erroneousSituationsFound = true;
201
+ onAccountSyncErroneousSituation?.('An account was present in the user storage accounts list but was not found in the internal accounts list after the sync', {
202
+ userStorageAccountsToBeDeleted,
203
+ internalAccountsList,
204
+ refreshedInternalAccountsList,
205
+ internalAccountsToBeSavedToUserStorage,
206
+ userStorageAccountsList,
162
207
  });
163
- const areInternalAndUserStorageAccountNamesEqual = internalAccount.metadata.name === userStorageAccount.n;
164
- if (!areInternalAndUserStorageAccountNamesEqual) {
165
- onAccountNameUpdated?.();
166
- }
167
- continue;
168
208
  }
169
- else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
170
- internalAccountsToBeSavedToUserStorage.push(internalAccount);
171
- continue;
209
+ if (erroneousSituationsFound) {
210
+ const [finalUserStorageAccountsList, finalInternalAccountsList] = await Promise.all([
211
+ getUserStorageAccountsList(options, entropySourceId),
212
+ getInternalAccountsList(options, entropySourceId),
213
+ ]);
214
+ const doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList = finalInternalAccountsList.every((account) => finalUserStorageAccountsList?.some((userStorageAccount) => userStorageAccount.a === account.address));
215
+ // istanbul ignore next
216
+ const doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList = (finalUserStorageAccountsList?.length || 0) > maxNumberOfAccountsToAdd
217
+ ? true
218
+ : finalUserStorageAccountsList?.every((account) => finalInternalAccountsList.some((internalAccount) => internalAccount.address === account.a));
219
+ const doFinalListsMatch = doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList &&
220
+ doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList;
221
+ const context = {
222
+ finalUserStorageAccountsList,
223
+ finalInternalAccountsList,
224
+ };
225
+ if (doFinalListsMatch) {
226
+ onAccountSyncErroneousSituation?.('Erroneous situations were found during the sync, but final state matches the expected state', context);
227
+ }
228
+ else {
229
+ onAccountSyncErroneousSituation?.('Erroneous situations were found during the sync, and final state does not match the expected state', context);
230
+ }
172
231
  }
173
232
  }
174
- // Save the internal accounts list to the user storage
175
- if (internalAccountsToBeSavedToUserStorage.length) {
176
- await getUserStorageControllerInstance().performBatchSetStorage(USER_STORAGE_FEATURE_NAMES.accounts, internalAccountsToBeSavedToUserStorage.map((account) => [
177
- account.address,
178
- JSON.stringify(mapInternalAccountToUserStorageAccount(account)),
179
- ]), entropySourceId);
180
- }
181
- // In case we have corrupted user storage with accounts that don't exist in the internal accounts list
182
- // Delete those accounts from the user storage
183
- const userStorageAccountsToBeDeleted = userStorageAccountsList.filter((account) => !refreshedInternalAccountsList.find((a) => a.address === account.a));
184
- if (userStorageAccountsToBeDeleted.length) {
185
- await getUserStorageControllerInstance().performBatchDeleteStorage(USER_STORAGE_FEATURE_NAMES.accounts, userStorageAccountsToBeDeleted.map((account) => account.a), entropySourceId);
186
- erroneousSituationsFound = true;
187
- onAccountSyncErroneousSituation?.('An account was present in the user storage accounts list but was not found in the internal accounts list after the sync', {
188
- userStorageAccountsToBeDeleted,
189
- internalAccountsList,
190
- refreshedInternalAccountsList,
191
- internalAccountsToBeSavedToUserStorage,
192
- userStorageAccountsList,
193
- });
194
- }
195
- if (erroneousSituationsFound) {
196
- const [finalUserStorageAccountsList, finalInternalAccountsList] = await Promise.all([
197
- getUserStorageAccountsList(options, entropySourceId),
198
- getInternalAccountsList(options, entropySourceId),
199
- ]);
200
- const doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList = finalInternalAccountsList.every((account) => finalUserStorageAccountsList?.some((userStorageAccount) => userStorageAccount.a === account.address));
233
+ catch (e) {
201
234
  // istanbul ignore next
202
- const doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList = (finalUserStorageAccountsList?.length || 0) > maxNumberOfAccountsToAdd
203
- ? true
204
- : finalUserStorageAccountsList?.every((account) => finalInternalAccountsList.some((internalAccount) => internalAccount.address === account.a));
205
- const doFinalListsMatch = doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList &&
206
- doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList;
207
- const context = {
208
- finalUserStorageAccountsList,
209
- finalInternalAccountsList,
210
- };
211
- if (doFinalListsMatch) {
212
- onAccountSyncErroneousSituation?.('Erroneous situations were found during the sync, but final state matches the expected state', context);
213
- }
214
- else {
215
- onAccountSyncErroneousSituation?.('Erroneous situations were found during the sync, and final state does not match the expected state', context);
216
- }
235
+ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
236
+ throw new Error(`UserStorageController - failed to sync user storage accounts list - ${errorMessage}`);
217
237
  }
238
+ finally {
239
+ await getUserStorageControllerInstance().setIsAccountSyncingInProgress(false);
240
+ }
241
+ };
242
+ if (trace) {
243
+ return await trace({ name: TraceName.AccountSyncFull }, performAccountSync);
218
244
  }
219
- catch (e) {
220
- // istanbul ignore next
221
- const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
222
- throw new Error(`UserStorageController - failed to sync user storage accounts list - ${errorMessage}`);
223
- }
224
- finally {
225
- await getUserStorageControllerInstance().setIsAccountSyncingInProgress(false);
226
- }
245
+ return await performAccountSync();
227
246
  }
228
247
  //# sourceMappingURL=controller-integration.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller-integration.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/controller-integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport {\n canPerformAccountSyncing,\n getInternalAccountsList,\n getUserStorageAccountsList,\n} from './sync-utils';\nimport type { AccountSyncingOptions } from './types';\nimport {\n isNameDefaultAccountName,\n mapInternalAccountToUserStorageAccount,\n} from './utils';\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\n\n/**\n * Saves an individual internal account to the user storage.\n *\n * @param internalAccount - The internal account to save\n * @param options - parameters used for saving the internal account\n */\nexport async function saveInternalAccountToUserStorage(\n internalAccount: InternalAccount,\n options: AccountSyncingOptions,\n): Promise<void> {\n const { getUserStorageControllerInstance } = options;\n\n if (\n !canPerformAccountSyncing(options) ||\n internalAccount.metadata.keyring.type !== String(KeyringTypes.hd) // sync only EVM accounts until we support multichain accounts\n ) {\n return;\n }\n\n // properties of `options` are (wrongly?) typed as `Json` and eslint crashes if we try to interpret it as such and call a `?.toString()` on it.\n // but we know this is a string?, so we can safely cast it\n const entropySourceId = internalAccount.options.entropySource as\n | string\n | undefined;\n\n try {\n // Map the internal account to the user storage account schema\n const mappedAccount =\n mapInternalAccountToUserStorageAccount(internalAccount);\n\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`,\n JSON.stringify(mappedAccount),\n entropySourceId,\n );\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to save account to user storage - ${errorMessage}`,\n );\n }\n}\n\n/**\n * Saves the list of internal accounts to the user storage.\n *\n * @param options - parameters used for saving the list of internal accounts\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n */\nexport async function saveInternalAccountsListToUserStorage(\n options: AccountSyncingOptions,\n entropySourceId: string,\n): Promise<void> {\n const { getUserStorageControllerInstance } = options;\n\n const internalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n if (!internalAccountsList?.length) {\n return;\n }\n\n const internalAccountsListFormattedForUserStorage = internalAccountsList.map(\n mapInternalAccountToUserStorageAccount,\n );\n\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsListFormattedForUserStorage.map((account) => [\n account.a,\n JSON.stringify(account),\n ]),\n entropySourceId,\n );\n}\n\ntype SyncInternalAccountsWithUserStorageConfig = {\n maxNumberOfAccountsToAdd?: number;\n onAccountAdded?: () => void;\n onAccountNameUpdated?: () => void;\n onAccountSyncErroneousSituation?: (\n errorMessage: string,\n sentryContext?: Record<string, unknown>,\n ) => void;\n};\n\n/**\n * Syncs the internal accounts list with the user storage accounts list.\n * This method is used to make sure that the internal accounts list is up-to-date with the user storage accounts list and vice-versa.\n * It will add new accounts to the internal accounts list, update/merge conflicting names and re-upload the results in some cases to the user storage.\n *\n * @param config - parameters used for syncing the internal accounts list with the user storage accounts list\n * @param options - parameters used for syncing the internal accounts list with the user storage accounts list\n * @param entropySourceId - The entropy source ID used to derive the key,\n */\nexport async function syncInternalAccountsWithUserStorage(\n config: SyncInternalAccountsWithUserStorageConfig,\n options: AccountSyncingOptions,\n entropySourceId: string,\n): Promise<void> {\n if (!canPerformAccountSyncing(options)) {\n return;\n }\n\n const {\n maxNumberOfAccountsToAdd = Infinity,\n onAccountAdded,\n onAccountNameUpdated,\n onAccountSyncErroneousSituation,\n } = config;\n const { getMessenger, getUserStorageControllerInstance } = options;\n\n try {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n true,\n );\n\n const userStorageAccountsList = await getUserStorageAccountsList(\n options,\n entropySourceId,\n );\n\n if (!userStorageAccountsList || !userStorageAccountsList.length) {\n await saveInternalAccountsListToUserStorage(options, entropySourceId);\n return;\n }\n // Keep a record if erroneous situations are found during the sync\n // This is done so we can send the context to Sentry in case of an erroneous situation\n let erroneousSituationsFound = false;\n\n // Prepare an array of internal accounts to be saved to the user storage\n const internalAccountsToBeSavedToUserStorage: InternalAccount[] = [];\n\n // Compare internal accounts list with user storage accounts list\n // First step: compare lengths\n const internalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n if (!internalAccountsList || !internalAccountsList.length) {\n throw new Error(`Failed to get internal accounts list`);\n }\n\n const hasMoreUserStorageAccountsThanInternalAccounts =\n userStorageAccountsList.length > internalAccountsList.length;\n\n // We don't want to remove existing accounts for a user\n // so we only add new accounts if the user has more accounts in user storage than internal accounts\n if (hasMoreUserStorageAccountsThanInternalAccounts) {\n const numberOfAccountsToAdd =\n Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -\n internalAccountsList.length;\n\n // Create new accounts to match the user storage accounts list\n await getMessenger().call(\n 'KeyringController:withKeyring',\n {\n id: entropySourceId,\n },\n async ({ keyring }) => {\n await keyring.addAccounts(numberOfAccountsToAdd);\n },\n );\n\n // TODO: below code is kept for analytics but should probably be re-thought\n for (let i = 0; i < numberOfAccountsToAdd; i++) {\n onAccountAdded?.();\n }\n }\n\n // Second step: compare account names\n // Get the internal accounts list again since new accounts might have been added in the previous step\n const refreshedInternalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n const newlyAddedAccounts = refreshedInternalAccountsList.filter(\n (account) =>\n !internalAccountsList.find((a) => a.address === account.address),\n );\n\n for (const internalAccount of refreshedInternalAccountsList) {\n const userStorageAccount = userStorageAccountsList.find(\n (account) => account.a === internalAccount.address,\n );\n\n // If the account is not present in user storage\n // istanbul ignore next\n if (!userStorageAccount) {\n // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account\n if (newlyAddedAccounts.includes(internalAccount)) {\n erroneousSituationsFound = true;\n onAccountSyncErroneousSituation?.(\n 'An account was added to the internal accounts list but was not present in the user storage accounts list',\n {\n internalAccount,\n userStorageAccount,\n newlyAddedAccounts,\n userStorageAccountsList,\n internalAccountsList,\n refreshedInternalAccountsList,\n internalAccountsToBeSavedToUserStorage,\n },\n );\n continue;\n }\n // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // From this point on, we know that the account is present in\n // both the internal accounts list and the user storage accounts list\n\n // One or both accounts have default names\n const isInternalAccountNameDefault = isNameDefaultAccountName(\n internalAccount.metadata.name,\n );\n const isUserStorageAccountNameDefault = isNameDefaultAccountName(\n userStorageAccount.n,\n );\n\n // Internal account has default name\n if (isInternalAccountNameDefault) {\n if (!isUserStorageAccountNameDefault) {\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n },\n );\n\n onAccountNameUpdated?.();\n }\n continue;\n }\n\n // Internal account has custom name but user storage account has default name\n if (isUserStorageAccountNameDefault) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // Both accounts have custom names\n\n // User storage account has a nameLastUpdatedAt timestamp\n // Note: not storing the undefined checks in constants to act as a type guard\n if (userStorageAccount.nlu !== undefined) {\n if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n const isInternalAccountNameNewer =\n internalAccount.metadata.nameLastUpdatedAt > userStorageAccount.nlu;\n\n if (isInternalAccountNameNewer) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n nameLastUpdatedAt: userStorageAccount.nlu,\n },\n );\n\n const areInternalAndUserStorageAccountNamesEqual =\n internalAccount.metadata.name === userStorageAccount.n;\n\n if (!areInternalAndUserStorageAccountNamesEqual) {\n onAccountNameUpdated?.();\n }\n\n continue;\n } else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n // Save the internal accounts list to the user storage\n if (internalAccountsToBeSavedToUserStorage.length) {\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsToBeSavedToUserStorage.map((account) => [\n account.address,\n JSON.stringify(mapInternalAccountToUserStorageAccount(account)),\n ]),\n entropySourceId,\n );\n }\n\n // In case we have corrupted user storage with accounts that don't exist in the internal accounts list\n // Delete those accounts from the user storage\n const userStorageAccountsToBeDeleted = userStorageAccountsList.filter(\n (account) =>\n !refreshedInternalAccountsList.find((a) => a.address === account.a),\n );\n\n if (userStorageAccountsToBeDeleted.length) {\n await getUserStorageControllerInstance().performBatchDeleteStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n userStorageAccountsToBeDeleted.map((account) => account.a),\n entropySourceId,\n );\n erroneousSituationsFound = true;\n onAccountSyncErroneousSituation?.(\n 'An account was present in the user storage accounts list but was not found in the internal accounts list after the sync',\n {\n userStorageAccountsToBeDeleted,\n internalAccountsList,\n refreshedInternalAccountsList,\n internalAccountsToBeSavedToUserStorage,\n userStorageAccountsList,\n },\n );\n }\n\n if (erroneousSituationsFound) {\n const [finalUserStorageAccountsList, finalInternalAccountsList] =\n await Promise.all([\n getUserStorageAccountsList(options, entropySourceId),\n getInternalAccountsList(options, entropySourceId),\n ]);\n\n const doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList =\n finalInternalAccountsList.every((account) =>\n finalUserStorageAccountsList?.some(\n (userStorageAccount) => userStorageAccount.a === account.address,\n ),\n );\n\n // istanbul ignore next\n const doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList =\n (finalUserStorageAccountsList?.length || 0) > maxNumberOfAccountsToAdd\n ? true\n : finalUserStorageAccountsList?.every((account) =>\n finalInternalAccountsList.some(\n (internalAccount) => internalAccount.address === account.a,\n ),\n );\n\n const doFinalListsMatch =\n doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList &&\n doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList;\n\n const context = {\n finalUserStorageAccountsList,\n finalInternalAccountsList,\n };\n if (doFinalListsMatch) {\n onAccountSyncErroneousSituation?.(\n 'Erroneous situations were found during the sync, but final state matches the expected state',\n context,\n );\n } else {\n onAccountSyncErroneousSituation?.(\n 'Erroneous situations were found during the sync, and final state does not match the expected state',\n context,\n );\n }\n }\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to sync user storage accounts list - ${errorMessage}`,\n );\n } finally {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n false,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"controller-integration.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/controller-integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport {\n canPerformAccountSyncing,\n getInternalAccountsList,\n getUserStorageAccountsList,\n} from './sync-utils';\nimport type { AccountSyncingOptions } from './types';\nimport {\n isNameDefaultAccountName,\n mapInternalAccountToUserStorageAccount,\n} from './utils';\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\nimport { TraceName } from '../constants';\n\n/**\n * Saves an individual internal account to the user storage.\n *\n * @param internalAccount - The internal account to save\n * @param options - parameters used for saving the internal account\n * @returns Promise that resolves when the account is saved\n */\nexport async function saveInternalAccountToUserStorage(\n internalAccount: InternalAccount,\n options: AccountSyncingOptions,\n): Promise<void> {\n const { trace } = options;\n\n const saveAccount = async () => {\n const { getUserStorageControllerInstance } = options;\n\n if (\n !canPerformAccountSyncing(options) ||\n internalAccount.metadata.keyring.type !== String(KeyringTypes.hd) // sync only EVM accounts until we support multichain accounts\n ) {\n return;\n }\n\n // properties of `options` are (wrongly?) typed as `Json` and eslint crashes if we try to interpret it as such and call a `?.toString()` on it.\n // but we know this is a string?, so we can safely cast it\n const entropySourceId = internalAccount.options?.entropySource as\n | string\n | undefined;\n\n try {\n // Map the internal account to the user storage account schema\n const mappedAccount =\n mapInternalAccountToUserStorageAccount(internalAccount);\n\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`,\n JSON.stringify(mappedAccount),\n entropySourceId,\n );\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to save account to user storage - ${errorMessage}`,\n );\n }\n };\n\n if (trace) {\n return await trace(\n { name: TraceName.AccountSyncSaveIndividual },\n saveAccount,\n );\n }\n\n return await saveAccount();\n}\n\n/**\n * Saves the list of internal accounts to the user storage.\n *\n * @param options - parameters used for saving the list of internal accounts\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns Promise that resolves when all accounts are saved\n */\nexport async function saveInternalAccountsListToUserStorage(\n options: AccountSyncingOptions,\n entropySourceId: string,\n): Promise<void> {\n const { getUserStorageControllerInstance } = options;\n\n const internalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n if (!internalAccountsList?.length) {\n return;\n }\n\n const internalAccountsListFormattedForUserStorage = internalAccountsList.map(\n mapInternalAccountToUserStorageAccount,\n );\n\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsListFormattedForUserStorage.map((account) => [\n account.a,\n JSON.stringify(account),\n ]),\n entropySourceId,\n );\n}\n\ntype SyncInternalAccountsWithUserStorageConfig = {\n maxNumberOfAccountsToAdd?: number;\n onAccountAdded?: () => void;\n onAccountNameUpdated?: () => void;\n onAccountSyncErroneousSituation?: (\n errorMessage: string,\n sentryContext?: Record<string, unknown>,\n ) => void;\n};\n\n/**\n * Syncs the internal accounts list with the user storage accounts list.\n * This method is used to make sure that the internal accounts list is up-to-date with the user storage accounts list and vice-versa.\n * It will add new accounts to the internal accounts list, update/merge conflicting names and re-upload the results in some cases to the user storage.\n *\n * @param config - parameters used for syncing the internal accounts list with the user storage accounts list\n * @param options - parameters used for syncing the internal accounts list with the user storage accounts list\n * @param entropySourceId - The entropy source ID used to derive the key,\n * @returns Promise that resolves when synchronization is complete\n */\nexport async function syncInternalAccountsWithUserStorage(\n config: SyncInternalAccountsWithUserStorageConfig,\n options: AccountSyncingOptions,\n entropySourceId: string,\n): Promise<void> {\n const { trace } = options;\n\n const performAccountSync = async () => {\n if (!canPerformAccountSyncing(options)) {\n return;\n }\n\n const {\n maxNumberOfAccountsToAdd = Infinity,\n onAccountAdded,\n onAccountNameUpdated,\n onAccountSyncErroneousSituation,\n } = config;\n const { getMessenger, getUserStorageControllerInstance } = options;\n\n try {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n true,\n );\n\n const userStorageAccountsList = await getUserStorageAccountsList(\n options,\n entropySourceId,\n );\n\n if (!userStorageAccountsList || !userStorageAccountsList.length) {\n await saveInternalAccountsListToUserStorage(options, entropySourceId);\n return;\n }\n // Keep a record if erroneous situations are found during the sync\n // This is done so we can send the context to Sentry in case of an erroneous situation\n let erroneousSituationsFound = false;\n\n // Prepare an array of internal accounts to be saved to the user storage\n const internalAccountsToBeSavedToUserStorage: InternalAccount[] = [];\n\n // Compare internal accounts list with user storage accounts list\n // First step: compare lengths\n const internalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n if (!internalAccountsList || !internalAccountsList.length) {\n throw new Error(`Failed to get internal accounts list`);\n }\n\n const hasMoreUserStorageAccountsThanInternalAccounts =\n userStorageAccountsList.length > internalAccountsList.length;\n\n // We don't want to remove existing accounts for a user\n // so we only add new accounts if the user has more accounts in user storage than internal accounts\n if (hasMoreUserStorageAccountsThanInternalAccounts) {\n const numberOfAccountsToAdd =\n Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -\n internalAccountsList.length;\n\n // Create new accounts to match the user storage accounts list\n await getMessenger().call(\n 'KeyringController:withKeyring',\n {\n id: entropySourceId,\n },\n async ({ keyring }) => {\n await keyring.addAccounts(numberOfAccountsToAdd);\n },\n );\n\n // TODO: below code is kept for analytics but should probably be re-thought\n for (let i = 0; i < numberOfAccountsToAdd; i++) {\n onAccountAdded?.();\n }\n }\n\n // Second step: compare account names\n // Get the internal accounts list again since new accounts might have been added in the previous step\n const refreshedInternalAccountsList = await getInternalAccountsList(\n options,\n entropySourceId,\n );\n\n const newlyAddedAccounts = refreshedInternalAccountsList.filter(\n (account) =>\n !internalAccountsList.find((a) => a.address === account.address),\n );\n\n for (const internalAccount of refreshedInternalAccountsList) {\n const userStorageAccount = userStorageAccountsList.find(\n (account) => account.a === internalAccount.address,\n );\n\n // If the account is not present in user storage\n // istanbul ignore next\n if (!userStorageAccount) {\n // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account\n if (newlyAddedAccounts.includes(internalAccount)) {\n erroneousSituationsFound = true;\n onAccountSyncErroneousSituation?.(\n 'An account was added to the internal accounts list but was not present in the user storage accounts list',\n {\n internalAccount,\n userStorageAccount,\n newlyAddedAccounts,\n userStorageAccountsList,\n internalAccountsList,\n refreshedInternalAccountsList,\n internalAccountsToBeSavedToUserStorage,\n },\n );\n continue;\n }\n // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // From this point on, we know that the account is present in\n // both the internal accounts list and the user storage accounts list\n\n // One or both accounts have default names\n const isInternalAccountNameDefault = isNameDefaultAccountName(\n internalAccount.metadata.name,\n );\n const isUserStorageAccountNameDefault = isNameDefaultAccountName(\n userStorageAccount.n,\n );\n\n // Internal account has default name\n if (isInternalAccountNameDefault) {\n if (!isUserStorageAccountNameDefault) {\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n },\n );\n\n onAccountNameUpdated?.();\n }\n continue;\n }\n\n // Internal account has custom name but user storage account has default name\n if (isUserStorageAccountNameDefault) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // Both accounts have custom names\n\n // User storage account has a nameLastUpdatedAt timestamp\n // Note: not storing the undefined checks in constants to act as a type guard\n if (userStorageAccount.nlu !== undefined) {\n if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n const isInternalAccountNameNewer =\n internalAccount.metadata.nameLastUpdatedAt >\n userStorageAccount.nlu;\n\n if (isInternalAccountNameNewer) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n nameLastUpdatedAt: userStorageAccount.nlu,\n },\n );\n\n const areInternalAndUserStorageAccountNamesEqual =\n internalAccount.metadata.name === userStorageAccount.n;\n\n if (!areInternalAndUserStorageAccountNamesEqual) {\n onAccountNameUpdated?.();\n }\n\n continue;\n } else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n // Save the internal accounts list to the user storage\n if (internalAccountsToBeSavedToUserStorage.length) {\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsToBeSavedToUserStorage.map((account) => [\n account.address,\n JSON.stringify(mapInternalAccountToUserStorageAccount(account)),\n ]),\n entropySourceId,\n );\n }\n\n // In case we have corrupted user storage with accounts that don't exist in the internal accounts list\n // Delete those accounts from the user storage\n const userStorageAccountsToBeDeleted = userStorageAccountsList.filter(\n (account) =>\n !refreshedInternalAccountsList.find((a) => a.address === account.a),\n );\n\n if (userStorageAccountsToBeDeleted.length) {\n await getUserStorageControllerInstance().performBatchDeleteStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n userStorageAccountsToBeDeleted.map((account) => account.a),\n entropySourceId,\n );\n erroneousSituationsFound = true;\n onAccountSyncErroneousSituation?.(\n 'An account was present in the user storage accounts list but was not found in the internal accounts list after the sync',\n {\n userStorageAccountsToBeDeleted,\n internalAccountsList,\n refreshedInternalAccountsList,\n internalAccountsToBeSavedToUserStorage,\n userStorageAccountsList,\n },\n );\n }\n\n if (erroneousSituationsFound) {\n const [finalUserStorageAccountsList, finalInternalAccountsList] =\n await Promise.all([\n getUserStorageAccountsList(options, entropySourceId),\n getInternalAccountsList(options, entropySourceId),\n ]);\n\n const doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList =\n finalInternalAccountsList.every((account) =>\n finalUserStorageAccountsList?.some(\n (userStorageAccount) => userStorageAccount.a === account.address,\n ),\n );\n\n // istanbul ignore next\n const doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList =\n (finalUserStorageAccountsList?.length || 0) > maxNumberOfAccountsToAdd\n ? true\n : finalUserStorageAccountsList?.every((account) =>\n finalInternalAccountsList.some(\n (internalAccount) => internalAccount.address === account.a,\n ),\n );\n\n const doFinalListsMatch =\n doesEveryAccountInInternalAccountsListExistInUserStorageAccountsList &&\n doesEveryAccountInUserStorageAccountsListExistInInternalAccountsList;\n\n const context = {\n finalUserStorageAccountsList,\n finalInternalAccountsList,\n };\n if (doFinalListsMatch) {\n onAccountSyncErroneousSituation?.(\n 'Erroneous situations were found during the sync, but final state matches the expected state',\n context,\n );\n } else {\n onAccountSyncErroneousSituation?.(\n 'Erroneous situations were found during the sync, and final state does not match the expected state',\n context,\n );\n }\n }\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to sync user storage accounts list - ${errorMessage}`,\n );\n } finally {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n false,\n );\n }\n };\n\n if (trace) {\n return await trace({ name: TraceName.AccountSyncFull }, performAccountSync);\n }\n\n return await performAccountSync();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type UserStorageController from '../UserStorageController';\n\nexport type UserStorageAccount = {\n /**\n * The Version 'v' of the User Storage.\n * NOTE - will allow us to support upgrade/downgrades in the future\n */\n [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION;\n /** the id 'i' of the account */\n i: string;\n /** the address 'a' of the account */\n a: string;\n /** the name 'n' of the account */\n n: string;\n /** the nameLastUpdatedAt timestamp 'nlu' of the account */\n nlu?: number;\n};\n\nexport type AccountSyncingOptions = {\n getUserStorageControllerInstance: () => UserStorageController;\n getMessenger: () => UserStorageControllerMessenger;\n};\n"]}
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\n\nimport type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type UserStorageController from '../UserStorageController';\n\nexport type UserStorageAccount = {\n /**\n * The Version 'v' of the User Storage.\n * NOTE - will allow us to support upgrade/downgrades in the future\n */\n [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION;\n /** the id 'i' of the account */\n i: string;\n /** the address 'a' of the account */\n a: string;\n /** the name 'n' of the account */\n n: string;\n /** the nameLastUpdatedAt timestamp 'nlu' of the account */\n nlu?: number;\n};\n\nexport type AccountSyncingOptions = {\n getUserStorageControllerInstance: () => UserStorageController;\n getMessenger: () => UserStorageControllerMessenger;\n trace?: TraceCallback;\n};\n"]}
@@ -1,3 +1,4 @@
1
+ import type { TraceCallback } from "@metamask/controller-utils";
1
2
  import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.cjs";
2
3
  import type { UserStorageControllerMessenger } from "../UserStorageController.cjs";
3
4
  import type UserStorageController from "../UserStorageController.cjs";
@@ -19,5 +20,6 @@ export type UserStorageAccount = {
19
20
  export type AccountSyncingOptions = {
20
21
  getUserStorageControllerInstance: () => UserStorageController;
21
22
  getMessenger: () => UserStorageControllerMessenger;
23
+ trace?: TraceCallback;
22
24
  };
23
25
  //# sourceMappingURL=types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AACrB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,qBAAqB,qCAAiC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,CAAC,wBAAwB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxD,gCAAgC;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;IAC9D,YAAY,EAAE,MAAM,8BAA8B,CAAC;CACpD,CAAC"}
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAEhE,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AACrB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,qBAAqB,qCAAiC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,CAAC,wBAAwB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxD,gCAAgC;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;IAC9D,YAAY,EAAE,MAAM,8BAA8B,CAAC;IACnD,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { TraceCallback } from "@metamask/controller-utils";
1
2
  import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.mjs";
2
3
  import type { UserStorageControllerMessenger } from "../UserStorageController.mjs";
3
4
  import type UserStorageController from "../UserStorageController.mjs";
@@ -19,5 +20,6 @@ export type UserStorageAccount = {
19
20
  export type AccountSyncingOptions = {
20
21
  getUserStorageControllerInstance: () => UserStorageController;
21
22
  getMessenger: () => UserStorageControllerMessenger;
23
+ trace?: TraceCallback;
22
24
  };
23
25
  //# sourceMappingURL=types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AACrB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,qBAAqB,qCAAiC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,CAAC,wBAAwB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxD,gCAAgC;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;IAC9D,YAAY,EAAE,MAAM,8BAA8B,CAAC;CACpD,CAAC"}
1
+ {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAEhE,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AACrB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,qBAAqB,qCAAiC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,CAAC,wBAAwB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxD,gCAAgC;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;IAC9D,YAAY,EAAE,MAAM,8BAA8B,CAAC;IACnD,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type UserStorageController from '../UserStorageController';\n\nexport type UserStorageAccount = {\n /**\n * The Version 'v' of the User Storage.\n * NOTE - will allow us to support upgrade/downgrades in the future\n */\n [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION;\n /** the id 'i' of the account */\n i: string;\n /** the address 'a' of the account */\n a: string;\n /** the name 'n' of the account */\n n: string;\n /** the nameLastUpdatedAt timestamp 'nlu' of the account */\n nlu?: number;\n};\n\nexport type AccountSyncingOptions = {\n getUserStorageControllerInstance: () => UserStorageController;\n getMessenger: () => UserStorageControllerMessenger;\n};\n"]}
1
+ {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\n\nimport type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type UserStorageController from '../UserStorageController';\n\nexport type UserStorageAccount = {\n /**\n * The Version 'v' of the User Storage.\n * NOTE - will allow us to support upgrade/downgrades in the future\n */\n [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION;\n /** the id 'i' of the account */\n i: string;\n /** the address 'a' of the account */\n a: string;\n /** the name 'n' of the account */\n n: string;\n /** the nameLastUpdatedAt timestamp 'nlu' of the account */\n nlu?: number;\n};\n\nexport type AccountSyncingOptions = {\n getUserStorageControllerInstance: () => UserStorageController;\n getMessenger: () => UserStorageControllerMessenger;\n trace?: TraceCallback;\n};\n"]}
@@ -1,9 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BACKUPANDSYNC_FEATURES = void 0;
3
+ exports.TraceName = exports.BACKUPANDSYNC_FEATURES = void 0;
4
4
  exports.BACKUPANDSYNC_FEATURES = {
5
5
  main: 'main',
6
6
  accountSyncing: 'accountSyncing',
7
7
  contactSyncing: 'contactSyncing',
8
8
  };
9
+ /**
10
+ * Trace names for UserStorage syncing operations
11
+ */
12
+ exports.TraceName = {
13
+ // Contact syncing traces
14
+ ContactSyncFull: 'Contact Sync Full',
15
+ ContactSyncSaveBatch: 'Contact Sync Save Batch',
16
+ ContactSyncUpdateRemote: 'Contact Sync Update Remote',
17
+ ContactSyncDeleteRemote: 'Contact Sync Delete Remote',
18
+ // Account syncing traces
19
+ AccountSyncFull: 'Account Sync Full',
20
+ AccountSyncSaveIndividual: 'Account Sync Save Individual',
21
+ };
9
22
  //# sourceMappingURL=constants.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,sBAAsB,GAAG;IACpC,IAAI,EAAE,MAAM;IACZ,cAAc,EAAE,gBAAgB;IAChC,cAAc,EAAE,gBAAgB;CACxB,CAAC","sourcesContent":["export const BACKUPANDSYNC_FEATURES = {\n main: 'main',\n accountSyncing: 'accountSyncing',\n contactSyncing: 'contactSyncing',\n} as const;\n"]}
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,sBAAsB,GAAG;IACpC,IAAI,EAAE,MAAM;IACZ,cAAc,EAAE,gBAAgB;IAChC,cAAc,EAAE,gBAAgB;CACxB,CAAC;AAEX;;GAEG;AACU,QAAA,SAAS,GAAG;IACvB,yBAAyB;IACzB,eAAe,EAAE,mBAAmB;IACpC,oBAAoB,EAAE,yBAAyB;IAC/C,uBAAuB,EAAE,4BAA4B;IACrD,uBAAuB,EAAE,4BAA4B;IAErD,yBAAyB;IACzB,eAAe,EAAE,mBAAmB;IACpC,yBAAyB,EAAE,8BAA8B;CACjD,CAAC","sourcesContent":["export const BACKUPANDSYNC_FEATURES = {\n main: 'main',\n accountSyncing: 'accountSyncing',\n contactSyncing: 'contactSyncing',\n} as const;\n\n/**\n * Trace names for UserStorage syncing operations\n */\nexport const TraceName = {\n // Contact syncing traces\n ContactSyncFull: 'Contact Sync Full',\n ContactSyncSaveBatch: 'Contact Sync Save Batch',\n ContactSyncUpdateRemote: 'Contact Sync Update Remote',\n ContactSyncDeleteRemote: 'Contact Sync Delete Remote',\n\n // Account syncing traces\n AccountSyncFull: 'Account Sync Full',\n AccountSyncSaveIndividual: 'Account Sync Save Individual',\n} as const;\n"]}