@metamask-previews/profile-sync-controller 19.0.0-preview-0d7196ba → 20.0.0-preview-988fbb56

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 (116) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/dist/controllers/authentication/AuthenticationController.cjs +5 -0
  3. package/dist/controllers/authentication/AuthenticationController.cjs.map +1 -1
  4. package/dist/controllers/authentication/AuthenticationController.d.cts +4 -2
  5. package/dist/controllers/authentication/AuthenticationController.d.cts.map +1 -1
  6. package/dist/controllers/authentication/AuthenticationController.d.mts +4 -2
  7. package/dist/controllers/authentication/AuthenticationController.d.mts.map +1 -1
  8. package/dist/controllers/authentication/AuthenticationController.mjs +5 -0
  9. package/dist/controllers/authentication/AuthenticationController.mjs.map +1 -1
  10. package/dist/controllers/user-storage/UserStorageController.cjs +11 -4
  11. package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
  12. package/dist/controllers/user-storage/UserStorageController.d.cts +4 -2
  13. package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
  14. package/dist/controllers/user-storage/UserStorageController.d.mts +4 -2
  15. package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
  16. package/dist/controllers/user-storage/UserStorageController.mjs +11 -4
  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/index.cjs +18 -0
  33. package/dist/controllers/user-storage/constants/index.cjs.map +1 -0
  34. package/dist/controllers/user-storage/constants/index.d.cts +2 -0
  35. package/dist/controllers/user-storage/constants/index.d.cts.map +1 -0
  36. package/dist/controllers/user-storage/constants/index.d.mts +2 -0
  37. package/dist/controllers/user-storage/constants/index.d.mts.map +1 -0
  38. package/dist/controllers/user-storage/constants/index.mjs +2 -0
  39. package/dist/controllers/user-storage/constants/index.mjs.map +1 -0
  40. package/dist/controllers/user-storage/constants/traces.cjs +17 -0
  41. package/dist/controllers/user-storage/constants/traces.cjs.map +1 -0
  42. package/dist/controllers/user-storage/constants/traces.d.cts +12 -0
  43. package/dist/controllers/user-storage/constants/traces.d.cts.map +1 -0
  44. package/dist/controllers/user-storage/constants/traces.d.mts +12 -0
  45. package/dist/controllers/user-storage/constants/traces.d.mts.map +1 -0
  46. package/dist/controllers/user-storage/constants/traces.mjs +14 -0
  47. package/dist/controllers/user-storage/constants/traces.mjs.map +1 -0
  48. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs +224 -162
  49. package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs.map +1 -1
  50. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts +3 -0
  51. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts.map +1 -1
  52. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts +3 -0
  53. package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts.map +1 -1
  54. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs +224 -162
  55. package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs.map +1 -1
  56. package/dist/controllers/user-storage/contact-syncing/types.cjs.map +1 -1
  57. package/dist/controllers/user-storage/contact-syncing/types.d.cts +2 -0
  58. package/dist/controllers/user-storage/contact-syncing/types.d.cts.map +1 -1
  59. package/dist/controllers/user-storage/contact-syncing/types.d.mts +2 -0
  60. package/dist/controllers/user-storage/contact-syncing/types.d.mts.map +1 -1
  61. package/dist/controllers/user-storage/contact-syncing/types.mjs.map +1 -1
  62. package/dist/controllers/user-storage/index.cjs +1 -1
  63. package/dist/controllers/user-storage/index.cjs.map +1 -1
  64. package/dist/controllers/user-storage/index.d.cts +1 -1
  65. package/dist/controllers/user-storage/index.d.cts.map +1 -1
  66. package/dist/controllers/user-storage/index.d.mts +1 -1
  67. package/dist/controllers/user-storage/index.d.mts.map +1 -1
  68. package/dist/controllers/user-storage/index.mjs +1 -1
  69. package/dist/controllers/user-storage/index.mjs.map +1 -1
  70. package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs +4 -0
  71. package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs.map +1 -1
  72. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.cts +2 -1
  73. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.cts.map +1 -1
  74. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.mts +2 -1
  75. package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.mts.map +1 -1
  76. package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs +5 -1
  77. package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs.map +1 -1
  78. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs +4 -0
  79. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs.map +1 -1
  80. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts +2 -1
  81. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts.map +1 -1
  82. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts +2 -1
  83. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts.map +1 -1
  84. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs +5 -1
  85. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs.map +1 -1
  86. package/dist/sdk/authentication-jwt-bearer/services.cjs +33 -1
  87. package/dist/sdk/authentication-jwt-bearer/services.cjs.map +1 -1
  88. package/dist/sdk/authentication-jwt-bearer/services.d.cts +10 -1
  89. package/dist/sdk/authentication-jwt-bearer/services.d.cts.map +1 -1
  90. package/dist/sdk/authentication-jwt-bearer/services.d.mts +10 -1
  91. package/dist/sdk/authentication-jwt-bearer/services.d.mts.map +1 -1
  92. package/dist/sdk/authentication-jwt-bearer/services.mjs +30 -0
  93. package/dist/sdk/authentication-jwt-bearer/services.mjs.map +1 -1
  94. package/dist/sdk/authentication-jwt-bearer/types.cjs.map +1 -1
  95. package/dist/sdk/authentication-jwt-bearer/types.d.cts +11 -0
  96. package/dist/sdk/authentication-jwt-bearer/types.d.cts.map +1 -1
  97. package/dist/sdk/authentication-jwt-bearer/types.d.mts +11 -0
  98. package/dist/sdk/authentication-jwt-bearer/types.d.mts.map +1 -1
  99. package/dist/sdk/authentication-jwt-bearer/types.mjs.map +1 -1
  100. package/dist/sdk/authentication.cjs +3 -0
  101. package/dist/sdk/authentication.cjs.map +1 -1
  102. package/dist/sdk/authentication.d.cts +2 -1
  103. package/dist/sdk/authentication.d.cts.map +1 -1
  104. package/dist/sdk/authentication.d.mts +2 -1
  105. package/dist/sdk/authentication.d.mts.map +1 -1
  106. package/dist/sdk/authentication.mjs +3 -0
  107. package/dist/sdk/authentication.mjs.map +1 -1
  108. package/dist/sdk/mocks/auth.cjs +22 -1
  109. package/dist/sdk/mocks/auth.cjs.map +1 -1
  110. package/dist/sdk/mocks/auth.d.cts +13 -0
  111. package/dist/sdk/mocks/auth.d.cts.map +1 -1
  112. package/dist/sdk/mocks/auth.d.mts +13 -0
  113. package/dist/sdk/mocks/auth.d.mts.map +1 -1
  114. package/dist/sdk/mocks/auth.mjs +23 -2
  115. package/dist/sdk/mocks/auth.mjs.map +1 -1
  116. package/package.json +6 -6
