@metamask-previews/profile-sync-controller 15.0.0-preview-e9f8bc88 → 15.0.0-preview-2723071f

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 (74) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/controllers/user-storage/UserStorageController.cjs +56 -3
  3. package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
  4. package/dist/controllers/user-storage/UserStorageController.d.cts +40 -2
  5. package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
  6. package/dist/controllers/user-storage/UserStorageController.d.mts +40 -2
  7. package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
  8. package/dist/controllers/user-storage/UserStorageController.mjs +53 -0
  9. package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
  10. package/dist/controllers/user-storage/constants.cjs +1 -0
  11. package/dist/controllers/user-storage/constants.cjs.map +1 -1
  12. package/dist/controllers/user-storage/constants.d.cts +1 -0
  13. package/dist/controllers/user-storage/constants.d.cts.map +1 -1
  14. package/dist/controllers/user-storage/constants.d.mts +1 -0
  15. package/dist/controllers/user-storage/constants.d.mts.map +1 -1
  16. package/dist/controllers/user-storage/constants.mjs +1 -0
  17. package/dist/controllers/user-storage/constants.mjs.map +1 -1
  18. package/dist/controllers/user-storage/contact-syncing/constants.cjs +12 -0
  19. package/dist/controllers/user-storage/contact-syncing/constants.cjs.map +1 -0
  20. package/dist/controllers/user-storage/contact-syncing/constants.d.cts +9 -0
  21. package/dist/controllers/user-storage/contact-syncing/constants.d.cts.map +1 -0
  22. package/dist/controllers/user-storage/contact-syncing/constants.d.mts +9 -0
  23. package/dist/controllers/user-storage/contact-syncing/constants.d.mts.map +1 -0
  24. package/dist/controllers/user-storage/contact-syncing/constants.mjs +9 -0
  25. package/dist/controllers/user-storage/contact-syncing/constants.mjs.map +1 -0
  26. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs +299 -0
  27. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs.map +1 -0
  28. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts +45 -0
  29. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts.map +1 -0
  30. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts +45 -0
  31. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts.map +1 -0
  32. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs +293 -0
  33. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs.map +1 -0
  34. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.cjs +55 -0
  35. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.cjs.map +1 -0
  36. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.d.cts +8 -0
  37. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.d.cts.map +1 -0
  38. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.d.mts +8 -0
  39. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.d.mts.map +1 -0
  40. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.mjs +51 -0
  41. package/dist/controllers/user-storage/contact-syncing/setup-subscriptions.mjs.map +1 -0
  42. package/dist/controllers/user-storage/contact-syncing/sync-utils.cjs +23 -0
  43. package/dist/controllers/user-storage/contact-syncing/sync-utils.cjs.map +1 -0
  44. package/dist/controllers/user-storage/contact-syncing/sync-utils.d.cts +9 -0
  45. package/dist/controllers/user-storage/contact-syncing/sync-utils.d.cts.map +1 -0
  46. package/dist/controllers/user-storage/contact-syncing/sync-utils.d.mts +9 -0
  47. package/dist/controllers/user-storage/contact-syncing/sync-utils.d.mts.map +1 -0
  48. package/dist/controllers/user-storage/contact-syncing/sync-utils.mjs +19 -0
  49. package/dist/controllers/user-storage/contact-syncing/sync-utils.mjs.map +1 -0
  50. package/dist/controllers/user-storage/contact-syncing/types.cjs +3 -0
  51. package/dist/controllers/user-storage/contact-syncing/types.cjs.map +1 -0
  52. package/dist/controllers/user-storage/contact-syncing/types.d.cts +35 -0
  53. package/dist/controllers/user-storage/contact-syncing/types.d.cts.map +1 -0
  54. package/dist/controllers/user-storage/contact-syncing/types.d.mts +35 -0
  55. package/dist/controllers/user-storage/contact-syncing/types.d.mts.map +1 -0
  56. package/dist/controllers/user-storage/contact-syncing/types.mjs +2 -0
  57. package/dist/controllers/user-storage/contact-syncing/types.mjs.map +1 -0
  58. package/dist/controllers/user-storage/contact-syncing/utils.cjs +68 -0
  59. package/dist/controllers/user-storage/contact-syncing/utils.cjs.map +1 -0
  60. package/dist/controllers/user-storage/contact-syncing/utils.d.cts +29 -0
  61. package/dist/controllers/user-storage/contact-syncing/utils.d.cts.map +1 -0
  62. package/dist/controllers/user-storage/contact-syncing/utils.d.mts +29 -0
  63. package/dist/controllers/user-storage/contact-syncing/utils.d.mts.map +1 -0
  64. package/dist/controllers/user-storage/contact-syncing/utils.mjs +63 -0
  65. package/dist/controllers/user-storage/contact-syncing/utils.mjs.map +1 -0
  66. package/dist/shared/storage-schema.cjs +3 -1
  67. package/dist/shared/storage-schema.cjs.map +1 -1
  68. package/dist/shared/storage-schema.d.cts +2 -0
  69. package/dist/shared/storage-schema.d.cts.map +1 -1
  70. package/dist/shared/storage-schema.d.mts +2 -0
  71. package/dist/shared/storage-schema.d.mts.map +1 -1
  72. package/dist/shared/storage-schema.mjs +3 -1
  73. package/dist/shared/storage-schema.mjs.map +1 -1
  74. package/package.json +2 -2