@@ -0,0 +1,2 @@
1
+ export * from "./traces.mjs";
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/constants/index.ts"],"names":[],"mappings":"AAAA,6BAAyB","sourcesContent":["export * from './traces';\n"]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TraceName = void 0;
4
+ /**
5
+ * Trace names for UserStorage syncing operations
6
+ */
7
+ exports.TraceName = {
8
+ // Contact syncing traces
9
+ ContactSyncFull: 'Contact Sync Full',
10
+ ContactSyncSaveBatch: 'Contact Sync Save Batch',
11
+ ContactSyncUpdateRemote: 'Contact Sync Update Remote',
12
+ ContactSyncDeleteRemote: 'Contact Sync Delete Remote',
13
+ // Account syncing traces
14
+ AccountSyncFull: 'Account Sync Full',
15
+ AccountSyncSaveIndividual: 'Account Sync Save Individual',
16
+ };
17
+ //# sourceMappingURL=traces.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/constants/traces.ts"],"names":[],"mappings":";;;AAAA;;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":["/**\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"]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Trace names for UserStorage syncing operations
3
+ */
4
+ export declare const TraceName: {
5
+ readonly ContactSyncFull: "Contact Sync Full";
6
+ readonly ContactSyncSaveBatch: "Contact Sync Save Batch";
7
+ readonly ContactSyncUpdateRemote: "Contact Sync Update Remote";
8
+ readonly ContactSyncDeleteRemote: "Contact Sync Delete Remote";
9
+ readonly AccountSyncFull: "Account Sync Full";
10
+ readonly AccountSyncSaveIndividual: "Account Sync Save Individual";
11
+ };
12
+ //# sourceMappingURL=traces.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/constants/traces.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;CAUZ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Trace names for UserStorage syncing operations
3
+ */
4
+ export declare const TraceName: {
5
+ readonly ContactSyncFull: "Contact Sync Full";
6
+ readonly ContactSyncSaveBatch: "Contact Sync Save Batch";
7
+ readonly ContactSyncUpdateRemote: "Contact Sync Update Remote";
8
+ readonly ContactSyncDeleteRemote: "Contact Sync Delete Remote";
9
+ readonly AccountSyncFull: "Account Sync Full";
10
+ readonly AccountSyncSaveIndividual: "Account Sync Save Individual";
11
+ };
12
+ //# sourceMappingURL=traces.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/constants/traces.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;CAUZ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Trace names for UserStorage syncing operations
3
+ */
4
+ export const TraceName = {
5
+ // Contact syncing traces
6
+ ContactSyncFull: 'Contact Sync Full',
7
+ ContactSyncSaveBatch: 'Contact Sync Save Batch',
8
+ ContactSyncUpdateRemote: 'Contact Sync Update Remote',
9
+ ContactSyncDeleteRemote: 'Contact Sync Delete Remote',
10
+ // Account syncing traces
11
+ AccountSyncFull: 'Account Sync Full',
12
+ AccountSyncSaveIndividual: 'Account Sync Save Individual',
13
+ };
14
+ //# sourceMappingURL=traces.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/constants/traces.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,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":["/**\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"]}
@@ -5,6 +5,7 @@ const sync_utils_1 = require("./sync-utils.cjs");
5
5
  const utils_1 = require("./utils.cjs");