@@ -0,0 +1,293 @@
1
+ import { canPerformContactSyncing } from "./sync-utils.mjs";
2
+ import { mapAddressBookEntryToUserStorageEntry, mapUserStorageEntryToAddressBookEntry } from "./utils.mjs";
3
+ import { USER_STORAGE_FEATURE_NAMES } from "../../../shared/storage-schema.mjs";
4
+ // Define a constant to use as the key for storing all contacts
5
+ export const ADDRESS_BOOK_CONTACTS_KEY = 'contacts';
6
+ /**
7
+ * Creates a unique key for a contact based on chainId and address
8
+ *
9
+ * @param contact - The contact to create a key for
10
+ * @returns A unique string key
11
+ */
12
+ function createContactKey(contact) {
13
+ return `${contact.chainId}:${contact.address.toLowerCase()}`;
14
+ }
15
+ /**
16
+ * Syncs contacts between local storage and user storage (remote).
17
+ *
18
+ * Handles the following syncing scenarios:
19
+ * 1. First Sync: When local contacts exist but there are no remote contacts, uploads all local contacts.
20
+ * 2. New Device Sync: Downloads remote contacts that don't exist locally (empty local address book).
21
+ * 3. Simple Merge: Ensures both sides (local & remote) have all contacts.
22
+ * 4. Contact Naming Conflicts: When same contact has different names, uses most recent by timestamp.
23
+ * 5. Local Updates: When a contact was updated locally, syncs changes to remote if local is newer.
24
+ * 6. Remote Updates: When a contact was updated remotely, applies changes locally if remote is newer.
25
+ * 7. Local Deletions: Handled by real-time event handlers (deleteContactInRemoteStorage) to prevent false positives.
26
+ * 8. Remote Deletions: When a contact was deleted remotely, applies deletion locally.
27
+ * 9. Concurrent Updates: Resolves conflicts using timestamps to determine the winner.
28
+ * 10. Restore After Delete: If a contact is modified after being deleted, restores it.
29
+ * 11. ChainId Differences: Treats same address on different chains as separate contacts.
30
+ *
31
+ * @param config - Parameters used for syncing callbacks
32
+ * @param options - Parameters used for syncing operations
33
+ */
34
+ export async function syncContactsWithUserStorage(config, options) {
35
+ const { getMessenger, getUserStorageControllerInstance } = options;
36
+ const { onContactSyncErroneousSituation, onContactUpdated, onContactDeleted, } = config;
37
+ try {
38
+ // Cannot perform sync, conditions not met
39
+ if (!canPerformContactSyncing(options)) {
40
+ return;
41
+ }
42
+ // Activate sync semaphore to prevent event loops
43
+ await getUserStorageControllerInstance().setIsContactSyncingInProgress(true);
44
+ // Get all local contacts from AddressBookController (exclude chain "*" contacts)
45
+ const localVisibleContacts = getMessenger()
46
+ .call('AddressBookController:list')
47
+ .filter((contact) => String(contact.chainId) !== '*') || [];
48
+ // Get remote contacts from user storage API
49
+ const remoteContacts = await getRemoteContacts(options);
50
+ // SCENARIO 1: First Sync - No remote contacts but local contacts exist
51
+ if (!remoteContacts || remoteContacts.length === 0) {
52
+ if (localVisibleContacts.length > 0) {
53
+ await saveContactsToUserStorage(localVisibleContacts, options);
54
+ }
55
+ return;
56
+ }
57
+ // Prepare maps for efficient lookup
58
+ const localContactsMap = new Map();
59
+ const remoteContactsMap = new Map();
60
+ localVisibleContacts.forEach((contact) => {
61
+ const key = createContactKey(contact);
62
+ localContactsMap.set(key, contact);
63
+ });
64
+ remoteContacts.forEach((contact) => {
65
+ const key = createContactKey(contact);
66
+ remoteContactsMap.set(key, contact);
67
+ });
68
+ // Lists to track contacts that need to be synced
69
+ const contactsToAddOrUpdateLocally = [];
70
+ const contactsToDeleteLocally = [];
71
+ const contactsToUpdateRemotely = [];
72
+ // SCENARIO 2 & 6: Process remote contacts - handle new device sync and remote updates
73
+ for (const remoteContact of remoteContacts) {
74
+ const key = createContactKey(remoteContact);
75
+ const localContact = localContactsMap.get(key);
76
+ // Handle remote contact based on its status and local existence
77
+ if (remoteContact.deleted) {
78
+ // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally
79
+ if (localContact) {
80
+ contactsToDeleteLocally.push(remoteContact);
81
+ if (onContactDeleted) {
82
+ onContactDeleted();
83
+ }
84
+ }
85
+ }
86
+ else if (!localContact) {
87
+ // SCENARIO 2: New contact from remote - import to local
88
+ contactsToAddOrUpdateLocally.push(remoteContact);
89
+ if (onContactUpdated) {
90
+ onContactUpdated();
91
+ }
92
+ }
93
+ else {
94
+ // SCENARIO 4 & 6: Contact exists on both sides - check for conflicts
95
+ const hasContentDifference = localContact.name !== remoteContact.name ||
96
+ localContact.memo !== remoteContact.memo;
97
+ if (hasContentDifference) {
98
+ // Check timestamps to determine which version to keep
99
+ const localTimestamp = localContact.lastUpdatedAt || 0;
100
+ const remoteTimestamp = remoteContact.lastUpdatedAt || 0;
101
+ if (localTimestamp >= remoteTimestamp) {
102
+ // Local is newer (or same age) - use local version
103
+ contactsToUpdateRemotely.push(localContact);
104
+ }
105
+ else {
106
+ // Remote is newer - use remote version
107
+ contactsToAddOrUpdateLocally.push(remoteContact);
108
+ if (onContactUpdated) {
109
+ onContactUpdated();
110
+ }
111
+ }
112
+ }
113
+ // Else: content is identical, no action needed
114
+ }
115
+ }
116
+ // SCENARIO 3 & 5: Process local contacts not in remote
117
+ for (const localContact of localVisibleContacts) {
118
+ const key = createContactKey(localContact);
119
+ const remoteContact = remoteContactsMap.get(key);
120
+ if (!remoteContact) {
121
+ // New local contact - add to remote
122
+ contactsToUpdateRemotely.push(localContact);
123
+ }
124
+ }
125
+ // Apply local deletions
126
+ for (const contact of contactsToDeleteLocally) {
127
+ try {
128
+ getMessenger().call('AddressBookController:delete', contact.chainId, contact.address);
129
+ }
130
+ catch (error) {
131
+ console.error('Error deleting contact:', error);
132
+ }
133
+ }
134
+ // Apply local additions/updates
135
+ for (const contact of contactsToAddOrUpdateLocally) {
136
+ if (!contact.deleted) {
137
+ try {
138
+ getMessenger().call('AddressBookController:set', contact.address, contact.name || '', contact.chainId, contact.memo || '', contact.addressType);
139
+ }
140
+ catch (error) {
141
+ console.error('Error updating contact:', error);
142
+ }
143
+ }
144
+ }
145
+ // Apply changes to remote storage
146
+ if (contactsToUpdateRemotely.length > 0) {
147
+ // Update existing remote contacts with new contacts
148
+ const updatedRemoteContacts = [...remoteContacts];
149
+ for (const localContact of contactsToUpdateRemotely) {
150
+ const key = createContactKey(localContact);
151
+ const existingIndex = updatedRemoteContacts.findIndex((c) => createContactKey(c) === key);
152
+ const now = Date.now();
153
+ const updatedEntry = {
154
+ ...localContact,
155
+ lastUpdatedAt: now,
156
+ deleted: false, // Ensure it's not deleted
157
+ };
158
+ if (existingIndex !== -1) {
159
+ // Update existing contact
160
+ updatedRemoteContacts[existingIndex] = updatedEntry;
161
+ }
162
+ else {
163
+ // Add new contact
164
+ updatedRemoteContacts.push(updatedEntry);
165
+ }
166
+ }
167
+ // Save updated contacts to remote storage
168
+ await saveContactsToUserStorage(updatedRemoteContacts, options);
169
+ }
170
+ }
171
+ catch (error) {
172
+ if (onContactSyncErroneousSituation) {
173
+ onContactSyncErroneousSituation('Error synchronizing contacts', {
174
+ error,
175
+ });
176
+ }
177
+ }
178
+ finally {
179
+ await getUserStorageControllerInstance().setIsContactSyncingInProgress(false);
180
+ }
181
+ }
182
+ /**
183
+ * Retrieves remote contacts from user storage API
184
+ *
185
+ * @param options - Parameters used for retrieving remote contacts
186
+ * @returns Array of contacts from remote storage, or null if none found
187
+ */
188
+ async function getRemoteContacts(options) {
189
+ const { getUserStorageControllerInstance } = options;
190
+ try {
191
+ const remoteContactsJson = await getUserStorageControllerInstance().performGetStorage(`${USER_STORAGE_FEATURE_NAMES.addressBook}.${ADDRESS_BOOK_CONTACTS_KEY}`);
192
+ if (!remoteContactsJson) {
193
+ return null;
194
+ }
195
+ // Parse the JSON and convert each entry from UserStorageContactEntry to AddressBookEntry
196
+ const remoteStorageEntries = JSON.parse(remoteContactsJson);
197
+ return remoteStorageEntries.map((entry) => mapUserStorageEntryToAddressBookEntry(entry));
198
+ }
199
+ catch {
200
+ return null;
201
+ }
202
+ }
203
+ /**
204
+ * Saves local contacts to user storage
205
+ *
206
+ * @param contacts - The contacts to save to user storage
207
+ * @param options - Parameters used for saving contacts
208
+ */
209
+ async function saveContactsToUserStorage(contacts, options) {
210
+ const { getUserStorageControllerInstance } = options;
211
+ if (!contacts || contacts.length === 0) {
212
+ return;
213
+ }
214
+ // Convert each AddressBookEntry to UserStorageContactEntry format before saving
215
+ const storageEntries = contacts.map((contact) => mapAddressBookEntryToUserStorageEntry(contact));
216
+ await getUserStorageControllerInstance().performSetStorage(`${USER_STORAGE_FEATURE_NAMES.addressBook}.${ADDRESS_BOOK_CONTACTS_KEY}`, JSON.stringify(storageEntries));
217
+ }
218
+ /**
219
+ * Updates a single contact in remote storage without performing a full sync
220
+ * This is used when a contact is updated locally to efficiently push changes to remote
221
+ *
222
+ * @param contact - The contact that was updated locally
223
+ * @param options - Parameters used for syncing operations
224
+ */
225
+ export async function updateContactInRemoteStorage(contact, options) {
226
+ if (!canPerformContactSyncing(options)) {
227
+ return;
228
+ }
229
+ try {
230
+ // Get current remote contacts or initialize empty array
231
+ const remoteContacts = (await getRemoteContacts(options)) || [];
232
+ // Find if this contact already exists in remote
233
+ const key = createContactKey(contact);
234
+ const existingIndex = remoteContacts.findIndex((c) => createContactKey(c) === key);
235
+ const updatedRemoteContacts = [...remoteContacts];
236
+ // Create an updated entry with timestamp
237
+ const updatedEntry = {
238
+ ...contact,
239
+ lastUpdatedAt: contact.lastUpdatedAt || Date.now(),
240
+ deleted: false, // Explicitly set to false in case this was previously deleted
241
+ };
242
+ if (existingIndex !== -1) {
243
+ // Update existing contact
244
+ updatedRemoteContacts[existingIndex] = updatedEntry;
245
+ }
246
+ else {
247
+ // Add as new contact
248
+ updatedRemoteContacts.push(updatedEntry);
249
+ }
250
+ // Save to remote storage
251
+ await saveContactsToUserStorage(updatedRemoteContacts, options);
252
+ }
253
+ catch (error) {
254
+ console.error('🔄 Contacts Sync: Error updating contact in remote storage', error);
255
+ }
256
+ }
257
+ /**
258
+ * Marks a single contact as deleted in remote storage without performing a full sync
259
+ * This is used when a contact is deleted locally to efficiently push the deletion to remote
260
+ *
261
+ * @param contact - The contact that was deleted locally (contains at least address and chainId)
262
+ * @param options - Parameters used for syncing operations
263
+ */
264
+ export async function deleteContactInRemoteStorage(contact, options) {
265
+ if (!canPerformContactSyncing(options)) {
266
+ return;
267
+ }
268
+ try {
269
+ // Get current remote contacts
270
+ const remoteContacts = (await getRemoteContacts(options)) || [];
271
+ // Find the contact in remote storage
272
+ const key = createContactKey(contact);
273
+ const existingIndex = remoteContacts.findIndex((c) => createContactKey(c) === key);
274
+ // If the contact exists in remote storage
275
+ if (existingIndex !== -1) {
276
+ const updatedRemoteContacts = [...remoteContacts];
277
+ const now = Date.now();
278
+ // Mark the contact as deleted
279
+ updatedRemoteContacts[existingIndex] = {
280
+ ...updatedRemoteContacts[existingIndex],
281
+ deleted: true,
282
+ deletedAt: now,
283
+ lastUpdatedAt: now,
284
+ };
285
+ // Save to remote storage
286
+ await saveContactsToUserStorage(updatedRemoteContacts, options);
287
+ }
288
+ }
289
+ catch (error) {
290
+ console.error('🔄 Contacts Sync: Error marking contact as deleted in remote storage', error);
291
+ }
292
+ }
293
+ //# sourceMappingURL=controller-integration.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-integration.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/controller-integration.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AddressBookEntry } from '@metamask/address-book-controller';\n\nimport { canPerformContactSyncing } from './sync-utils';\nimport type { ContactSyncingOptions } from './types';\nimport type { UserStorageContactEntry } from './types';\nimport {\n mapAddressBookEntryToUserStorageEntry,\n mapUserStorageEntryToAddressBookEntry,\n type SyncAddressBookEntry,\n} from './utils';\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\n\n// Define a constant to use as the key for storing all contacts\nexport const ADDRESS_BOOK_CONTACTS_KEY = 'contacts';\n\nexport type SyncContactsWithUserStorageConfig = {\n onContactSyncErroneousSituation?: (\n errorMessage: string,\n sentryContext?: Record<string, unknown>,\n ) => void;\n onContactUpdated?: () => void;\n onContactDeleted?: () => void;\n};\n\n/**\n * Creates a unique key for a contact based on chainId and address\n *\n * @param contact - The contact to create a key for\n * @returns A unique string key\n */\nfunction createContactKey(contact: AddressBookEntry): string {\n return `${contact.chainId}:${contact.address.toLowerCase()}`;\n}\n\n/**\n * Syncs contacts between local storage and user storage (remote).\n *\n * Handles the following syncing scenarios:\n * 1. First Sync: When local contacts exist but there are no remote contacts, uploads all local contacts.\n * 2. New Device Sync: Downloads remote contacts that don't exist locally (empty local address book).\n * 3. Simple Merge: Ensures both sides (local & remote) have all contacts.\n * 4. Contact Naming Conflicts: When same contact has different names, uses most recent by timestamp.\n * 5. Local Updates: When a contact was updated locally, syncs changes to remote if local is newer.\n * 6. Remote Updates: When a contact was updated remotely, applies changes locally if remote is newer.\n * 7. Local Deletions: Handled by real-time event handlers (deleteContactInRemoteStorage) to prevent false positives.\n * 8. Remote Deletions: When a contact was deleted remotely, applies deletion locally.\n * 9. Concurrent Updates: Resolves conflicts using timestamps to determine the winner.\n * 10. Restore After Delete: If a contact is modified after being deleted, restores it.\n * 11. ChainId Differences: Treats same address on different chains as separate contacts.\n *\n * @param config - Parameters used for syncing callbacks\n * @param options - Parameters used for syncing operations\n */\nexport async function syncContactsWithUserStorage(\n config: SyncContactsWithUserStorageConfig,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getMessenger, getUserStorageControllerInstance } = options;\n const {\n onContactSyncErroneousSituation,\n onContactUpdated,\n onContactDeleted,\n } = config;\n\n try {\n // Cannot perform sync, conditions not met\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // Activate sync semaphore to prevent event loops\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n true,\n );\n\n // Get all local contacts from AddressBookController (exclude chain \"*\" contacts)\n const localVisibleContacts =\n getMessenger()\n .call('AddressBookController:list')\n .filter((contact) => String(contact.chainId) !== '*') || [];\n\n // Get remote contacts from user storage API\n const remoteContacts = await getRemoteContacts(options);\n\n // SCENARIO 1: First Sync - No remote contacts but local contacts exist\n if (!remoteContacts || remoteContacts.length === 0) {\n if (localVisibleContacts.length > 0) {\n await saveContactsToUserStorage(localVisibleContacts, options);\n }\n return;\n }\n\n // Prepare maps for efficient lookup\n const localContactsMap = new Map<string, AddressBookEntry>();\n const remoteContactsMap = new Map<string, SyncAddressBookEntry>();\n\n localVisibleContacts.forEach((contact) => {\n const key = createContactKey(contact);\n localContactsMap.set(key, contact);\n });\n\n remoteContacts.forEach((contact) => {\n const key = createContactKey(contact);\n remoteContactsMap.set(key, contact);\n });\n\n // Lists to track contacts that need to be synced\n const contactsToAddOrUpdateLocally: SyncAddressBookEntry[] = [];\n const contactsToDeleteLocally: SyncAddressBookEntry[] = [];\n const contactsToUpdateRemotely: AddressBookEntry[] = [];\n\n // SCENARIO 2 & 6: Process remote contacts - handle new device sync and remote updates\n for (const remoteContact of remoteContacts) {\n const key = createContactKey(remoteContact);\n const localContact = localContactsMap.get(key);\n\n // Handle remote contact based on its status and local existence\n if (remoteContact.deleted) {\n // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally\n if (localContact) {\n contactsToDeleteLocally.push(remoteContact);\n\n if (onContactDeleted) {\n onContactDeleted();\n }\n }\n } else if (!localContact) {\n // SCENARIO 2: New contact from remote - import to local\n contactsToAddOrUpdateLocally.push(remoteContact);\n\n if (onContactUpdated) {\n onContactUpdated();\n }\n } else {\n // SCENARIO 4 & 6: Contact exists on both sides - check for conflicts\n const hasContentDifference =\n localContact.name !== remoteContact.name ||\n localContact.memo !== remoteContact.memo;\n\n if (hasContentDifference) {\n // Check timestamps to determine which version to keep\n const localTimestamp = localContact.lastUpdatedAt || 0;\n const remoteTimestamp = remoteContact.lastUpdatedAt || 0;\n\n if (localTimestamp >= remoteTimestamp) {\n // Local is newer (or same age) - use local version\n contactsToUpdateRemotely.push(localContact);\n } else {\n // Remote is newer - use remote version\n contactsToAddOrUpdateLocally.push(remoteContact);\n\n if (onContactUpdated) {\n onContactUpdated();\n }\n }\n }\n\n // Else: content is identical, no action needed\n }\n }\n\n // SCENARIO 3 & 5: Process local contacts not in remote\n for (const localContact of localVisibleContacts) {\n const key = createContactKey(localContact);\n const remoteContact = remoteContactsMap.get(key);\n\n if (!remoteContact) {\n // New local contact - add to remote\n contactsToUpdateRemotely.push(localContact);\n }\n }\n\n // Apply local deletions\n for (const contact of contactsToDeleteLocally) {\n try {\n getMessenger().call(\n 'AddressBookController:delete',\n contact.chainId,\n contact.address,\n );\n } catch (error) {\n console.error('Error deleting contact:', error);\n }\n }\n\n // Apply local additions/updates\n for (const contact of contactsToAddOrUpdateLocally) {\n if (!contact.deleted) {\n try {\n getMessenger().call(\n 'AddressBookController:set',\n contact.address,\n contact.name || '',\n contact.chainId,\n contact.memo || '',\n contact.addressType,\n );\n } catch (error) {\n console.error('Error updating contact:', error);\n }\n }\n }\n\n // Apply changes to remote storage\n if (contactsToUpdateRemotely.length > 0) {\n // Update existing remote contacts with new contacts\n const updatedRemoteContacts = [...remoteContacts];\n\n for (const localContact of contactsToUpdateRemotely) {\n const key = createContactKey(localContact);\n const existingIndex = updatedRemoteContacts.findIndex(\n (c) => createContactKey(c) === key,\n );\n\n const now = Date.now();\n const updatedEntry = {\n ...localContact,\n lastUpdatedAt: now,\n deleted: false, // Ensure it's not deleted\n } as SyncAddressBookEntry;\n\n if (existingIndex !== -1) {\n // Update existing contact\n updatedRemoteContacts[existingIndex] = updatedEntry;\n } else {\n // Add new contact\n updatedRemoteContacts.push(updatedEntry);\n }\n }\n\n // Save updated contacts to remote storage\n await saveContactsToUserStorage(updatedRemoteContacts, options);\n }\n } catch (error) {\n if (onContactSyncErroneousSituation) {\n onContactSyncErroneousSituation('Error synchronizing contacts', {\n error,\n });\n }\n } finally {\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n false,\n );\n }\n}\n\n/**\n * Retrieves remote contacts from user storage API\n *\n * @param options - Parameters used for retrieving remote contacts\n * @returns Array of contacts from remote storage, or null if none found\n */\nasync function getRemoteContacts(\n options: ContactSyncingOptions,\n): Promise<SyncAddressBookEntry[] | null> {\n const { getUserStorageControllerInstance } = options;\n\n try {\n const remoteContactsJson =\n await getUserStorageControllerInstance().performGetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${ADDRESS_BOOK_CONTACTS_KEY}`,\n );\n\n if (!remoteContactsJson) {\n return null;\n }\n\n // Parse the JSON and convert each entry from UserStorageContactEntry to AddressBookEntry\n const remoteStorageEntries = JSON.parse(\n remoteContactsJson,\n ) as UserStorageContactEntry[];\n return remoteStorageEntries.map((entry) =>\n mapUserStorageEntryToAddressBookEntry(entry),\n );\n } catch {\n return null;\n }\n}\n\n/**\n * Saves local contacts to user storage\n *\n * @param contacts - The contacts to save to user storage\n * @param options - Parameters used for saving contacts\n */\nasync function saveContactsToUserStorage(\n contacts: AddressBookEntry[],\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getUserStorageControllerInstance } = options;\n\n if (!contacts || contacts.length === 0) {\n return;\n }\n\n // Convert each AddressBookEntry to UserStorageContactEntry format before saving\n const storageEntries = contacts.map((contact) =>\n mapAddressBookEntryToUserStorageEntry(contact),\n );\n\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${ADDRESS_BOOK_CONTACTS_KEY}`,\n JSON.stringify(storageEntries),\n );\n}\n\n/**\n * Updates a single contact in remote storage without performing a full sync\n * This is used when a contact is updated locally to efficiently push changes to remote\n *\n * @param contact - The contact that was updated locally\n * @param options - Parameters used for syncing operations\n */\nexport async function updateContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n try {\n // Get current remote contacts or initialize empty array\n const remoteContacts = (await getRemoteContacts(options)) || [];\n\n // Find if this contact already exists in remote\n const key = createContactKey(contact);\n const existingIndex = remoteContacts.findIndex(\n (c) => createContactKey(c) === key,\n );\n\n const updatedRemoteContacts = [...remoteContacts];\n\n // Create an updated entry with timestamp\n const updatedEntry = {\n ...contact,\n lastUpdatedAt: contact.lastUpdatedAt || Date.now(),\n deleted: false, // Explicitly set to false in case this was previously deleted\n } as SyncAddressBookEntry;\n\n if (existingIndex !== -1) {\n // Update existing contact\n updatedRemoteContacts[existingIndex] = updatedEntry;\n } else {\n // Add as new contact\n updatedRemoteContacts.push(updatedEntry);\n }\n\n // Save to remote storage\n await saveContactsToUserStorage(updatedRemoteContacts, options);\n } catch (error) {\n console.error(\n '🔄 Contacts Sync: Error updating contact in remote storage',\n error,\n );\n }\n}\n\n/**\n * Marks a single contact as deleted in remote storage without performing a full sync\n * This is used when a contact is deleted locally to efficiently push the deletion to remote\n *\n * @param contact - The contact that was deleted locally (contains at least address and chainId)\n * @param options - Parameters used for syncing operations\n */\nexport async function deleteContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n try {\n // Get current remote contacts\n const remoteContacts = (await getRemoteContacts(options)) || [];\n\n // Find the contact in remote storage\n const key = createContactKey(contact);\n const existingIndex = remoteContacts.findIndex(\n (c) => createContactKey(c) === key,\n );\n\n // If the contact exists in remote storage\n if (existingIndex !== -1) {\n const updatedRemoteContacts = [...remoteContacts];\n const now = Date.now();\n\n // Mark the contact as deleted\n updatedRemoteContacts[existingIndex] = {\n ...updatedRemoteContacts[existingIndex],\n deleted: true,\n deletedAt: now,\n lastUpdatedAt: now,\n };\n\n // Save to remote storage\n await saveContactsToUserStorage(updatedRemoteContacts, options);\n }\n } catch (error) {\n console.error(\n '🔄 Contacts Sync: Error marking contact as deleted in remote storage',\n error,\n );\n }\n}\n"]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupContactSyncingSubscriptions = void 0;
4
+ const controller_integration_1 = require("./controller-integration.cjs");
5
+ const sync_utils_1 = require("./sync-utils.cjs");
6
+ /**
7
+ * Initialize and setup events to listen to for contact syncing
8
+ *
9
+ * @param options - parameters used for initializing and enabling contact syncing
10
+ */
11
+ function setupContactSyncingSubscriptions(options) {
12
+ const { getMessenger } = options;
13
+ // Listen for contact updates and immediately sync the individual contact
14
+ getMessenger().subscribe('AddressBookController:contactUpdated', (contactEntry) => {
15
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
16
+ (async () => {
17
+ if (!(0, sync_utils_1.canPerformContactSyncing)(options)) {
18
+ return;
19
+ }
20
+ // Skip global accounts with chainId "*" : they are contacts bridged from accounts
21
+ if (String(contactEntry.chainId) === '*') {
22
+ return;
23
+ }
24
+ try {
25
+ // Use the targeted method to update just this contact
26
+ await (0, controller_integration_1.updateContactInRemoteStorage)(contactEntry, options);
27
+ }
28
+ catch (error) {
29
+ console.error('Error updating contact in remote storage:', error);
30
+ }
31
+ })();
32
+ });
33
+ // Listen for contact deletions and immediately sync the individual deletion
34
+ getMessenger().subscribe('AddressBookController:contactDeleted', (contactEntry) => {
35
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
36
+ (async () => {
37
+ if (!(0, sync_utils_1.canPerformContactSyncing)(options)) {
38
+ return;
39
+ }
40
+ // Skip global accounts with chainId "*" : they are contacts bridged from accounts
41
+ if (String(contactEntry.chainId) === '*') {
42
+ return;
43
+ }
44
+ try {
45
+ // Use the targeted method to delete just this contact
46
+ await (0, controller_integration_1.deleteContactInRemoteStorage)(contactEntry, options);
47
+ }
48
+ catch (error) {
49
+ console.error('Error deleting contact from remote storage:', error);
50
+ }
51
+ })();
52
+ });
53
+ }
54
+ exports.setupContactSyncingSubscriptions = setupContactSyncingSubscriptions;
55
+ //# sourceMappingURL=setup-subscriptions.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-subscriptions.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/setup-subscriptions.ts"],"names":[],"mappings":";;;AAEA,yEAGkC;AAClC,iDAAwD;AAGxD;;;;GAIG;AACH,SAAgB,gCAAgC,CAC9C,OAA8B;IAE9B,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAEjC,yEAAyE;IACzE,YAAY,EAAE,CAAC,SAAS,CACtB,sCAAsC,EACtC,CAAC,YAA8B,EAAE,EAAE;QACjC,mEAAmE;QACnE,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC,IAAA,qCAAwB,EAAC,OAAO,CAAC,EAAE;gBACtC,OAAO;aACR;YAED,kFAAkF;YAClF,IAAI,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE;gBACxC,OAAO;aACR;YAED,IAAI;gBACF,sDAAsD;gBACtD,MAAM,IAAA,qDAA4B,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;aACnE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,YAAY,EAAE,CAAC,SAAS,CACtB,sCAAsC,EACtC,CAAC,YAA8B,EAAE,EAAE;QACjC,mEAAmE;QACnE,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC,IAAA,qCAAwB,EAAC,OAAO,CAAC,EAAE;gBACtC,OAAO;aACR;YAED,kFAAkF;YAClF,IAAI,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE;gBACxC,OAAO;aACR;YAED,IAAI;gBACF,sDAAsD;gBACtD,MAAM,IAAA,qDAA4B,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;aACrE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CACF,CAAC;AACJ,CAAC;AAtDD,4EAsDC","sourcesContent":["import type { AddressBookEntry } from '@metamask/address-book-controller';\n\nimport {\n updateContactInRemoteStorage,\n deleteContactInRemoteStorage,\n} from './controller-integration';\nimport { canPerformContactSyncing } from './sync-utils';\nimport type { ContactSyncingOptions } from './types';\n\n/**\n * Initialize and setup events to listen to for contact syncing\n *\n * @param options - parameters used for initializing and enabling contact syncing\n */\nexport function setupContactSyncingSubscriptions(\n options: ContactSyncingOptions,\n): void {\n const { getMessenger } = options;\n\n // Listen for contact updates and immediately sync the individual contact\n getMessenger().subscribe(\n 'AddressBookController:contactUpdated',\n (contactEntry: AddressBookEntry) => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n (async () => {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // Skip global accounts with chainId \"*\" : they are contacts bridged from accounts\n if (String(contactEntry.chainId) === '*') {\n return;\n }\n\n try {\n // Use the targeted method to update just this contact\n await updateContactInRemoteStorage(contactEntry, options);\n } catch (error) {\n console.error('Error updating contact in remote storage:', error);\n }\n })();\n },\n );\n\n // Listen for contact deletions and immediately sync the individual deletion\n getMessenger().subscribe(\n 'AddressBookController:contactDeleted',\n (contactEntry: AddressBookEntry) => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n (async () => {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // Skip global accounts with chainId \"*\" : they are contacts bridged from accounts\n if (String(contactEntry.chainId) === '*') {\n return;\n }\n\n try {\n // Use the targeted method to delete just this contact\n await deleteContactInRemoteStorage(contactEntry, options);\n } catch (error) {\n console.error('Error deleting contact from remote storage:', error);\n }\n })();\n },\n );\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ContactSyncingOptions } from "./types.cjs";
2
+ /**
3
+ * Initialize and setup events to listen to for contact syncing
4
+ *
5
+ * @param options - parameters used for initializing and enabling contact syncing
6
+ */
7
+ export declare function setupContactSyncingSubscriptions(options: ContactSyncingOptions): void;
8
+ //# sourceMappingURL=setup-subscriptions.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-subscriptions.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/setup-subscriptions.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAgB;AAErD;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CAoDN"}
@@ -0,0 +1,8 @@
1
+ import type { ContactSyncingOptions } from "./types.mjs";
2
+ /**
3
+ * Initialize and setup events to listen to for contact syncing
4
+ *
5
+ * @param options - parameters used for initializing and enabling contact syncing
6
+ */
7
+ export declare function setupContactSyncingSubscriptions(options: ContactSyncingOptions): void;
8
+ //# sourceMappingURL=setup-subscriptions.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-subscriptions.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/setup-subscriptions.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAgB;AAErD;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CAoDN"}
@@ -0,0 +1,51 @@
1
+ import { updateContactInRemoteStorage, deleteContactInRemoteStorage } from "./controller-integration.mjs";
2
+ import { canPerformContactSyncing } from "./sync-utils.mjs";
3
+ /**
4
+ * Initialize and setup events to listen to for contact syncing
5
+ *
6
+ * @param options - parameters used for initializing and enabling contact syncing
7
+ */
8
+ export function setupContactSyncingSubscriptions(options) {
9
+ const { getMessenger } = options;
10
+ // Listen for contact updates and immediately sync the individual contact
11
+ getMessenger().subscribe('AddressBookController:contactUpdated', (contactEntry) => {
12
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
13
+ (async () => {
14
+ if (!canPerformContactSyncing(options)) {
15
+ return;
16
+ }
17
+ // Skip global accounts with chainId "*" : they are contacts bridged from accounts
18
+ if (String(contactEntry.chainId) === '*') {
19
+ return;
20
+ }
21
+ try {
22
+ // Use the targeted method to update just this contact
23
+ await updateContactInRemoteStorage(contactEntry, options);
24
+ }
25
+ catch (error) {
26
+ console.error('Error updating contact in remote storage:', error);
27
+ }
28
+ })();
29
+ });
30
+ // Listen for contact deletions and immediately sync the individual deletion
31
+ getMessenger().subscribe('AddressBookController:contactDeleted', (contactEntry) => {
32
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
33
+ (async () => {
34
+ if (!canPerformContactSyncing(options)) {
35
+ return;
36
+ }
37
+ // Skip global accounts with chainId "*" : they are contacts bridged from accounts
38
+ if (String(contactEntry.chainId) === '*') {
39
+ return;
40
+ }
41
+ try {
42
+ // Use the targeted method to delete just this contact
43
+ await deleteContactInRemoteStorage(contactEntry, options);
44
+ }
45
+ catch (error) {
46
+ console.error('Error deleting contact from remote storage:', error);
47
+ }
48
+ })();
49
+ });
50
+ }
51
+ //# sourceMappingURL=setup-subscriptions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-subscriptions.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/setup-subscriptions.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC7B,qCAAiC;AAClC,OAAO,EAAE,wBAAwB,EAAE,yBAAqB;AAGxD;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAC9C,OAA8B;IAE9B,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAEjC,yEAAyE;IACzE,YAAY,EAAE,CAAC,SAAS,CACtB,sCAAsC,EACtC,CAAC,YAA8B,EAAE,EAAE;QACjC,mEAAmE;QACnE,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE;gBACtC,OAAO;aACR;YAED,kFAAkF;YAClF,IAAI,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE;gBACxC,OAAO;aACR;YAED,IAAI;gBACF,sDAAsD;gBACtD,MAAM,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;aACnE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,YAAY,EAAE,CAAC,SAAS,CACtB,sCAAsC,EACtC,CAAC,YAA8B,EAAE,EAAE;QACjC,mEAAmE;QACnE,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE;gBACtC,OAAO;aACR;YAED,kFAAkF;YAClF,IAAI,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE;gBACxC,OAAO;aACR;YAED,IAAI;gBACF,sDAAsD;gBACtD,MAAM,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;aACrE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import type { AddressBookEntry } from '@metamask/address-book-controller';\n\nimport {\n updateContactInRemoteStorage,\n deleteContactInRemoteStorage,\n} from './controller-integration';\nimport { canPerformContactSyncing } from './sync-utils';\nimport type { ContactSyncingOptions } from './types';\n\n/**\n * Initialize and setup events to listen to for contact syncing\n *\n * @param options - parameters used for initializing and enabling contact syncing\n */\nexport function setupContactSyncingSubscriptions(\n options: ContactSyncingOptions,\n): void {\n const { getMessenger } = options;\n\n // Listen for contact updates and immediately sync the individual contact\n getMessenger().subscribe(\n 'AddressBookController:contactUpdated',\n (contactEntry: AddressBookEntry) => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n (async () => {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // Skip global accounts with chainId \"*\" : they are contacts bridged from accounts\n if (String(contactEntry.chainId) === '*') {\n return;\n }\n\n try {\n // Use the targeted method to update just this contact\n await updateContactInRemoteStorage(contactEntry, options);\n } catch (error) {\n console.error('Error updating contact in remote storage:', error);\n }\n })();\n },\n );\n\n // Listen for contact deletions and immediately sync the individual deletion\n getMessenger().subscribe(\n 'AddressBookController:contactDeleted',\n (contactEntry: AddressBookEntry) => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n (async () => {\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // Skip global accounts with chainId \"*\" : they are contacts bridged from accounts\n if (String(contactEntry.chainId) === '*') {\n return;\n }\n\n try {\n // Use the targeted method to delete just this contact\n await deleteContactInRemoteStorage(contactEntry, options);\n } catch (error) {\n console.error('Error deleting contact from remote storage:', error);\n }\n })();\n },\n );\n}\n"]}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.canPerformContactSyncing = void 0;
4
+ /**
5
+ * Check if we can perform contact syncing
6
+ *
7
+ * @param options - parameters used for checking if we can perform contact syncing
8
+ * @returns whether we can perform contact syncing
9
+ */
10
+ function canPerformContactSyncing(options) {
11
+ const { getMessenger, getUserStorageControllerInstance } = options;
12
+ const { isBackupAndSyncEnabled, isContactSyncingEnabled, isContactSyncingInProgress, } = getUserStorageControllerInstance().state;
13
+ const isAuthEnabled = getMessenger().call('AuthenticationController:isSignedIn');
14
+ if (!isBackupAndSyncEnabled ||
15
+ !isContactSyncingEnabled ||
16
+ isContactSyncingInProgress ||
17
+ !isAuthEnabled) {
18
+ return false;
19
+ }
20
+ return true;
21
+ }
22
+ exports.canPerformContactSyncing = canPerformContactSyncing;
23
+ //# sourceMappingURL=sync-utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-utils.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/sync-utils.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,SAAgB,wBAAwB,CACtC,OAA8B;IAE9B,MAAM,EAAE,YAAY,EAAE,gCAAgC,EAAE,GAAG,OAAO,CAAC;IAEnE,MAAM,EACJ,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,GAC3B,GAAG,gCAAgC,EAAE,CAAC,KAAK,CAAC;IAC7C,MAAM,aAAa,GAAG,YAAY,EAAE,CAAC,IAAI,CACvC,qCAAqC,CACtC,CAAC;IAEF,IACE,CAAC,sBAAsB;QACvB,CAAC,uBAAuB;QACxB,0BAA0B;QAC1B,CAAC,aAAa,EACd;QACA,OAAO,KAAK,CAAC;KACd;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAxBD,4DAwBC","sourcesContent":["import type { ContactSyncingOptions } from './types';\n\n/**\n * Check if we can perform contact syncing\n *\n * @param options - parameters used for checking if we can perform contact syncing\n * @returns whether we can perform contact syncing\n */\nexport function canPerformContactSyncing(\n options: ContactSyncingOptions,\n): boolean {\n const { getMessenger, getUserStorageControllerInstance } = options;\n\n const {\n isBackupAndSyncEnabled,\n isContactSyncingEnabled,\n isContactSyncingInProgress,\n } = getUserStorageControllerInstance().state;\n const isAuthEnabled = getMessenger().call(\n 'AuthenticationController:isSignedIn',\n );\n\n if (\n !isBackupAndSyncEnabled ||\n !isContactSyncingEnabled ||\n isContactSyncingInProgress ||\n !isAuthEnabled\n ) {\n return false;\n }\n\n return true;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { ContactSyncingOptions } from "./types.cjs";
2
+ /**
3
+ * Check if we can perform contact syncing
4
+ *
5
+ * @param options - parameters used for checking if we can perform contact syncing
6
+ * @returns whether we can perform contact syncing
7
+ */
8
+ export declare function canPerformContactSyncing(options: ContactSyncingOptions): boolean;
9
+ //# sourceMappingURL=sync-utils.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-utils.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/sync-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAgB;AAErD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAsBT"}
@@ -0,0 +1,9 @@
1
+ import type { ContactSyncingOptions } from "./types.mjs";
2
+ /**
3
+ * Check if we can perform contact syncing
4
+ *
5
+ * @param options - parameters used for checking if we can perform contact syncing
6
+ * @returns whether we can perform contact syncing
7
+ */
8
+ export declare function canPerformContactSyncing(options: ContactSyncingOptions): boolean;
9
+ //# sourceMappingURL=sync-utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-utils.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/sync-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAgB;AAErD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAsBT"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Check if we can perform contact syncing
3
+ *
4
+ * @param options - parameters used for checking if we can perform contact syncing
5
+ * @returns whether we can perform contact syncing
6
+ */
7
+ export function canPerformContactSyncing(options) {
8
+ const { getMessenger, getUserStorageControllerInstance } = options;
9
+ const { isBackupAndSyncEnabled, isContactSyncingEnabled, isContactSyncingInProgress, } = getUserStorageControllerInstance().state;
10
+ const isAuthEnabled = getMessenger().call('AuthenticationController:isSignedIn');
11
+ if (!isBackupAndSyncEnabled ||
12
+ !isContactSyncingEnabled ||
13
+ isContactSyncingInProgress ||
14
+ !isAuthEnabled) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ //# sourceMappingURL=sync-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-utils.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/sync-utils.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA8B;IAE9B,MAAM,EAAE,YAAY,EAAE,gCAAgC,EAAE,GAAG,OAAO,CAAC;IAEnE,MAAM,EACJ,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,GAC3B,GAAG,gCAAgC,EAAE,CAAC,KAAK,CAAC;IAC7C,MAAM,aAAa,GAAG,YAAY,EAAE,CAAC,IAAI,CACvC,qCAAqC,CACtC,CAAC;IAEF,IACE,CAAC,sBAAsB;QACvB,CAAC,uBAAuB;QACxB,0BAA0B;QAC1B,CAAC,aAAa,EACd;QACA,OAAO,KAAK,CAAC;KACd;IAED,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { ContactSyncingOptions } from './types';\n\n/**\n * Check if we can perform contact syncing\n *\n * @param options - parameters used for checking if we can perform contact syncing\n * @returns whether we can perform contact syncing\n */\nexport function canPerformContactSyncing(\n options: ContactSyncingOptions,\n): boolean {\n const { getMessenger, getUserStorageControllerInstance } = options;\n\n const {\n isBackupAndSyncEnabled,\n isContactSyncingEnabled,\n isContactSyncingInProgress,\n } = getUserStorageControllerInstance().state;\n const isAuthEnabled = getMessenger().call(\n 'AuthenticationController:isSignedIn',\n );\n\n if (\n !isBackupAndSyncEnabled ||\n !isContactSyncingEnabled ||\n isContactSyncingInProgress ||\n !isAuthEnabled\n ) {\n return false;\n }\n\n return true;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Hex } from '@metamask/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 UserStorageContactEntry = {\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 address 'a' of the contact */\n a: string;\n /** the name 'n' of the contact */\n n: string;\n /** the chainId 'c' of the contact */\n c: Hex;\n /** the memo 'm' of the contact (optional) */\n m?: string;\n /** the addressType 't' of the contact (optional) */\n t?: string;\n /** the lastUpdatedAt timestamp 'lu' of the contact */\n lu?: number;\n /** the deleted flag 'd' of the contact (optional) */\n d?: boolean;\n /** the deletedAt timestamp 'dt' of the contact (optional) */\n dt?: number;\n};\n\n/**\n * Options for contact syncing operations\n */\nexport type ContactSyncingOptions = {\n getUserStorageControllerInstance: () => UserStorageController;\n getMessenger: () => UserStorageControllerMessenger;\n};\n"]}
@@ -0,0 +1,35 @@
1
+ import type { Hex } from "@metamask/utils";
2
+ import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.cjs";
3
+ import type { UserStorageControllerMessenger } from "../UserStorageController.cjs";
4
+ import type UserStorageController from "../UserStorageController.cjs";
5
+ export type UserStorageContactEntry = {
6
+ /**
7
+ * The Version 'v' of the User Storage.
8
+ * NOTE - will allow us to support upgrade/downgrades in the future
9
+ */
10
+ [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION;
11
+ /** the address 'a' of the contact */
12
+ a: string;
13
+ /** the name 'n' of the contact */
14
+ n: string;
15
+ /** the chainId 'c' of the contact */
16
+ c: Hex;
17
+ /** the memo 'm' of the contact (optional) */
18
+ m?: string;
19
+ /** the addressType 't' of the contact (optional) */
20
+ t?: string;
21
+ /** the lastUpdatedAt timestamp 'lu' of the contact */
22
+ lu?: number;
23
+ /** the deleted flag 'd' of the contact (optional) */
24
+ d?: boolean;
25
+ /** the deletedAt timestamp 'dt' of the contact (optional) */
26
+ dt?: number;
27
+ };
28
+ /**
29
+ * Options for contact syncing operations
30
+ */
31
+ export type ContactSyncingOptions = {
32
+ getUserStorageControllerInstance: () => UserStorageController;
33
+ getMessenger: () => UserStorageControllerMessenger;
34
+ };
35
+ //# sourceMappingURL=types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AACrB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,qBAAqB,qCAAiC;AAElE,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,CAAC,wBAAwB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxD,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,GAAG,CAAC;IACP,6CAA6C;IAC7C,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,CAAC,CAAC,EAAE,OAAO,CAAC;IACZ,6DAA6D;IAC7D,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;IAC9D,YAAY,EAAE,MAAM,8BAA8B,CAAC;CACpD,CAAC"}