6
6
  const utils_2 = require("./utils.cjs");
7
7
  const storage_schema_1 = require("../../../shared/storage-schema.cjs");
8
+ const traces_1 = require("../constants/traces.cjs");
8
9
  /**
9
10
  * Creates a unique key for a contact based on chainId and address
10
11
  *
@@ -35,138 +36,160 @@ function createContactKey(contact) {
35
36
  *
36
37
  * @param config - Parameters used for syncing callbacks
37
38
  * @param options - Parameters used for syncing operations
39
+ * @returns Promise that resolves when contact synchronization is complete
38
40
  */
39
41
  async function syncContactsWithUserStorage(config, options) {
40
- const { getMessenger, getUserStorageControllerInstance } = options;
42
+ const { getMessenger, getUserStorageControllerInstance, trace } = options;
41
43
  const { onContactSyncErroneousSituation, onContactUpdated, onContactDeleted, } = config;
42
- try {
43
- // Cannot perform sync, conditions not met
44
- if (!(0, sync_utils_1.canPerformContactSyncing)(options)) {
45
- return;
46
- }
47
- // Activate sync semaphore to prevent event loops
48
- await getUserStorageControllerInstance().setIsContactSyncingInProgress(true);
49
- // Get all local contacts from AddressBookController (exclude chain "*" contacts)
50
- const localVisibleContacts = getMessenger()
51
- .call('AddressBookController:list')
52
- .filter((contact) => !(0, utils_2.isContactBridgedFromAccounts)(contact))
53
- .filter((contact) => contact.address && contact.chainId && contact.name?.trim()) || [];
54
- // Get remote contacts from user storage API
55
- const remoteContacts = await getRemoteContacts(options);
56
- // Filter remote contacts to exclude invalid ones (or empty array if no remote contacts)
57
- const validRemoteContacts = remoteContacts?.filter((contact) => contact.address && contact.chainId && contact.name?.trim()) || [];
58
- // Prepare maps for efficient lookup
59
- const localContactsMap = new Map();
60
- const remoteContactsMap = new Map();
61
- localVisibleContacts.forEach((contact) => {
62
- const key = createContactKey(contact);
63
- localContactsMap.set(key, contact);
64
- });
65
- validRemoteContacts.forEach((contact) => {
66
- const key = createContactKey(contact);
67
- remoteContactsMap.set(key, contact);
68
- });
69
- // Lists to track contacts that need to be synced
70
- const contactsToAddOrUpdateLocally = [];
71
- const contactsToDeleteLocally = [];
72
- const contactsToUpdateRemotely = [];
73
- // SCENARIO 2 & 6: Process remote contacts - handle new device sync and remote updates
74
- for (const remoteContact of validRemoteContacts) {
75
- const key = createContactKey(remoteContact);
76
- const localContact = localContactsMap.get(key);
77
- // Handle remote contact based on its status and local existence
78
- if (remoteContact.deletedAt) {
79
- // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally
80
- if (localContact) {
81
- contactsToDeleteLocally.push(remoteContact);
82
- }
83
- }
84
- else if (!localContact) {
85
- // SCENARIO 2: New contact from remote - import to local
86
- contactsToAddOrUpdateLocally.push(remoteContact);
87
- }
88
- else {
89
- // SCENARIO 4 & 6: Contact exists on both sides - check for conflicts
90
- const hasContentDifference = localContact.name !== remoteContact.name ||
91
- localContact.memo !== remoteContact.memo;
92
- if (hasContentDifference) {
93
- // Check timestamps to determine which version to keep
94
- const localTimestamp = localContact.lastUpdatedAt || 0;
95
- const remoteTimestamp = remoteContact.lastUpdatedAt || 0;
96
- if (localTimestamp >= remoteTimestamp) {
97
- // Local is newer (or same age) - use local version
98
- contactsToUpdateRemotely.push(localContact);
44
+ // Cannot perform sync, conditions not met
45
+ if (!(0, sync_utils_1.canPerformContactSyncing)(options)) {
46
+ return;
47
+ }
48
+ // Get all local contacts from AddressBookController (exclude chain "*" contacts)
49
+ const localVisibleContacts = getMessenger()
50
+ .call('AddressBookController:list')
51
+ .filter((contact) => !(0, utils_2.isContactBridgedFromAccounts)(contact))
52
+ .filter((contact) => contact.address && contact.chainId && contact.name?.trim()) || [];
53
+ // Get remote contacts from user storage API
54
+ const remoteContacts = await getRemoteContacts(options);
55
+ // Filter remote contacts to exclude invalid ones (or empty array if no remote contacts)
56
+ const validRemoteContacts = remoteContacts?.filter((contact) => contact.address && contact.chainId && contact.name?.trim()) || [];
57
+ const performSync = async () => {
58
+ try {
59
+ // Activate sync semaphore to prevent event loops
60
+ await getUserStorageControllerInstance().setIsContactSyncingInProgress(true);
61
+ // Prepare maps for efficient lookup
62
+ const localContactsMap = new Map();
63
+ const remoteContactsMap = new Map();
64
+ localVisibleContacts.forEach((contact) => {
65
+ const key = createContactKey(contact);
66
+ localContactsMap.set(key, contact);
67
+ });
68
+ validRemoteContacts.forEach((contact) => {
69
+ const key = createContactKey(contact);
70
+ remoteContactsMap.set(key, contact);
71
+ });
72
+ // Lists to track contacts that need to be synced
73
+ const contactsToAddOrUpdateLocally = [];
74
+ const contactsToDeleteLocally = [];
75
+ const contactsToUpdateRemotely = [];
76
+ // SCENARIO 2 & 6: Process remote contacts - handle new device sync and remote updates
77
+ for (const remoteContact of validRemoteContacts) {
78
+ const key = createContactKey(remoteContact);
79
+ const localContact = localContactsMap.get(key);
80
+ // Handle remote contact based on its status and local existence
81
+ if (remoteContact.deletedAt) {
82
+ // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally
83
+ if (localContact) {
84
+ contactsToDeleteLocally.push(remoteContact);
99
85
  }
100
- else {
101
- // Remote is newer - use remote version
102
- contactsToAddOrUpdateLocally.push(remoteContact);
86
+ }
87
+ else if (!localContact) {
88
+ // SCENARIO 2: New contact from remote - import to local
89
+ contactsToAddOrUpdateLocally.push(remoteContact);
90
+ }
91
+ else {
92
+ // SCENARIO 4 & 6: Contact exists on both sides - check for conflicts
93
+ const hasContentDifference = localContact.name !== remoteContact.name ||
94
+ localContact.memo !== remoteContact.memo;
95
+ if (hasContentDifference) {
96
+ // Check timestamps to determine which version to keep
97
+ const localTimestamp = localContact.lastUpdatedAt || 0;
98
+ const remoteTimestamp = remoteContact.lastUpdatedAt || 0;
99
+ if (localTimestamp >= remoteTimestamp) {
100
+ // Local is newer (or same age) - use local version
101
+ contactsToUpdateRemotely.push(localContact);
102
+ }
103
+ else {
104
+ // Remote is newer - use remote version
105
+ contactsToAddOrUpdateLocally.push(remoteContact);
106
+ }
103
107
  }
108
+ // Else: content is identical, no action needed
104
109
  }
105
- // Else: content is identical, no action needed
106
110
  }
107
- }
108
- // SCENARIO 1, 3 & 5: Process local contacts not in remote - handles first sync and new local contacts
109
- for (const localContact of localVisibleContacts) {
110
- const key = createContactKey(localContact);
111
- const remoteContact = remoteContactsMap.get(key);
112
- if (!remoteContact) {
113
- // New local contact or first sync - add to remote
114
- contactsToUpdateRemotely.push(localContact);
111
+ // SCENARIO 1, 3 & 5: Process local contacts not in remote - handles first sync and new local contacts
112
+ for (const localContact of localVisibleContacts) {
113
+ const key = createContactKey(localContact);
114
+ const remoteContact = remoteContactsMap.get(key);
115
+ if (!remoteContact) {
116
+ // New local contact or first sync - add to remote
117
+ contactsToUpdateRemotely.push(localContact);
118
+ }
115
119
  }
116
- }
117
- // Apply local deletions
118
- for (const contact of contactsToDeleteLocally) {
119
- try {
120
+ // Apply local deletions
121
+ // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry
122
+ // for debugging. Previous versions silently suppressed these errors which made
123
+ // troubleshooting contact sync issues difficult.
124
+ for (const contact of contactsToDeleteLocally) {
120
125
  getMessenger().call('AddressBookController:delete', contact.chainId, contact.address);
121
126
  if (onContactDeleted) {
122
127
  onContactDeleted();
123
128
  }
124
129
  }
125
- catch (error) {
126
- console.error('Error deleting contact:', error);
127
- }
128
- }
129
- // Apply local additions/updates
130
- for (const contact of contactsToAddOrUpdateLocally) {
131
- if (!contact.deletedAt) {
132
- try {
130
+ // Apply local additions/updates
131
+ // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry
132
+ // for debugging. Previous versions silently suppressed these errors which made
133
+ // troubleshooting contact sync issues difficult.
134
+ for (const contact of contactsToAddOrUpdateLocally) {
135
+ if (!contact.deletedAt) {
133
136
  getMessenger().call('AddressBookController:set', contact.address, contact.name || '', contact.chainId, contact.memo || '', contact.addressType);
134
137
  if (onContactUpdated) {
135
138
  onContactUpdated();
136
139
  }
137
140
  }
138
- catch (error) {
139
- console.error('Error updating contact:', error);
141
+ }
142
+ // Apply changes to remote storage
143
+ if (contactsToUpdateRemotely.length > 0) {
144
+ const updatedRemoteContacts = {};
145
+ for (const localContact of contactsToUpdateRemotely) {
146
+ const key = createContactKey(localContact);
147
+ updatedRemoteContacts[key] = {
148
+ ...remoteContactsMap.get(key),
149
+ ...localContact,
150
+ lastUpdatedAt: Date.now(), // mark as updated
151
+ };
140
152
  }
153
+ // Save updated contacts to remote storage
154
+ await saveContactsToUserStorage(Object.values(updatedRemoteContacts), options);
141
155
  }
142
156
  }
143
- // Apply changes to remote storage
144
- if (contactsToUpdateRemotely.length > 0) {
145
- const updatedRemoteContacts = {};
146
- for (const localContact of contactsToUpdateRemotely) {
147
- const key = createContactKey(localContact);
148
- updatedRemoteContacts[key] = {
149
- ...remoteContactsMap.get(key),
150
- ...localContact,
151
- lastUpdatedAt: Date.now(), // mark as updated
152
- };
157
+ catch (error) {
158
+ if (onContactSyncErroneousSituation) {
159
+ onContactSyncErroneousSituation('Error synchronizing contacts', {
160
+ error,
161
+ });
162
+ // Re-throw the error to be handled by the caller
163
+ throw error;
153
164
  }
154
- // Save updated contacts to remote storage
155
- await saveContactsToUserStorage(Object.values(updatedRemoteContacts), options);
156
165
  }
157
- }
158
- catch (error) {
159
- if (onContactSyncErroneousSituation) {
160
- onContactSyncErroneousSituation('Error synchronizing contacts', {
161
- error,
162
- });
163
- // Re-throw the error to be handled by the caller
164
- throw error;
166
+ finally {
167
+ await getUserStorageControllerInstance().setIsContactSyncingInProgress(false);
165
168
  }
169
+ };
170
+ if (trace) {
171
+ // Gather pre-sync metrics for performance analysis
172
+ const initialLocalContacts = localVisibleContacts;
173
+ const initialValidRemoteContacts = validRemoteContacts;
174
+ await trace({
175
+ name: traces_1.TraceName.ContactSyncFull,
176
+ data: {
177
+ localContactCount: initialLocalContacts.length,
178
+ remoteContactCount: initialValidRemoteContacts.length,
179
+ isFirstSync: initialValidRemoteContacts.length === 0 &&
180
+ initialLocalContacts.length > 0,
181
+ isNewDeviceSync: initialLocalContacts.length === 0 &&
182
+ initialValidRemoteContacts.length > 0,
183
+ isRegularSync: initialLocalContacts.length > 0 &&
184
+ initialValidRemoteContacts.length > 0,
185
+ hasDataToSync: initialLocalContacts.length > 0 ||
186
+ initialValidRemoteContacts.length > 0,
187
+ expectedWorkload: initialLocalContacts.length + initialValidRemoteContacts.length,
188
+ },
189
+ }, performSync);
190
+ return;
166
191
  }
167
- finally {
168
- await getUserStorageControllerInstance().setIsContactSyncingInProgress(false);
169
- }
192
+ await performSync();
170
193
  }
171
194
  exports.syncContactsWithUserStorage = syncContactsWithUserStorage;
172
195
  /**
@@ -198,19 +221,34 @@ async function getRemoteContacts(options) {
198
221
  *
199
222
  * @param contacts - The contacts to save to user storage
200
223
  * @param options - Parameters used for saving contacts
224
+ * @returns Promise that resolves when contacts are saved
201
225
  */
202
226
  async function saveContactsToUserStorage(contacts, options) {
203
- const { getUserStorageControllerInstance } = options;
204
- if (!contacts || contacts.length === 0) {
205
- return;
206
- }
207
- // Convert each AddressBookEntry to UserStorageContactEntry format and create key-value pairs
208
- const storageEntries = contacts.map((contact) => {
209
- const key = createContactKey(contact);
210
- const storageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(contact);
211
- return [key, JSON.stringify(storageEntry)];
212
- });
213
- await getUserStorageControllerInstance().performBatchSetStorage(storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook, storageEntries);
227
+ const { getUserStorageControllerInstance, trace } = options;
228
+ const saveContacts = async () => {
229
+ if (!contacts || contacts.length === 0) {
230
+ return;
231
+ }
232
+ // Convert each AddressBookEntry to UserStorageContactEntry format and create key-value pairs
233
+ const storageEntries = contacts.map((contact) => {
234
+ const key = createContactKey(contact);
235
+ const storageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(contact);
236
+ return [key, JSON.stringify(storageEntry)];
237
+ });
238
+ await getUserStorageControllerInstance().performBatchSetStorage(storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook, storageEntries);
239
+ };
240
+ return trace
241
+ ? await trace({
242
+ name: traces_1.TraceName.ContactSyncSaveBatch,
243
+ data: {
244
+ contactCount: contacts.length,
245
+ // Performance scaling indicators
246
+ hasBatchOperations: contacts.length > 1,
247
+ chainCount: new Set(contacts.map((c) => c.chainId)).size,
248
+ hasMemosCount: contacts.filter((c) => c.memo?.length).length,
249
+ },
250
+ }, saveContacts)
251
+ : await saveContacts();
214
252
  }
215
253
  /**
216
254
  * Updates a single contact in remote storage without performing a full sync
@@ -218,24 +256,41 @@ async function saveContactsToUserStorage(contacts, options) {
218
256
  *
219
257
  * @param contact - The contact that was updated locally
220
258
  * @param options - Parameters used for syncing operations
259
+ * @returns Promise that resolves when the contact is updated
221
260
  */
222
261
  async function updateContactInRemoteStorage(contact, options) {
223
- if (!(0, sync_utils_1.canPerformContactSyncing)(options) ||
224
- !contact.address ||
225
- !contact.chainId ||
226
- !contact.name?.trim()) {
227
- return;
228
- }
229
- const { getUserStorageControllerInstance } = options;
230
- // Create an updated entry with timestamp
231
- const updatedEntry = {
232
- ...contact,
233
- lastUpdatedAt: contact.lastUpdatedAt || Date.now(),
262
+ const { trace } = options;
263
+ const updateContact = async () => {
264
+ if (!(0, sync_utils_1.canPerformContactSyncing)(options) ||
265
+ !contact.address ||
266
+ !contact.chainId ||
267
+ !contact.name?.trim()) {
268
+ return;
269
+ }
270
+ const { getUserStorageControllerInstance } = options;
271
+ // Create an updated entry with timestamp
272
+ const updatedEntry = {
273
+ ...contact,
274
+ lastUpdatedAt: contact.lastUpdatedAt || Date.now(),
275
+ };
276
+ const key = createContactKey(contact);
277
+ const storageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(updatedEntry);
278
+ // Save individual contact to remote storage
279
+ await getUserStorageControllerInstance().performSetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`, JSON.stringify(storageEntry));
234
280
  };
235
- const key = createContactKey(contact);
236
- const storageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(updatedEntry);
237
- // Save individual contact to remote storage
238
- await getUserStorageControllerInstance().performSetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`, JSON.stringify(storageEntry));
281
+ if (trace) {
282
+ return await trace({
283
+ name: traces_1.TraceName.ContactSyncUpdateRemote,
284
+ data: {
285
+ chainId: contact.chainId,
286
+ // Performance indicators
287
+ hasTimestamp: Boolean(contact.lastUpdatedAt),
288
+ hasMemo: Boolean(contact.memo?.length),
289
+ isUpdate: Boolean(contact.lastUpdatedAt), // vs new contact
290
+ },
291
+ }, updateContact);
292
+ }
293
+ return await updateContact();
239
294
  }
240
295
  exports.updateContactInRemoteStorage = updateContactInRemoteStorage;
241
296
  /**
@@ -244,38 +299,45 @@ exports.updateContactInRemoteStorage = updateContactInRemoteStorage;
244
299
  *
245
300
  * @param contact - The contact that was deleted locally (contains at least address and chainId)
246
301
  * @param options - Parameters used for syncing operations
302
+ * @returns Promise that resolves when the contact is marked as deleted
247
303
  */
248
304
  async function deleteContactInRemoteStorage(contact, options) {
249
- if (!(0, sync_utils_1.canPerformContactSyncing)(options) ||
250
- !contact.address ||
251
- !contact.chainId ||
252
- !contact.name?.trim()) {
253
- return;
254
- }
255
- const { getUserStorageControllerInstance } = options;
256
- const key = createContactKey(contact);
257
- try {
258
- // Try to get the existing contact first
259
- const existingContactJson = await getUserStorageControllerInstance().performGetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`);
260
- if (existingContactJson) {
261
- // Mark the existing contact as deleted
262
- const existingStorageEntry = JSON.parse(existingContactJson);
263
- const existingContact = (0, utils_1.mapUserStorageEntryToAddressBookEntry)(existingStorageEntry);
264
- const now = Date.now();
265
- const deletedContact = {
266
- ...existingContact,
267
- deletedAt: now,
268
- lastUpdatedAt: now,
269
- };
270
- const deletedStorageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(deletedContact);
271
- // Save the deleted contact back to storage
272
- await getUserStorageControllerInstance().performSetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`, JSON.stringify(deletedStorageEntry));
305
+ const { trace } = options;
306
+ const deleteContact = async () => {
307
+ if (!(0, sync_utils_1.canPerformContactSyncing)(options) ||
308
+ !contact.address ||
309
+ !contact.chainId ||
310
+ !contact.name?.trim()) {
311
+ return;
273
312
  }
274
- }
275
- catch {
276
- // If contact doesn't exist in remote storage, no need to mark as deleted
277
- console.warn('Contact not found in remote storage for deletion:', key);
278
- }
313
+ const { getUserStorageControllerInstance } = options;
314
+ const key = createContactKey(contact);
315
+ try {
316
+ // Try to get the existing contact first
317
+ const existingContactJson = await getUserStorageControllerInstance().performGetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`);
318
+ if (existingContactJson) {
319
+ // Mark the existing contact as deleted
320
+ const existingStorageEntry = JSON.parse(existingContactJson);
321
+ const existingContact = (0, utils_1.mapUserStorageEntryToAddressBookEntry)(existingStorageEntry);
322
+ const now = Date.now();
323
+ const deletedContact = {
324
+ ...existingContact,
325
+ deletedAt: now,
326
+ lastUpdatedAt: now,
327
+ };
328
+ const deletedStorageEntry = (0, utils_1.mapAddressBookEntryToUserStorageEntry)(deletedContact);
329
+ // Save the deleted contact back to storage
330
+ await getUserStorageControllerInstance().performSetStorage(`${storage_schema_1.USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`, JSON.stringify(deletedStorageEntry));
331
+ }
332
+ }
333
+ catch {
334
+ // If contact doesn't exist in remote storage, no need to mark as deleted
335
+ console.warn('Contact not found in remote storage for deletion:', key);
336
+ }
337
+ };
338
+ return trace
339
+ ? await trace({ name: traces_1.TraceName.ContactSyncDeleteRemote }, deleteContact)
340
+ : await deleteContact();
279
341
  }
280
342
  exports.deleteContactInRemoteStorage = deleteContactInRemoteStorage;
281
343
  //# sourceMappingURL=controller-integration.cjs.map