@metamask/profile-sync-controller 28.0.2 → 28.1.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.
- package/CHANGELOG.md +30 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.cjs.map +1 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.cts +45 -6
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.cts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.mts +45 -6
- package/dist/controllers/authentication/AuthenticationController-method-action-types.d.mts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController-method-action-types.mjs.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.cjs +170 -8
- package/dist/controllers/authentication/AuthenticationController.cjs.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.d.cts +62 -8
- package/dist/controllers/authentication/AuthenticationController.d.cts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.d.mts +62 -8
- package/dist/controllers/authentication/AuthenticationController.d.mts.map +1 -1
- package/dist/controllers/authentication/AuthenticationController.mjs +170 -8
- package/dist/controllers/authentication/AuthenticationController.mjs.map +1 -1
- package/dist/controllers/authentication/index.cjs.map +1 -1
- package/dist/controllers/authentication/index.d.cts +1 -1
- package/dist/controllers/authentication/index.d.cts.map +1 -1
- package/dist/controllers/authentication/index.d.mts +1 -1
- package/dist/controllers/authentication/index.d.mts.map +1 -1
- package/dist/controllers/authentication/index.mjs.map +1 -1
- package/dist/controllers/authentication/mocks/mockResponses.cjs +10 -1
- package/dist/controllers/authentication/mocks/mockResponses.cjs.map +1 -1
- package/dist/controllers/authentication/mocks/mockResponses.d.cts +17 -32
- package/dist/controllers/authentication/mocks/mockResponses.d.cts.map +1 -1
- package/dist/controllers/authentication/mocks/mockResponses.d.mts +17 -32
- package/dist/controllers/authentication/mocks/mockResponses.d.mts.map +1 -1
- package/dist/controllers/authentication/mocks/mockResponses.mjs +9 -1
- package/dist/controllers/authentication/mocks/mockResponses.mjs.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.cjs +3 -3
- package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.cts +2 -2
- package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.d.mts +2 -2
- package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
- package/dist/controllers/user-storage/UserStorageController.mjs +3 -3
- package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs +2 -2
- package/dist/controllers/user-storage/contact-syncing/controller-integration.cjs.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/controller-integration.d.cts.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/controller-integration.d.mts.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs +2 -2
- package/dist/controllers/user-storage/contact-syncing/controller-integration.mjs.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.cjs.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.d.cts +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.d.cts.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.d.mts +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.d.mts.map +1 -1
- package/dist/controllers/user-storage/contact-syncing/types.mjs.map +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.cjs +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.cjs.map +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.d.cts.map +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.d.mts.map +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.mjs +1 -1
- package/dist/controllers/user-storage/mocks/mockResponses.mjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.cjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.cts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.d.mts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-siwe.mjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs +30 -3
- package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts +3 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts +3 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs +30 -3
- package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/services.cjs +60 -2
- package/dist/sdk/authentication-jwt-bearer/services.cjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/services.d.cts +18 -2
- package/dist/sdk/authentication-jwt-bearer/services.d.cts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/services.d.mts +18 -2
- package/dist/sdk/authentication-jwt-bearer/services.d.mts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/services.mjs +57 -1
- package/dist/sdk/authentication-jwt-bearer/services.mjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/types.cjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/types.d.cts +20 -1
- package/dist/sdk/authentication-jwt-bearer/types.d.cts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/types.d.mts +20 -1
- package/dist/sdk/authentication-jwt-bearer/types.d.mts.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/types.mjs.map +1 -1
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.cjs +27 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.cjs.map +1 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.cts +13 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.cts.map +1 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.mts +13 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.mts.map +1 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.mjs +23 -0
- package/dist/sdk/authentication-jwt-bearer/utils/identifier.mjs.map +1 -0
- package/dist/sdk/authentication.cjs +4 -0
- package/dist/sdk/authentication.cjs.map +1 -1
- package/dist/sdk/authentication.d.cts +2 -0
- package/dist/sdk/authentication.d.cts.map +1 -1
- package/dist/sdk/authentication.d.mts +2 -0
- package/dist/sdk/authentication.d.mts.map +1 -1
- package/dist/sdk/authentication.mjs +4 -0
- package/dist/sdk/authentication.mjs.map +1 -1
- package/dist/sdk/mocks/auth.cjs +11 -1
- package/dist/sdk/mocks/auth.cjs.map +1 -1
- package/dist/sdk/mocks/auth.d.cts +10 -0
- package/dist/sdk/mocks/auth.d.cts.map +1 -1
- package/dist/sdk/mocks/auth.d.mts +10 -0
- package/dist/sdk/mocks/auth.d.mts.map +1 -1
- package/dist/sdk/mocks/auth.mjs +11 -1
- package/dist/sdk/mocks/auth.mjs.map +1 -1
- package/dist/sdk/user-storage.cjs +27 -4
- package/dist/sdk/user-storage.cjs.map +1 -1
- package/dist/sdk/user-storage.d.cts +8 -1
- package/dist/sdk/user-storage.d.cts.map +1 -1
- package/dist/sdk/user-storage.d.mts +8 -1
- package/dist/sdk/user-storage.d.mts.map +1 -1
- package/dist/sdk/user-storage.mjs +27 -4
- package/dist/sdk/user-storage.mjs.map +1 -1
- package/dist/sdk/utils/validate-pair-response.cjs +29 -0
- package/dist/sdk/utils/validate-pair-response.cjs.map +1 -0
- package/dist/sdk/utils/validate-pair-response.d.cts +26 -0
- package/dist/sdk/utils/validate-pair-response.d.cts.map +1 -0
- package/dist/sdk/utils/validate-pair-response.d.mts +26 -0
- package/dist/sdk/utils/validate-pair-response.d.mts.map +1 -0
- package/dist/sdk/utils/validate-pair-response.mjs +25 -0
- package/dist/sdk/utils/validate-pair-response.mjs.map +1 -0
- package/dist/shared/encryption/encryption.cjs.map +1 -1
- package/dist/shared/encryption/encryption.d.cts.map +1 -1
- package/dist/shared/encryption/encryption.d.mts.map +1 -1
- package/dist/shared/encryption/encryption.mjs.map +1 -1
- package/dist/shared/types/services.cjs.map +1 -1
- package/dist/shared/types/services.d.cts +7 -0
- package/dist/shared/types/services.d.cts.map +1 -1
- package/dist/shared/types/services.d.mts +7 -0
- package/dist/shared/types/services.d.mts.map +1 -1
- package/dist/shared/types/services.mjs.map +1 -1
- package/package.json +25 -26
|
@@ -1 +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 type { SyncAddressBookEntry } from './utils';\nimport {\n mapAddressBookEntryToUserStorageEntry,\n mapUserStorageEntryToAddressBookEntry,\n} from './utils';\nimport { isContactBridgedFromAccounts } from './utils';\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\nimport { TraceName } from '../constants';\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 if (!contact.address) {\n throw new Error('Contact address is required to create storage key');\n }\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 * @returns Promise that resolves when contact synchronization is complete\n */\nexport async function syncContactsWithUserStorage(\n config: SyncContactsWithUserStorageConfig,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getMessenger, getUserStorageControllerInstance, trace } = options;\n const {\n onContactSyncErroneousSituation,\n onContactUpdated,\n onContactDeleted,\n } = config;\n\n // Cannot perform sync, conditions not met\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // NOTE: Pre-sync operations (canPerformContactSyncing, AddressBookController:list, getRemoteContacts)\n // are intentionally outside try-catch to let errors bubble up to Sentry for better debugging.\n // Only \"erroneous situation\" errors during sync logic itself should be caught.\n\n // Get all local contacts from AddressBookController (exclude chain \"*\" contacts)\n const localVisibleContacts =\n getMessenger()\n .call('AddressBookController:list')\n .filter((contact) => !isContactBridgedFromAccounts(contact))\n .filter(\n (contact) => contact.address && contact.chainId && contact.name?.trim(),\n ) || [];\n\n // Get remote contacts from user storage API\n const remoteContacts = await getRemoteContacts(options);\n\n // Filter remote contacts to exclude invalid ones (or empty array if no remote contacts)\n const validRemoteContacts =\n remoteContacts?.filter(\n (contact) => contact.address && contact.chainId && contact.name?.trim(),\n ) || [];\n\n const performSync = async () => {\n try {\n // Activate sync semaphore to prevent event loops\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n true,\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 validRemoteContacts.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 validRemoteContacts) {\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.deletedAt) {\n // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally\n if (localContact) {\n contactsToDeleteLocally.push(remoteContact);\n }\n } else if (!localContact) {\n // SCENARIO 2: New contact from remote - import to local\n contactsToAddOrUpdateLocally.push(remoteContact);\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 }\n\n // Else: content is identical, no action needed\n }\n }\n\n // SCENARIO 1, 3 & 5: Process local contacts not in remote - handles first sync and new local contacts\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 or first sync - add to remote\n contactsToUpdateRemotely.push(localContact);\n }\n }\n\n // Apply local deletions\n // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry\n // for debugging. Previous versions silently suppressed these errors which made\n // troubleshooting contact sync issues difficult.\n for (const contact of contactsToDeleteLocally) {\n getMessenger().call(\n 'AddressBookController:delete',\n contact.chainId,\n contact.address,\n );\n\n if (onContactDeleted) {\n onContactDeleted();\n }\n }\n\n // Apply local additions/updates\n // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry\n // for debugging. Previous versions silently suppressed these errors which made\n // troubleshooting contact sync issues difficult.\n for (const contact of contactsToAddOrUpdateLocally) {\n if (!contact.deletedAt) {\n getMessenger().call(\n 'AddressBookController:set',\n contact.address,\n contact.name || '',\n contact.chainId,\n contact.memo || '',\n contact.addressType,\n );\n\n if (onContactUpdated) {\n onContactUpdated();\n }\n }\n }\n\n // Apply changes to remote storage\n if (contactsToUpdateRemotely.length > 0) {\n const updatedRemoteContacts: Record<string, SyncAddressBookEntry> = {};\n for (const localContact of contactsToUpdateRemotely) {\n const key = createContactKey(localContact);\n updatedRemoteContacts[key] = {\n ...remoteContactsMap.get(key), // Start with an existing remote contact if it exists\n ...localContact, // override with local changes\n lastUpdatedAt: Date.now(), // mark as updated\n };\n }\n // Save updated contacts to remote storage\n await saveContactsToUserStorage(\n Object.values(updatedRemoteContacts),\n options,\n );\n }\n } catch (error) {\n if (onContactSyncErroneousSituation) {\n onContactSyncErroneousSituation('Error synchronizing contacts', {\n error,\n });\n\n // Re-throw the error to be handled by the caller\n throw error;\n }\n } finally {\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n false,\n );\n }\n };\n\n if (trace) {\n // Gather pre-sync metrics for performance analysis\n const initialLocalContacts = localVisibleContacts;\n const initialValidRemoteContacts = validRemoteContacts;\n\n await trace(\n {\n name: TraceName.ContactSyncFull,\n data: {\n localContactCount: initialLocalContacts.length,\n remoteContactCount: initialValidRemoteContacts.length,\n isFirstSync:\n initialValidRemoteContacts.length === 0 &&\n initialLocalContacts.length > 0,\n isNewDeviceSync:\n initialLocalContacts.length === 0 &&\n initialValidRemoteContacts.length > 0,\n isRegularSync:\n initialLocalContacts.length > 0 &&\n initialValidRemoteContacts.length > 0,\n hasDataToSync:\n initialLocalContacts.length > 0 ||\n initialValidRemoteContacts.length > 0,\n expectedWorkload:\n initialLocalContacts.length + initialValidRemoteContacts.length,\n },\n },\n performSync,\n );\n\n return;\n }\n\n await performSync();\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 remoteContactsJsonArray =\n await getUserStorageControllerInstance().performGetStorageAllFeatureEntries(\n USER_STORAGE_FEATURE_NAMES.addressBook,\n );\n\n if (!remoteContactsJsonArray || remoteContactsJsonArray.length === 0) {\n return null;\n }\n\n // Parse each JSON entry and convert from UserStorageContactEntry to AddressBookEntry\n const remoteStorageEntries = remoteContactsJsonArray.map((contactJson) => {\n const entry = JSON.parse(contactJson) as UserStorageContactEntry;\n return mapUserStorageEntryToAddressBookEntry(entry);\n });\n\n return remoteStorageEntries;\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 * @returns Promise that resolves when contacts are saved\n */\nasync function saveContactsToUserStorage(\n contacts: AddressBookEntry[],\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getUserStorageControllerInstance, trace } = options;\n\n const saveContacts = async () => {\n if (!contacts || contacts.length === 0) {\n return;\n }\n\n // Convert each AddressBookEntry to UserStorageContactEntry format and create key-value pairs\n const storageEntries: [string, string][] = contacts.map((contact) => {\n const key = createContactKey(contact);\n const storageEntry = mapAddressBookEntryToUserStorageEntry(contact);\n return [key, JSON.stringify(storageEntry)];\n });\n\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.addressBook,\n storageEntries,\n );\n };\n\n return trace\n ? await trace(\n {\n name: TraceName.ContactSyncSaveBatch,\n data: {\n contactCount: contacts.length,\n // Performance scaling indicators\n hasBatchOperations: contacts.length > 1,\n chainCount: new Set(contacts.map((c) => c.chainId)).size,\n hasMemosCount: contacts.filter((c) => c.memo?.length).length,\n },\n },\n saveContacts,\n )\n : await saveContacts();\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 * @returns Promise that resolves when the contact is updated\n */\nexport async function updateContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { trace } = options;\n\n const updateContact = async () => {\n if (\n !canPerformContactSyncing(options) ||\n !contact.address ||\n !contact.chainId ||\n !contact.name?.trim()\n ) {\n return;\n }\n\n const { getUserStorageControllerInstance } = options;\n\n // Create an updated entry with timestamp\n const updatedEntry = {\n ...contact,\n lastUpdatedAt: contact.lastUpdatedAt || Date.now(),\n } as SyncAddressBookEntry;\n\n const key = createContactKey(contact);\n const storageEntry = mapAddressBookEntryToUserStorageEntry(updatedEntry);\n\n // Save individual contact to remote storage\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n JSON.stringify(storageEntry),\n );\n };\n\n if (trace) {\n return await trace(\n {\n name: TraceName.ContactSyncUpdateRemote,\n data: {\n chainId: contact.chainId,\n // Performance indicators\n hasTimestamp: Boolean(contact.lastUpdatedAt),\n hasMemo: Boolean(contact.memo?.length),\n isUpdate: Boolean(contact.lastUpdatedAt), // vs new contact\n },\n },\n updateContact,\n );\n }\n\n return await updateContact();\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 * @returns Promise that resolves when the contact is marked as deleted\n */\nexport async function deleteContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { trace } = options;\n const deleteContact = async () => {\n if (\n !canPerformContactSyncing(options) ||\n !contact.address ||\n !contact.chainId ||\n !contact.name?.trim()\n ) {\n return;\n }\n\n const { getUserStorageControllerInstance } = options;\n const key = createContactKey(contact);\n\n try {\n // Try to get the existing contact first\n const existingContactJson =\n await getUserStorageControllerInstance().performGetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n );\n\n if (existingContactJson) {\n // Mark the existing contact as deleted\n const existingStorageEntry = JSON.parse(\n existingContactJson,\n ) as UserStorageContactEntry;\n const existingContact =\n mapUserStorageEntryToAddressBookEntry(existingStorageEntry);\n\n const now = Date.now();\n const deletedContact = {\n ...existingContact,\n deletedAt: now,\n lastUpdatedAt: now,\n } as SyncAddressBookEntry;\n\n const deletedStorageEntry =\n mapAddressBookEntryToUserStorageEntry(deletedContact);\n\n // Save the deleted contact back to storage\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n JSON.stringify(deletedStorageEntry),\n );\n }\n } catch {\n // If contact doesn't exist in remote storage, no need to mark as deleted\n console.warn('Contact not found in remote storage for deletion:', key);\n }\n };\n\n return trace\n ? await trace({ name: TraceName.ContactSyncDeleteRemote }, deleteContact)\n : await deleteContact();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller-integration.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/controller-integration.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,2CAAuC;AAC5E,OAAO,EAAE,SAAS,EAAE,yBAAqB;AACzC,OAAO,EAAE,wBAAwB,EAAE,yBAAqB;AAIxD,OAAO,EACL,qCAAqC,EACrC,qCAAqC,EACtC,oBAAgB;AACjB,OAAO,EAAE,4BAA4B,EAAE,oBAAgB;AAWvD;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAyB;IACjD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAyC,EACzC,OAA8B;IAE9B,MAAM,EAAE,YAAY,EAAE,gCAAgC,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1E,MAAM,EACJ,+BAA+B,EAC/B,gBAAgB,EAChB,gBAAgB,GACjB,GAAG,MAAM,CAAC;IAEX,0CAA0C;IAC1C,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,OAAO;IACT,CAAC;IAED,sGAAsG;IACtG,8FAA8F;IAC9F,+EAA+E;IAE/E,iFAAiF;IACjF,MAAM,oBAAoB,GACxB,YAAY,EAAE;SACX,IAAI,CAAC,4BAA4B,CAAC;SAClC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAAC;SAC3D,MAAM,CACL,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CACxE,IAAI,EAAE,CAAC;IAEZ,4CAA4C;IAC5C,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAExD,wFAAwF;IACxF,MAAM,mBAAmB,GACvB,cAAc,EAAE,MAAM,CACpB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CACxE,IAAI,EAAE,CAAC;IAEV,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;QAC7B,IAAI,CAAC;YACH,iDAAiD;YACjD,MAAM,gCAAgC,EAAE,CAAC,6BAA6B,CACpE,IAAI,CACL,CAAC;YAEF,oCAAoC;YACpC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA4B,CAAC;YAC7D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAgC,CAAC;YAElE,oBAAoB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvC,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACtC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC;YAEH,mBAAmB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACtC,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACtC,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,iDAAiD;YACjD,MAAM,4BAA4B,GAA2B,EAAE,CAAC;YAChE,MAAM,uBAAuB,GAA2B,EAAE,CAAC;YAC3D,MAAM,wBAAwB,GAAuB,EAAE,CAAC;YAExD,sFAAsF;YACtF,KAAK,MAAM,aAAa,IAAI,mBAAmB,EAAE,CAAC;gBAChD,MAAM,GAAG,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;gBAC5C,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAE/C,gEAAgE;gBAChE,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;oBAC5B,oFAAoF;oBACpF,IAAI,YAAY,EAAE,CAAC;wBACjB,uBAAuB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBAC9C,CAAC;gBACH,CAAC;qBAAM,IAAI,CAAC,YAAY,EAAE,CAAC;oBACzB,wDAAwD;oBACxD,4BAA4B,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,qEAAqE;oBACrE,MAAM,oBAAoB,GACxB,YAAY,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI;wBACxC,YAAY,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,CAAC;oBAE3C,IAAI,oBAAoB,EAAE,CAAC;wBACzB,sDAAsD;wBACtD,MAAM,cAAc,GAAG,YAAY,CAAC,aAAa,IAAI,CAAC,CAAC;wBACvD,MAAM,eAAe,GAAG,aAAa,CAAC,aAAa,IAAI,CAAC,CAAC;wBAEzD,IAAI,cAAc,IAAI,eAAe,EAAE,CAAC;4BACtC,mDAAmD;4BACnD,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBAC9C,CAAC;6BAAM,CAAC;4BACN,uCAAuC;4BACvC,4BAA4B,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;wBACnD,CAAC;oBACH,CAAC;oBAED,+CAA+C;gBACjD,CAAC;YACH,CAAC;YAED,sGAAsG;YACtG,KAAK,MAAM,YAAY,IAAI,oBAAoB,EAAE,CAAC;gBAChD,MAAM,GAAG,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;gBAC3C,MAAM,aAAa,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEjD,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,kDAAkD;oBAClD,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;YAED,wBAAwB;YACxB,wFAAwF;YACxF,+EAA+E;YAC/E,iDAAiD;YACjD,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;gBAC9C,YAAY,EAAE,CAAC,IAAI,CACjB,8BAA8B,EAC9B,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,OAAO,CAChB,CAAC;gBAEF,IAAI,gBAAgB,EAAE,CAAC;oBACrB,gBAAgB,EAAE,CAAC;gBACrB,CAAC;YACH,CAAC;YAED,gCAAgC;YAChC,wFAAwF;YACxF,+EAA+E;YAC/E,iDAAiD;YACjD,KAAK,MAAM,OAAO,IAAI,4BAA4B,EAAE,CAAC;gBACnD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;oBACvB,YAAY,EAAE,CAAC,IAAI,CACjB,2BAA2B,EAC3B,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,IAAI,IAAI,EAAE,EAClB,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,IAAI,IAAI,EAAE,EAClB,OAAO,CAAC,WAAW,CACpB,CAAC;oBAEF,IAAI,gBAAgB,EAAE,CAAC;wBACrB,gBAAgB,EAAE,CAAC;oBACrB,CAAC;gBACH,CAAC;YACH,CAAC;YAED,kCAAkC;YAClC,IAAI,wBAAwB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxC,MAAM,qBAAqB,GAAyC,EAAE,CAAC;gBACvE,KAAK,MAAM,YAAY,IAAI,wBAAwB,EAAE,CAAC;oBACpD,MAAM,GAAG,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;oBAC3C,qBAAqB,CAAC,GAAG,CAAC,GAAG;wBAC3B,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,qDAAqD;wBACpF,GAAG,YAAY,EAAE,8BAA8B;wBAC/C,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,kBAAkB;qBAC9C,CAAC;gBACJ,CAAC;gBACD,0CAA0C;gBAC1C,MAAM,yBAAyB,CAC7B,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,EACpC,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,+BAA+B,EAAE,CAAC;gBACpC,+BAA+B,CAAC,8BAA8B,EAAE;oBAC9D,KAAK;iBACN,CAAC,CAAC;gBAEH,iDAAiD;gBACjD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,gCAAgC,EAAE,CAAC,6BAA6B,CACpE,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,mDAAmD;QACnD,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;QAClD,MAAM,0BAA0B,GAAG,mBAAmB,CAAC;QAEvD,MAAM,KAAK,CACT;YACE,IAAI,EAAE,SAAS,CAAC,eAAe;YAC/B,IAAI,EAAE;gBACJ,iBAAiB,EAAE,oBAAoB,CAAC,MAAM;gBAC9C,kBAAkB,EAAE,0BAA0B,CAAC,MAAM;gBACrD,WAAW,EACT,0BAA0B,CAAC,MAAM,KAAK,CAAC;oBACvC,oBAAoB,CAAC,MAAM,GAAG,CAAC;gBACjC,eAAe,EACb,oBAAoB,CAAC,MAAM,KAAK,CAAC;oBACjC,0BAA0B,CAAC,MAAM,GAAG,CAAC;gBACvC,aAAa,EACX,oBAAoB,CAAC,MAAM,GAAG,CAAC;oBAC/B,0BAA0B,CAAC,MAAM,GAAG,CAAC;gBACvC,aAAa,EACX,oBAAoB,CAAC,MAAM,GAAG,CAAC;oBAC/B,0BAA0B,CAAC,MAAM,GAAG,CAAC;gBACvC,gBAAgB,EACd,oBAAoB,CAAC,MAAM,GAAG,0BAA0B,CAAC,MAAM;aAClE;SACF,EACD,WAAW,CACZ,CAAC;QAEF,OAAO;IACT,CAAC;IAED,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,iBAAiB,CAC9B,OAA8B;IAE9B,MAAM,EAAE,gCAAgC,EAAE,GAAG,OAAO,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,uBAAuB,GAC3B,MAAM,gCAAgC,EAAE,CAAC,kCAAkC,CACzE,0BAA0B,CAAC,WAAW,CACvC,CAAC;QAEJ,IAAI,CAAC,uBAAuB,IAAI,uBAAuB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,qFAAqF;QACrF,MAAM,oBAAoB,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;YACvE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAA4B,CAAC;YACjE,OAAO,qCAAqC,CAAC,KAAK,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,yBAAyB,CACtC,QAA4B,EAC5B,OAA8B;IAE9B,MAAM,EAAE,gCAAgC,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAE5D,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;QAC9B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,6FAA6F;QAC7F,MAAM,cAAc,GAAuB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YAClE,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,YAAY,GAAG,qCAAqC,CAAC,OAAO,CAAC,CAAC;YACpE,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,MAAM,gCAAgC,EAAE,CAAC,sBAAsB,CAC7D,0BAA0B,CAAC,WAAW,EACtC,cAAc,CACf,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,KAAK;QACV,CAAC,CAAC,MAAM,KAAK,CACT;YACE,IAAI,EAAE,SAAS,CAAC,oBAAoB;YACpC,IAAI,EAAE;gBACJ,YAAY,EAAE,QAAQ,CAAC,MAAM;gBAC7B,iCAAiC;gBACjC,kBAAkB,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACvC,UAAU,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;gBACxD,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM;aAC7D;SACF,EACD,YAAY,CACb;QACH,CAAC,CAAC,MAAM,YAAY,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAyB,EACzB,OAA8B;IAE9B,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAE1B,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;QAC/B,IACE,CAAC,wBAAwB,CAAC,OAAO,CAAC;YAClC,CAAC,OAAO,CAAC,OAAO;YAChB,CAAC,OAAO,CAAC,OAAO;YAChB,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EACrB,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,gCAAgC,EAAE,GAAG,OAAO,CAAC;QAErD,yCAAyC;QACzC,MAAM,YAAY,GAAG;YACnB,GAAG,OAAO;YACV,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;QAE1B,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,YAAY,GAAG,qCAAqC,CAAC,YAAY,CAAC,CAAC;QAEzE,4CAA4C;QAC5C,MAAM,gCAAgC,EAAE,CAAC,iBAAiB,CACxD,GAAG,0BAA0B,CAAC,WAAW,IAAI,GAAG,EAAE,EAClD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAC7B,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,MAAM,KAAK,CAChB;YACE,IAAI,EAAE,SAAS,CAAC,uBAAuB;YACvC,IAAI,EAAE;gBACJ,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,yBAAyB;gBACzB,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;gBAC5C,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;gBACtC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,iBAAiB;aAC5D;SACF,EACD,aAAa,CACd,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,aAAa,EAAE,CAAC;AAC/B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAyB,EACzB,OAA8B;IAE9B,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1B,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;QAC/B,IACE,CAAC,wBAAwB,CAAC,OAAO,CAAC;YAClC,CAAC,OAAO,CAAC,OAAO;YAChB,CAAC,OAAO,CAAC,OAAO;YAChB,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EACrB,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,gCAAgC,EAAE,GAAG,OAAO,CAAC;QACrD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,CAAC;YACH,wCAAwC;YACxC,MAAM,mBAAmB,GACvB,MAAM,gCAAgC,EAAE,CAAC,iBAAiB,CACxD,GAAG,0BAA0B,CAAC,WAAW,IAAI,GAAG,EAAE,CACnD,CAAC;YAEJ,IAAI,mBAAmB,EAAE,CAAC;gBACxB,uCAAuC;gBACvC,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CACrC,mBAAmB,CACO,CAAC;gBAC7B,MAAM,eAAe,GACnB,qCAAqC,CAAC,oBAAoB,CAAC,CAAC;gBAE9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,MAAM,cAAc,GAAG;oBACrB,GAAG,eAAe;oBAClB,SAAS,EAAE,GAAG;oBACd,aAAa,EAAE,GAAG;iBACK,CAAC;gBAE1B,MAAM,mBAAmB,GACvB,qCAAqC,CAAC,cAAc,CAAC,CAAC;gBAExD,2CAA2C;gBAC3C,MAAM,gCAAgC,EAAE,CAAC,iBAAiB,CACxD,GAAG,0BAA0B,CAAC,WAAW,IAAI,GAAG,EAAE,EAClD,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,CACpC,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,OAAO,CAAC,IAAI,CAAC,mDAAmD,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,KAAK;QACV,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,uBAAuB,EAAE,EAAE,aAAa,CAAC;QACzE,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC;AAC5B,CAAC","sourcesContent":["import type { AddressBookEntry } from '@metamask/address-book-controller';\n\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\nimport { TraceName } from '../constants';\nimport { canPerformContactSyncing } from './sync-utils';\nimport type { ContactSyncingOptions } from './types';\nimport type { UserStorageContactEntry } from './types';\nimport type { SyncAddressBookEntry } from './utils';\nimport {\n mapAddressBookEntryToUserStorageEntry,\n mapUserStorageEntryToAddressBookEntry,\n} from './utils';\nimport { isContactBridgedFromAccounts } from './utils';\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 if (!contact.address) {\n throw new Error('Contact address is required to create storage key');\n }\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 * @returns Promise that resolves when contact synchronization is complete\n */\nexport async function syncContactsWithUserStorage(\n config: SyncContactsWithUserStorageConfig,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getMessenger, getUserStorageControllerInstance, trace } = options;\n const {\n onContactSyncErroneousSituation,\n onContactUpdated,\n onContactDeleted,\n } = config;\n\n // Cannot perform sync, conditions not met\n if (!canPerformContactSyncing(options)) {\n return;\n }\n\n // NOTE: Pre-sync operations (canPerformContactSyncing, AddressBookController:list, getRemoteContacts)\n // are intentionally outside try-catch to let errors bubble up to Sentry for better debugging.\n // Only \"erroneous situation\" errors during sync logic itself should be caught.\n\n // Get all local contacts from AddressBookController (exclude chain \"*\" contacts)\n const localVisibleContacts =\n getMessenger()\n .call('AddressBookController:list')\n .filter((contact) => !isContactBridgedFromAccounts(contact))\n .filter(\n (contact) => contact.address && contact.chainId && contact.name?.trim(),\n ) || [];\n\n // Get remote contacts from user storage API\n const remoteContacts = await getRemoteContacts(options);\n\n // Filter remote contacts to exclude invalid ones (or empty array if no remote contacts)\n const validRemoteContacts =\n remoteContacts?.filter(\n (contact) => contact.address && contact.chainId && contact.name?.trim(),\n ) || [];\n\n const performSync = async () => {\n try {\n // Activate sync semaphore to prevent event loops\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n true,\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 validRemoteContacts.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 validRemoteContacts) {\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.deletedAt) {\n // SCENARIO 8: Remote deletion - should be applied locally if contact exists locally\n if (localContact) {\n contactsToDeleteLocally.push(remoteContact);\n }\n } else if (!localContact) {\n // SCENARIO 2: New contact from remote - import to local\n contactsToAddOrUpdateLocally.push(remoteContact);\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 }\n\n // Else: content is identical, no action needed\n }\n }\n\n // SCENARIO 1, 3 & 5: Process local contacts not in remote - handles first sync and new local contacts\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 or first sync - add to remote\n contactsToUpdateRemotely.push(localContact);\n }\n }\n\n // Apply local deletions\n // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry\n // for debugging. Previous versions silently suppressed these errors which made\n // troubleshooting contact sync issues difficult.\n for (const contact of contactsToDeleteLocally) {\n getMessenger().call(\n 'AddressBookController:delete',\n contact.chainId,\n contact.address,\n );\n\n if (onContactDeleted) {\n onContactDeleted();\n }\n }\n\n // Apply local additions/updates\n // Note: Individual errors are intentionally NOT caught here to ensure they reach Sentry\n // for debugging. Previous versions silently suppressed these errors which made\n // troubleshooting contact sync issues difficult.\n for (const contact of contactsToAddOrUpdateLocally) {\n if (!contact.deletedAt) {\n getMessenger().call(\n 'AddressBookController:set',\n contact.address,\n contact.name || '',\n contact.chainId,\n contact.memo || '',\n contact.addressType,\n );\n\n if (onContactUpdated) {\n onContactUpdated();\n }\n }\n }\n\n // Apply changes to remote storage\n if (contactsToUpdateRemotely.length > 0) {\n const updatedRemoteContacts: Record<string, SyncAddressBookEntry> = {};\n for (const localContact of contactsToUpdateRemotely) {\n const key = createContactKey(localContact);\n updatedRemoteContacts[key] = {\n ...remoteContactsMap.get(key), // Start with an existing remote contact if it exists\n ...localContact, // override with local changes\n lastUpdatedAt: Date.now(), // mark as updated\n };\n }\n // Save updated contacts to remote storage\n await saveContactsToUserStorage(\n Object.values(updatedRemoteContacts),\n options,\n );\n }\n } catch (error) {\n if (onContactSyncErroneousSituation) {\n onContactSyncErroneousSituation('Error synchronizing contacts', {\n error,\n });\n\n // Re-throw the error to be handled by the caller\n throw error;\n }\n } finally {\n await getUserStorageControllerInstance().setIsContactSyncingInProgress(\n false,\n );\n }\n };\n\n if (trace) {\n // Gather pre-sync metrics for performance analysis\n const initialLocalContacts = localVisibleContacts;\n const initialValidRemoteContacts = validRemoteContacts;\n\n await trace(\n {\n name: TraceName.ContactSyncFull,\n data: {\n localContactCount: initialLocalContacts.length,\n remoteContactCount: initialValidRemoteContacts.length,\n isFirstSync:\n initialValidRemoteContacts.length === 0 &&\n initialLocalContacts.length > 0,\n isNewDeviceSync:\n initialLocalContacts.length === 0 &&\n initialValidRemoteContacts.length > 0,\n isRegularSync:\n initialLocalContacts.length > 0 &&\n initialValidRemoteContacts.length > 0,\n hasDataToSync:\n initialLocalContacts.length > 0 ||\n initialValidRemoteContacts.length > 0,\n expectedWorkload:\n initialLocalContacts.length + initialValidRemoteContacts.length,\n },\n },\n performSync,\n );\n\n return;\n }\n\n await performSync();\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 remoteContactsJsonArray =\n await getUserStorageControllerInstance().performGetStorageAllFeatureEntries(\n USER_STORAGE_FEATURE_NAMES.addressBook,\n );\n\n if (!remoteContactsJsonArray || remoteContactsJsonArray.length === 0) {\n return null;\n }\n\n // Parse each JSON entry and convert from UserStorageContactEntry to AddressBookEntry\n const remoteStorageEntries = remoteContactsJsonArray.map((contactJson) => {\n const entry = JSON.parse(contactJson) as UserStorageContactEntry;\n return mapUserStorageEntryToAddressBookEntry(entry);\n });\n\n return remoteStorageEntries;\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 * @returns Promise that resolves when contacts are saved\n */\nasync function saveContactsToUserStorage(\n contacts: AddressBookEntry[],\n options: ContactSyncingOptions,\n): Promise<void> {\n const { getUserStorageControllerInstance, trace } = options;\n\n const saveContacts = async () => {\n if (!contacts || contacts.length === 0) {\n return;\n }\n\n // Convert each AddressBookEntry to UserStorageContactEntry format and create key-value pairs\n const storageEntries: [string, string][] = contacts.map((contact) => {\n const key = createContactKey(contact);\n const storageEntry = mapAddressBookEntryToUserStorageEntry(contact);\n return [key, JSON.stringify(storageEntry)];\n });\n\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.addressBook,\n storageEntries,\n );\n };\n\n return trace\n ? await trace(\n {\n name: TraceName.ContactSyncSaveBatch,\n data: {\n contactCount: contacts.length,\n // Performance scaling indicators\n hasBatchOperations: contacts.length > 1,\n chainCount: new Set(contacts.map((c) => c.chainId)).size,\n hasMemosCount: contacts.filter((c) => c.memo?.length).length,\n },\n },\n saveContacts,\n )\n : await saveContacts();\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 * @returns Promise that resolves when the contact is updated\n */\nexport async function updateContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { trace } = options;\n\n const updateContact = async () => {\n if (\n !canPerformContactSyncing(options) ||\n !contact.address ||\n !contact.chainId ||\n !contact.name?.trim()\n ) {\n return;\n }\n\n const { getUserStorageControllerInstance } = options;\n\n // Create an updated entry with timestamp\n const updatedEntry = {\n ...contact,\n lastUpdatedAt: contact.lastUpdatedAt || Date.now(),\n } as SyncAddressBookEntry;\n\n const key = createContactKey(contact);\n const storageEntry = mapAddressBookEntryToUserStorageEntry(updatedEntry);\n\n // Save individual contact to remote storage\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n JSON.stringify(storageEntry),\n );\n };\n\n if (trace) {\n return await trace(\n {\n name: TraceName.ContactSyncUpdateRemote,\n data: {\n chainId: contact.chainId,\n // Performance indicators\n hasTimestamp: Boolean(contact.lastUpdatedAt),\n hasMemo: Boolean(contact.memo?.length),\n isUpdate: Boolean(contact.lastUpdatedAt), // vs new contact\n },\n },\n updateContact,\n );\n }\n\n return await updateContact();\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 * @returns Promise that resolves when the contact is marked as deleted\n */\nexport async function deleteContactInRemoteStorage(\n contact: AddressBookEntry,\n options: ContactSyncingOptions,\n): Promise<void> {\n const { trace } = options;\n const deleteContact = async () => {\n if (\n !canPerformContactSyncing(options) ||\n !contact.address ||\n !contact.chainId ||\n !contact.name?.trim()\n ) {\n return;\n }\n\n const { getUserStorageControllerInstance } = options;\n const key = createContactKey(contact);\n\n try {\n // Try to get the existing contact first\n const existingContactJson =\n await getUserStorageControllerInstance().performGetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n );\n\n if (existingContactJson) {\n // Mark the existing contact as deleted\n const existingStorageEntry = JSON.parse(\n existingContactJson,\n ) as UserStorageContactEntry;\n const existingContact =\n mapUserStorageEntryToAddressBookEntry(existingStorageEntry);\n\n const now = Date.now();\n const deletedContact = {\n ...existingContact,\n deletedAt: now,\n lastUpdatedAt: now,\n } as SyncAddressBookEntry;\n\n const deletedStorageEntry =\n mapAddressBookEntryToUserStorageEntry(deletedContact);\n\n // Save the deleted contact back to storage\n await getUserStorageControllerInstance().performSetStorage(\n `${USER_STORAGE_FEATURE_NAMES.addressBook}.${key}`,\n JSON.stringify(deletedStorageEntry),\n );\n }\n } catch {\n // If contact doesn't exist in remote storage, no need to mark as deleted\n console.warn('Contact not found in remote storage for deletion:', key);\n }\n };\n\n return trace\n ? await trace({ name: TraceName.ContactSyncDeleteRemote }, deleteContact)\n : await deleteContact();\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type {
|
|
1
|
+
{"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type { UserStorageController } from '../UserStorageController';\nimport type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\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 isEns flag 'e' of the contact (optional) */\n e?: boolean;\n /** the lastUpdatedAt timestamp 'lu' of the contact */\n lu?: number;\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 trace?: TraceCallback;\n};\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { TraceCallback } from "@metamask/controller-utils";
|
|
2
2
|
import type { Hex } from "@metamask/utils";
|
|
3
|
-
import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.cjs";
|
|
4
3
|
import type { UserStorageControllerMessenger } from "../UserStorageController.cjs";
|
|
5
4
|
import type { UserStorageController } from "../UserStorageController.cjs";
|
|
5
|
+
import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.cjs";
|
|
6
6
|
export type UserStorageContactEntry = {
|
|
7
7
|
/**
|
|
8
8
|
* The Version 'v' of the User Storage.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,qCAAiC;AACtE,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AAErB,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,mDAAmD;IACnD,CAAC,CAAC,EAAE,OAAO,CAAC;IACZ,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,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;IACnD,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { TraceCallback } from "@metamask/controller-utils";
|
|
2
2
|
import type { Hex } from "@metamask/utils";
|
|
3
|
-
import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.mjs";
|
|
4
3
|
import type { UserStorageControllerMessenger } from "../UserStorageController.mjs";
|
|
5
4
|
import type { UserStorageController } from "../UserStorageController.mjs";
|
|
5
|
+
import type { USER_STORAGE_VERSION_KEY, USER_STORAGE_VERSION } from "./constants.mjs";
|
|
6
6
|
export type UserStorageContactEntry = {
|
|
7
7
|
/**
|
|
8
8
|
* The Version 'v' of the User Storage.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,qCAAiC;AACtE,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EACrB,wBAAoB;AAErB,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,mDAAmD;IACnD,CAAC,CAAC,EAAE,OAAO,CAAC;IACZ,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,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;IACnD,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type {
|
|
1
|
+
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/contact-syncing/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { UserStorageControllerMessenger } from '../UserStorageController';\nimport type { UserStorageController } from '../UserStorageController';\nimport type {\n USER_STORAGE_VERSION_KEY,\n USER_STORAGE_VERSION,\n} from './constants';\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 isEns flag 'e' of the contact (optional) */\n e?: boolean;\n /** the lastUpdatedAt timestamp 'lu' of the contact */\n lu?: number;\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 trace?: TraceCallback;\n};\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.deleteMockUserStorageAllFeatureEntriesResponse = exports.deleteMockUserStorageResponse = exports.getMockUserStorageBatchDeleteResponse = exports.getMockUserStorageBatchPutResponse = exports.getMockUserStoragePutResponse = exports.getMockUserStorageAllFeatureEntriesResponse = exports.getMockUserStorageGetResponse = exports.createMockAllFeatureEntriesResponse = exports.createMockGetStorageResponse = exports.getMockUserStorageEndpoint = void 0;
|
|
4
|
-
const mockStorage_1 = require("./mockStorage.cjs");
|
|
5
4
|
const sdk_1 = require("../../../sdk/index.cjs");
|
|
6
5
|
const storage_schema_1 = require("../../../shared/storage-schema.cjs");
|
|
6
|
+
const mockStorage_1 = require("./mockStorage.cjs");
|
|
7
7
|
const getMockUserStorageEndpoint = (path) => {
|
|
8
8
|
if (path.split('.').length === 1) {
|
|
9
9
|
return `${(0, sdk_1.getEnvUrls)(sdk_1.Env.PRD).userStorageApiUrl}/api/v1/userstorage/${path}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockResponses.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"mockResponses.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"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","sourcesContent":["import { Env, getEnvUrls } from '../../../sdk';\nimport type {\n UserStorageGenericPathWithFeatureAndKey,\n UserStorageGenericPathWithFeatureOnly,\n} from '../../../shared/storage-schema';\nimport {\n createEntryPath,\n USER_STORAGE_FEATURE_NAMES,\n} from '../../../shared/storage-schema';\nimport type {\n GetUserStorageAllFeatureEntriesResponse,\n GetUserStorageResponse,\n} from '../types';\nimport {\n MOCK_ENCRYPTED_STORAGE_DATA,\n MOCK_STORAGE_DATA,\n MOCK_STORAGE_KEY,\n} from './mockStorage';\n\ntype MockResponse = {\n url: string;\n requestMethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n response: unknown;\n};\n\nexport const getMockUserStorageEndpoint = (\n path:\n | UserStorageGenericPathWithFeatureAndKey\n | UserStorageGenericPathWithFeatureOnly,\n) => {\n if (path.split('.').length === 1) {\n return `${getEnvUrls(Env.PRD).userStorageApiUrl}/api/v1/userstorage/${path}`;\n }\n\n return `${getEnvUrls(Env.PRD).userStorageApiUrl}/api/v1/userstorage/${createEntryPath(\n path as UserStorageGenericPathWithFeatureAndKey,\n MOCK_STORAGE_KEY,\n )}`;\n};\n\n/**\n * Creates a mock GET user-storage response\n *\n * @param data - data to encrypt\n * @returns a realistic GET Response Body\n */\nexport async function createMockGetStorageResponse(\n data?: string,\n): Promise<GetUserStorageResponse> {\n return {\n HashedKey: 'HASHED_KEY',\n Data: await MOCK_ENCRYPTED_STORAGE_DATA(data),\n };\n}\n\n/**\n * Creates a mock GET ALL user-storage response\n *\n * @param dataArr - array of data to encrypt\n * @returns a realistic GET ALL Response Body\n */\nexport async function createMockAllFeatureEntriesResponse(\n dataArr: string[] = [MOCK_STORAGE_DATA],\n): Promise<GetUserStorageAllFeatureEntriesResponse> {\n const decryptedData = [];\n\n for (const data of dataArr) {\n decryptedData.push({\n HashedKey: 'HASHED_KEY',\n Data: await MOCK_ENCRYPTED_STORAGE_DATA(data),\n });\n }\n\n return decryptedData;\n}\n\n/**\n * Creates a mock user-storage api GET request\n *\n * @param path - path of the GET Url\n * @returns mock GET API request. Can be used by e2e or unit mock servers\n */\nexport async function getMockUserStorageGetResponse(\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'GET',\n response: await createMockGetStorageResponse(),\n } satisfies MockResponse;\n}\n\n/**\n * Creates a mock user-storage api GET ALL request\n *\n * @param path - path of the GET url\n * @param dataArr - data to encrypt\n * @returns mock GET ALL API request. Can be used by e2e or unit mock servers\n */\nexport async function getMockUserStorageAllFeatureEntriesResponse(\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n dataArr?: string[],\n) {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'GET',\n response: await createMockAllFeatureEntriesResponse(dataArr),\n } satisfies MockResponse;\n}\n\nexport const getMockUserStoragePutResponse = (\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const getMockUserStorageBatchPutResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const getMockUserStorageBatchDeleteResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const deleteMockUserStorageResponse = (\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'DELETE',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const deleteMockUserStorageAllFeatureEntriesResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'DELETE',\n response: null,\n } satisfies MockResponse;\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockResponses.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mockResponses.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uCAAuC,EACvC,qCAAqC,EACtC,2CAAuC;AAKxC,OAAO,KAAK,EACV,uCAAuC,EACvC,sBAAsB,EACvB,qBAAiB;AAalB,eAAO,MAAM,0BAA0B,SAEjC,uCAAuC,GACvC,qCAAqC,WAU1C,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,sBAAsB,CAAC,CAKjC;AAED;;;;;GAKG;AACH,wBAAsB,mCAAmC,CACvD,OAAO,GAAE,MAAM,EAAwB,GACtC,OAAO,CAAC,uCAAuC,CAAC,CAWlD;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,GAAE,uCAA6G;;;;GAOpH;AAED;;;;;;GAMG;AACH,wBAAsB,2CAA2C,CAC/D,IAAI,GAAE,qCAAgF,EACtF,OAAO,CAAC,EAAE,MAAM,EAAE;;;;GAOnB;AAED,eAAO,MAAM,6BAA6B,UAClC,uCAAuC;;;;CAO9C,CAAC;AAEF,eAAO,MAAM,kCAAkC,UACvC,qCAAqC;;;;CAO5C,CAAC;AAEF,eAAO,MAAM,qCAAqC,UAC1C,qCAAqC;;;;CAO5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,UAClC,uCAAuC;;;;CAO9C,CAAC;AAEF,eAAO,MAAM,8CAA8C,UACnD,qCAAqC;;;;CAO5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockResponses.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mockResponses.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uCAAuC,EACvC,qCAAqC,EACtC,2CAAuC;AAKxC,OAAO,KAAK,EACV,uCAAuC,EACvC,sBAAsB,EACvB,qBAAiB;AAalB,eAAO,MAAM,0BAA0B,SAEjC,uCAAuC,GACvC,qCAAqC,WAU1C,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,sBAAsB,CAAC,CAKjC;AAED;;;;;GAKG;AACH,wBAAsB,mCAAmC,CACvD,OAAO,GAAE,MAAM,EAAwB,GACtC,OAAO,CAAC,uCAAuC,CAAC,CAWlD;AAED;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,GAAE,uCAA6G;;;;GAOpH;AAED;;;;;;GAMG;AACH,wBAAsB,2CAA2C,CAC/D,IAAI,GAAE,qCAAgF,EACtF,OAAO,CAAC,EAAE,MAAM,EAAE;;;;GAOnB;AAED,eAAO,MAAM,6BAA6B,UAClC,uCAAuC;;;;CAO9C,CAAC;AAEF,eAAO,MAAM,kCAAkC,UACvC,qCAAqC;;;;CAO5C,CAAC;AAEF,eAAO,MAAM,qCAAqC,UAC1C,qCAAqC;;;;CAO5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,UAClC,uCAAuC;;;;CAO9C,CAAC;AAEF,eAAO,MAAM,8CAA8C,UACnD,qCAAqC;;;;CAO5C,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { MOCK_ENCRYPTED_STORAGE_DATA, MOCK_STORAGE_DATA, MOCK_STORAGE_KEY } from "./mockStorage.mjs";
|
|
2
1
|
import { Env, getEnvUrls } from "../../../sdk/index.mjs";
|
|
3
2
|
import { createEntryPath, USER_STORAGE_FEATURE_NAMES } from "../../../shared/storage-schema.mjs";
|
|
3
|
+
import { MOCK_ENCRYPTED_STORAGE_DATA, MOCK_STORAGE_DATA, MOCK_STORAGE_KEY } from "./mockStorage.mjs";
|
|
4
4
|
export const getMockUserStorageEndpoint = (path) => {
|
|
5
5
|
if (path.split('.').length === 1) {
|
|
6
6
|
return `${getEnvUrls(Env.PRD).userStorageApiUrl}/api/v1/userstorage/${path}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockResponses.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"mockResponses.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/mocks/mockResponses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,+BAAqB;AAK/C,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,2CAAuC;AAKxC,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,EACjB,gBAAgB,EACjB,0BAAsB;AAQvB,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,IAEyC,EACzC,EAAE;IACF,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,iBAAiB,uBAAuB,IAAI,EAAE,CAAC;IAC/E,CAAC;IAED,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,iBAAiB,uBAAuB,eAAe,CACnF,IAA+C,EAC/C,gBAAgB,CACjB,EAAE,CAAC;AACN,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,IAAa;IAEb,OAAO;QACL,SAAS,EAAE,YAAY;QACvB,IAAI,EAAE,MAAM,2BAA2B,CAAC,IAAI,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,UAAoB,CAAC,iBAAiB,CAAC;IAEvC,MAAM,aAAa,GAAG,EAAE,CAAC;IAEzB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,aAAa,CAAC,IAAI,CAAC;YACjB,SAAS,EAAE,YAAY;YACvB,IAAI,EAAE,MAAM,2BAA2B,CAAC,IAAI,CAAC;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAgD,GAAG,0BAA0B,CAAC,aAAa,wBAAwB;IAEnH,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,MAAM,4BAA4B,EAAE;KACxB,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,2CAA2C,CAC/D,OAA8C,0BAA0B,CAAC,aAAa,EACtF,OAAkB;IAElB,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,MAAM,mCAAmC,CAAC,OAAO,CAAC;KACtC,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,OAAgD,GAAG,0BAA0B,CAAC,aAAa,wBAAwB,EACnH,EAAE;IACF,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,IAAI;KACQ,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAChD,OAA8C,0BAA0B,CAAC,aAAa,EACtF,EAAE;IACF,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,IAAI;KACQ,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qCAAqC,GAAG,CACnD,OAA8C,0BAA0B,CAAC,aAAa,EACtF,EAAE;IACF,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,IAAI;KACQ,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,OAAgD,GAAG,0BAA0B,CAAC,aAAa,wBAAwB,EACnH,EAAE;IACF,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,QAAQ;QACvB,QAAQ,EAAE,IAAI;KACQ,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,8CAA8C,GAAG,CAC5D,OAA8C,0BAA0B,CAAC,aAAa,EACtF,EAAE;IACF,OAAO;QACL,GAAG,EAAE,0BAA0B,CAAC,IAAI,CAAC;QACrC,aAAa,EAAE,QAAQ;QACvB,QAAQ,EAAE,IAAI;KACQ,CAAC;AAC3B,CAAC,CAAC","sourcesContent":["import { Env, getEnvUrls } from '../../../sdk';\nimport type {\n UserStorageGenericPathWithFeatureAndKey,\n UserStorageGenericPathWithFeatureOnly,\n} from '../../../shared/storage-schema';\nimport {\n createEntryPath,\n USER_STORAGE_FEATURE_NAMES,\n} from '../../../shared/storage-schema';\nimport type {\n GetUserStorageAllFeatureEntriesResponse,\n GetUserStorageResponse,\n} from '../types';\nimport {\n MOCK_ENCRYPTED_STORAGE_DATA,\n MOCK_STORAGE_DATA,\n MOCK_STORAGE_KEY,\n} from './mockStorage';\n\ntype MockResponse = {\n url: string;\n requestMethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n response: unknown;\n};\n\nexport const getMockUserStorageEndpoint = (\n path:\n | UserStorageGenericPathWithFeatureAndKey\n | UserStorageGenericPathWithFeatureOnly,\n) => {\n if (path.split('.').length === 1) {\n return `${getEnvUrls(Env.PRD).userStorageApiUrl}/api/v1/userstorage/${path}`;\n }\n\n return `${getEnvUrls(Env.PRD).userStorageApiUrl}/api/v1/userstorage/${createEntryPath(\n path as UserStorageGenericPathWithFeatureAndKey,\n MOCK_STORAGE_KEY,\n )}`;\n};\n\n/**\n * Creates a mock GET user-storage response\n *\n * @param data - data to encrypt\n * @returns a realistic GET Response Body\n */\nexport async function createMockGetStorageResponse(\n data?: string,\n): Promise<GetUserStorageResponse> {\n return {\n HashedKey: 'HASHED_KEY',\n Data: await MOCK_ENCRYPTED_STORAGE_DATA(data),\n };\n}\n\n/**\n * Creates a mock GET ALL user-storage response\n *\n * @param dataArr - array of data to encrypt\n * @returns a realistic GET ALL Response Body\n */\nexport async function createMockAllFeatureEntriesResponse(\n dataArr: string[] = [MOCK_STORAGE_DATA],\n): Promise<GetUserStorageAllFeatureEntriesResponse> {\n const decryptedData = [];\n\n for (const data of dataArr) {\n decryptedData.push({\n HashedKey: 'HASHED_KEY',\n Data: await MOCK_ENCRYPTED_STORAGE_DATA(data),\n });\n }\n\n return decryptedData;\n}\n\n/**\n * Creates a mock user-storage api GET request\n *\n * @param path - path of the GET Url\n * @returns mock GET API request. Can be used by e2e or unit mock servers\n */\nexport async function getMockUserStorageGetResponse(\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'GET',\n response: await createMockGetStorageResponse(),\n } satisfies MockResponse;\n}\n\n/**\n * Creates a mock user-storage api GET ALL request\n *\n * @param path - path of the GET url\n * @param dataArr - data to encrypt\n * @returns mock GET ALL API request. Can be used by e2e or unit mock servers\n */\nexport async function getMockUserStorageAllFeatureEntriesResponse(\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n dataArr?: string[],\n) {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'GET',\n response: await createMockAllFeatureEntriesResponse(dataArr),\n } satisfies MockResponse;\n}\n\nexport const getMockUserStoragePutResponse = (\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const getMockUserStorageBatchPutResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const getMockUserStorageBatchDeleteResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'PUT',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const deleteMockUserStorageResponse = (\n path: UserStorageGenericPathWithFeatureAndKey = `${USER_STORAGE_FEATURE_NAMES.notifications}.notification_settings`,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'DELETE',\n response: null,\n } satisfies MockResponse;\n};\n\nexport const deleteMockUserStorageAllFeatureEntriesResponse = (\n path: UserStorageGenericPathWithFeatureOnly = USER_STORAGE_FEATURE_NAMES.notifications,\n) => {\n return {\n url: getMockUserStorageEndpoint(path),\n requestMethod: 'DELETE',\n response: null,\n } satisfies MockResponse;\n};\n"]}
|
|
@@ -14,9 +14,9 @@ var _SIWEJwtBearerAuth_instances, _SIWEJwtBearerAuth_config, _SIWEJwtBearerAuth_
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.SIWEJwtBearerAuth = void 0;
|
|
16
16
|
const siwe_1 = require("siwe");
|
|
17
|
-
const services_1 = require("./services.cjs");
|
|
18
17
|
const errors_1 = require("../errors.cjs");
|
|
19
18
|
const validate_login_response_1 = require("../utils/validate-login-response.cjs");
|
|
19
|
+
const services_1 = require("./services.cjs");
|
|
20
20
|
class SIWEJwtBearerAuth {
|
|
21
21
|
constructor(config, options) {
|
|
22
22
|
_SIWEJwtBearerAuth_instances.add(this);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-siwe.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,+BAAmC;AAEnC,
|
|
1
|
+
{"version":3,"file":"flow-siwe.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"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","sourcesContent":["import { SiweMessage } from 'siwe';\n\nimport { ValidationError } from '../errors';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n SIWE_LOGIN_URL,\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n} from './services';\nimport type {\n AuthConfig,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\n\ntype JwtBearerAuth_SIWE_Options = {\n storage: AuthStorageOptions;\n};\n\ntype JwtBearerAuth_SIWE_Signer = {\n address: string;\n chainId: number;\n signMessage: (message: string) => Promise<string>;\n domain: string;\n};\n\nexport class SIWEJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: JwtBearerAuth_SIWE_Options;\n\n #signer: JwtBearerAuth_SIWE_Signer | undefined;\n\n constructor(\n config: AuthConfig & { type: AuthType.SiWE },\n options: JwtBearerAuth_SIWE_Options,\n ) {\n this.#config = config;\n this.#options = options;\n }\n\n async getAccessToken(): Promise<string> {\n const session = await this.#getAuthSession();\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login();\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(): Promise<UserProfile> {\n const session = await this.#getAuthSession();\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login();\n return loginResponse.profile;\n }\n\n async getIdentifier(): Promise<string> {\n this.#assertSigner(this.#signer);\n return this.#signer.address;\n }\n\n async getUserProfileLineage(): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken();\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async signMessage(message: string): Promise<string> {\n this.#assertSigner(this.#signer);\n return await this.#signer.signMessage(message);\n }\n\n prepare(signer: JwtBearerAuth_SIWE_Signer) {\n this.#signer = signer;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse();\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(): Promise<LoginResponse> {\n this.#assertSigner(this.#signer);\n\n // Nonce\n const address = await this.getIdentifier();\n const nonceRes = await getNonce(address, this.#config.env);\n const rawMessage = this.#createSiWELoginRawMessage(nonceRes.nonce);\n const signature = await this.signMessage(rawMessage);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n );\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile: authResponse.profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result);\n\n return result;\n }\n\n #createSiWELoginRawMessage(nonce: string): string {\n this.#assertSigner(this.#signer);\n\n return new SiweMessage({\n domain: this.#signer?.domain,\n address: this.#signer?.address,\n uri: SIWE_LOGIN_URL(this.#config.env),\n version: '1',\n chainId: this.#signer?.chainId,\n nonce,\n issuedAt: new Date().toISOString(),\n }).prepareMessage();\n }\n\n #assertSigner(\n signer?: JwtBearerAuth_SIWE_Signer,\n ): asserts signer is JwtBearerAuth_SIWE_Signer {\n if (!signer) {\n throw new ValidationError(`you must call 'prepare()' before logging in`);\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-siwe.d.cts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"flow-siwe.d.cts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAEjB,KAAK,0BAA0B,GAAG;IAChC,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,iBAAkB,YAAW,SAAS;;gBAQ/C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;KAAE,EAC5C,OAAO,EAAE,0BAA0B;IAM/B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAUjC,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAUtC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAKhC,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKpD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnD,OAAO,CAAC,MAAM,EAAE,yBAAyB;CA6E1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-siwe.d.mts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"flow-siwe.d.mts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAEjB,KAAK,0BAA0B,GAAG;IAChC,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,iBAAkB,YAAW,SAAS;;gBAQ/C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;KAAE,EAC5C,OAAO,EAAE,0BAA0B;IAM/B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAUjC,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAUtC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAKhC,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKpD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnD,OAAO,CAAC,MAAM,EAAE,yBAAyB;CA6E1C"}
|
|
@@ -11,9 +11,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
};
|
|
12
12
|
var _SIWEJwtBearerAuth_instances, _SIWEJwtBearerAuth_config, _SIWEJwtBearerAuth_options, _SIWEJwtBearerAuth_signer, _SIWEJwtBearerAuth_getAuthSession, _SIWEJwtBearerAuth_login, _SIWEJwtBearerAuth_createSiWELoginRawMessage, _SIWEJwtBearerAuth_assertSigner;
|
|
13
13
|
import { SiweMessage } from "siwe";
|
|
14
|
-
import { SIWE_LOGIN_URL, authenticate, authorizeOIDC, getNonce, getUserProfileLineage } from "./services.mjs";
|
|
15
14
|
import { ValidationError } from "../errors.mjs";
|
|
16
15
|
import { validateLoginResponse } from "../utils/validate-login-response.mjs";
|
|
16
|
+
import { SIWE_LOGIN_URL, authenticate, authorizeOIDC, getNonce, getUserProfileLineage } from "./services.mjs";
|
|
17
17
|
export class SIWEJwtBearerAuth {
|
|
18
18
|
constructor(config, options) {
|
|
19
19
|
_SIWEJwtBearerAuth_instances.add(this);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-siwe.mjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,aAAa;AAEnC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,qBAAqB,EACtB,uBAAmB;
|
|
1
|
+
{"version":3,"file":"flow-siwe.mjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-siwe.ts"],"names":[],"mappings":"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","sourcesContent":["import { SiweMessage } from 'siwe';\n\nimport { ValidationError } from '../errors';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n SIWE_LOGIN_URL,\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n} from './services';\nimport type {\n AuthConfig,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\n\ntype JwtBearerAuth_SIWE_Options = {\n storage: AuthStorageOptions;\n};\n\ntype JwtBearerAuth_SIWE_Signer = {\n address: string;\n chainId: number;\n signMessage: (message: string) => Promise<string>;\n domain: string;\n};\n\nexport class SIWEJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: JwtBearerAuth_SIWE_Options;\n\n #signer: JwtBearerAuth_SIWE_Signer | undefined;\n\n constructor(\n config: AuthConfig & { type: AuthType.SiWE },\n options: JwtBearerAuth_SIWE_Options,\n ) {\n this.#config = config;\n this.#options = options;\n }\n\n async getAccessToken(): Promise<string> {\n const session = await this.#getAuthSession();\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login();\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(): Promise<UserProfile> {\n const session = await this.#getAuthSession();\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login();\n return loginResponse.profile;\n }\n\n async getIdentifier(): Promise<string> {\n this.#assertSigner(this.#signer);\n return this.#signer.address;\n }\n\n async getUserProfileLineage(): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken();\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async signMessage(message: string): Promise<string> {\n this.#assertSigner(this.#signer);\n return await this.#signer.signMessage(message);\n }\n\n prepare(signer: JwtBearerAuth_SIWE_Signer) {\n this.#signer = signer;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse();\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(): Promise<LoginResponse> {\n this.#assertSigner(this.#signer);\n\n // Nonce\n const address = await this.getIdentifier();\n const nonceRes = await getNonce(address, this.#config.env);\n const rawMessage = this.#createSiWELoginRawMessage(nonceRes.nonce);\n const signature = await this.signMessage(rawMessage);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n );\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile: authResponse.profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result);\n\n return result;\n }\n\n #createSiWELoginRawMessage(nonce: string): string {\n this.#assertSigner(this.#signer);\n\n return new SiweMessage({\n domain: this.#signer?.domain,\n address: this.#signer?.address,\n uri: SIWE_LOGIN_URL(this.#config.env),\n version: '1',\n chainId: this.#signer?.chainId,\n nonce,\n issuedAt: new Date().toISOString(),\n }).prepareMessage();\n }\n\n #assertSigner(\n signer?: JwtBearerAuth_SIWE_Signer,\n ): asserts signer is JwtBearerAuth_SIWE_Signer {\n if (!signer) {\n throw new ValidationError(`you must call 'prepare()' before logging in`);\n }\n }\n}\n"]}
|
|
@@ -36,12 +36,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
36
36
|
var _SRPJwtBearerAuth_instances, _SRPJwtBearerAuth_config, _SRPJwtBearerAuth_options, _SRPJwtBearerAuth_metametrics, _SRPJwtBearerAuth_ongoingLogins, _SRPJwtBearerAuth_cooldownDefaultMs, _SRPJwtBearerAuth_maxLoginRetries, _SRPJwtBearerAuth_customProvider, _SRPJwtBearerAuth_getAuthSession, _SRPJwtBearerAuth_login, _SRPJwtBearerAuth_performLogin, _SRPJwtBearerAuth_deferredLogin, _SRPJwtBearerAuth_loginWithRetry, _SRPJwtBearerAuth_createSrpLoginRawMessage;
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
38
|
exports.SRPJwtBearerAuth = void 0;
|
|
39
|
-
const services_1 = require("./services.cjs");
|
|
40
|
-
const timeUtils = __importStar(require("./utils/time.cjs"));
|
|
41
39
|
const errors_1 = require("../errors.cjs");
|
|
42
40
|
const eip_6963_metamask_provider_1 = require("../utils/eip-6963-metamask-provider.cjs");
|
|
43
41
|
const messaging_signing_snap_requests_1 = require("../utils/messaging-signing-snap-requests.cjs");
|
|
44
42
|
const validate_login_response_1 = require("../utils/validate-login-response.cjs");
|
|
43
|
+
const services_1 = require("./services.cjs");
|
|
44
|
+
const identifier_1 = require("./utils/identifier.cjs");
|
|
45
|
+
const timeUtils = __importStar(require("./utils/time.cjs"));
|
|
45
46
|
const getDefaultEIP6963Provider = async () => {
|
|
46
47
|
const provider = await (0, eip_6963_metamask_provider_1.getMetaMaskProviderEIP6963)();
|
|
47
48
|
if (!provider) {
|
|
@@ -113,6 +114,9 @@ class SRPJwtBearerAuth {
|
|
|
113
114
|
const accessToken = await this.getAccessToken(entropySourceId);
|
|
114
115
|
return await (0, services_1.getUserProfileLineage)(__classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, accessToken);
|
|
115
116
|
}
|
|
117
|
+
async pairSrpProfiles(accessTokens, authAccessToken) {
|
|
118
|
+
return await (0, services_1.pairProfiles)(accessTokens, authAccessToken, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
|
|
119
|
+
}
|
|
116
120
|
async signMessage(message, entropySourceId) {
|
|
117
121
|
return await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").signing.signMessage(message, entropySourceId);
|
|
118
122
|
}
|
|
@@ -138,6 +142,10 @@ async function _SRPJwtBearerAuth_getAuthSession(entropySourceId) {
|
|
|
138
142
|
if (!(0, validate_login_response_1.validateLoginResponse)(auth)) {
|
|
139
143
|
return null;
|
|
140
144
|
}
|
|
145
|
+
// get canonical profile id from server if not present in the cached session
|
|
146
|
+
if (!auth.profile.canonicalProfileId) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
141
149
|
const currentTime = Date.now();
|
|
142
150
|
const sessionAge = currentTime - auth.token.obtainedAt;
|
|
143
151
|
const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;
|
|
@@ -156,11 +164,30 @@ async function _SRPJwtBearerAuth_getAuthSession(entropySourceId) {
|
|
|
156
164
|
const signature = await this.signMessage(rawMessage, entropySourceId);
|
|
157
165
|
// Authenticate
|
|
158
166
|
const authResponse = await (0, services_1.authenticate)(rawMessage, signature, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").type, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_metametrics, "f"));
|
|
167
|
+
// Resolve original profileId from aliases.
|
|
168
|
+
// This is done mainly to preserve the original profileId for storage key derivation
|
|
169
|
+
// until we migrate to the canonical profileId storage system.
|
|
170
|
+
const canonicalProfileId = authResponse.profile.profileId;
|
|
171
|
+
const profile = { ...authResponse.profile };
|
|
172
|
+
if (authResponse.profileAliases?.length > 0) {
|
|
173
|
+
const targetIdentifierId = (0, identifier_1.computeIdentifierId)(publicKey, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
|
|
174
|
+
const matchingAliases = authResponse.profileAliases.filter((alias) => alias.identifierIds.some((id) => id.id === targetIdentifierId));
|
|
175
|
+
// Prefer the leaf alias (single identifier) — it's the original profile
|
|
176
|
+
// created for this SRP. Multi-identifier aliases are former canonicals
|
|
177
|
+
// that absorbed other profiles; they are correct only when this SRP's
|
|
178
|
+
// original profile was itself a canonical before being absorbed.
|
|
179
|
+
const targetAlias = matchingAliases.find((alias) => alias.identifierIds.length === 1) ??
|
|
180
|
+
matchingAliases[0];
|
|
181
|
+
if (targetAlias) {
|
|
182
|
+
profile.profileId = targetAlias.aliasProfileId;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
profile.canonicalProfileId = canonicalProfileId;
|
|
159
186
|
// Authorize
|
|
160
187
|
const tokenResponse = await (0, services_1.authorizeOIDC)(authResponse.token, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").platform);
|
|
161
188
|
// Save
|
|
162
189
|
const result = {
|
|
163
|
-
profile
|
|
190
|
+
profile,
|
|
164
191
|
token: tokenResponse,
|
|
165
192
|
};
|
|
166
193
|
await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").storage.setLoginResponse(result, entropySourceId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-srp.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n} from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport * as timeUtils from './utils/time';\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile: authResponse.profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"flow-srp.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,0CAA8D;AAC9D,wFAAiF;AACjF,kGAKkD;AAClD,kFAAyE;AACzE,6CAMoB;AAYpB,uDAAyD;AACzD,4DAA0C;AAW1C,MAAM,yBAAyB,GAAG,KAAK,IAAI,EAAE;IAC3C,MAAM,QAAQ,GAAG,MAAM,IAAA,uDAA0B,GAAE,CAAC;IACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,wBAAe,CAAC,8BAA8B,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,+BAA+B,GAAG,CACtC,cAAgC,EACZ,EAAE,CAAC,CAAC;IACxB,aAAa,EAAE,KAAK,EAAE,eAAwB,EAAmB,EAAE;QACjE,MAAM,QAAQ,GAAG,cAAc,IAAI,CAAC,MAAM,yBAAyB,EAAE,CAAC,CAAC;QACvE,OAAO,MAAM,sDAAoB,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAC5E,CAAC;IACD,WAAW,EAAE,KAAK,EAChB,OAAe,EACf,eAAwB,EACP,EAAE;QACnB,MAAM,QAAQ,GAAG,cAAc,IAAI,CAAC,MAAM,yBAAyB,EAAE,CAAC,CAAC;QACvE,IAAA,iEAA+B,EAAC,OAAO,CAAC,CAAC;QACzC,OAAO,MAAM,sDAAoB,CAAC,WAAW,CAC3C,QAAQ,EACR,OAAO,EACP,eAAe,CAChB,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,MAAa,gBAAgB;IAwB3B,YACE,MAA2C,EAC3C,OAGC;;QA5BM,2CAAoB;QAEpB,4CAGP;QAEO,gDAA+B;QAExC,yDAAyD;QAChD,0CAAiB,IAAI,GAAG,EAG9B,EAAC;QAEJ,sDAAsD;QAC7C,sDAA2B;QAEpC,uDAAuD;QAC9C,oDAAyB;QAElC,mDAAkC;QAShC,uBAAA,IAAI,4BAAW,MAAM,MAAA,CAAC;QACtB,uBAAA,IAAI,oCAAmB,OAAO,CAAC,cAAc,MAAA,CAAC;QAC9C,uBAAA,IAAI,6BAAY;YACd,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EACL,OAAO,CAAC,OAAO;gBACf,+BAA+B,CAAC,uBAAA,IAAI,wCAAgB,CAAC;SACxD,MAAA,CAAC;QACF,uBAAA,IAAI,iCAAgB,OAAO,CAAC,WAAW,MAAA,CAAC;QAExC,4CAA4C;QAC5C,uBAAA,IAAI,uCACF,OAAO,CAAC,cAAc,EAAE,iBAAiB,IAAI,KAAK,MAAA,CAAC;QACrD,uBAAA,IAAI,qCAAoB,OAAO,CAAC,cAAc,EAAE,eAAe,IAAI,CAAC,MAAA,CAAC;IACvE,CAAC;IAED,iBAAiB,CAAC,QAAyB;QACzC,uBAAA,IAAI,oCAAmB,QAAQ,MAAA,CAAC;QAChC,uBAAA,IAAI,iCAAS,CAAC,OAAO,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;IACpE,CAAC;IAED,0HAA0H;IAC1H,KAAK,CAAC,cAAc,CAAC,eAAwB;QAC3C,MAAM,OAAO,GAAG,MAAM,uBAAA,IAAI,qEAAgB,MAApB,IAAI,EAAiB,eAAe,CAAC,CAAC;QAC5D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;QACnC,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,4DAAO,MAAX,IAAI,EAAQ,eAAe,CAAC,CAAC;QACzD,OAAO,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,eAAwB;QAC3C,MAAM,OAAO,GAAG,MAAM,uBAAA,IAAI,qEAAgB,MAApB,IAAI,EAAiB,eAAe,CAAC,CAAC;QAC5D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC,OAAO,CAAC;QACzB,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,4DAAO,MAAX,IAAI,EAAQ,eAAe,CAAC,CAAC;QACzD,OAAO,aAAa,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,eAAwB;QAC1C,OAAO,MAAM,uBAAA,IAAI,iCAAS,CAAC,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,qBAAqB,CACzB,eAAwB;QAExB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/D,OAAO,MAAM,IAAA,gCAAqB,EAAC,uBAAA,IAAI,gCAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,YAAsB,EACtB,eAAuB;QAEvB,OAAO,MAAM,IAAA,uBAAY,EAAC,YAAY,EAAE,eAAe,EAAE,uBAAA,IAAI,gCAAQ,CAAC,GAAG,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAe,EACf,eAAwB;QAExB,OAAO,MAAM,uBAAA,IAAI,iCAAS,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,QAAQ,GACZ,uBAAA,IAAI,wCAAgB,IAAI,CAAC,MAAM,yBAAyB,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,IAAA,iDAAe,EAAC,QAAQ,CAAC,CAAC;QACpD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,QAAQ,GACZ,uBAAA,IAAI,wCAAgB,IAAI,CAAC,MAAM,yBAAyB,EAAE,CAAC,CAAC;QAE9D,MAAM,GAAG,GAAG,MAAM,IAAA,6CAAW,EAAC,QAAQ,CAAC,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC;CA4JF;AA/QD,4CA+QC;;AA1JC,0EAA0E;AAC1E,KAAK,2CACH,eAAwB;IAExB,MAAM,IAAI,GAAG,MAAM,uBAAA,IAAI,iCAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC3E,IAAI,CAAC,IAAA,+CAAqB,EAAC,IAAI,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IACvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,GAAG,GAAG,CAAC;IAE3D,IAAI,UAAU,GAAG,gBAAgB,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,4BAED,KAAK,kCAAQ,eAAwB;IACnC,gDAAgD;IAChD,OAAO,MAAM,uBAAA,IAAI,oEAAe,MAAnB,IAAI,EAAgB,eAAe,CAAC,CAAC;AACpD,CAAC,mCAED,KAAK,yCAAe,eAAwB;IAC1C,QAAQ;IACR,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,IAAA,mBAAQ,EAAC,SAAS,EAAE,uBAAA,IAAI,gCAAQ,CAAC,GAAG,CAAC,CAAC;IAE7D,MAAM,UAAU,GAAG,uBAAA,IAAI,+EAA0B,MAA9B,IAAI,EACrB,QAAQ,CAAC,KAAK,EACd,SAAS,CACV,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IAEtE,eAAe;IACf,MAAM,YAAY,GAAG,MAAM,IAAA,uBAAY,EACrC,UAAU,EACV,SAAS,EACT,uBAAA,IAAI,gCAAQ,CAAC,IAAI,EACjB,uBAAA,IAAI,gCAAQ,CAAC,GAAG,EAChB,uBAAA,IAAI,qCAAa,CAClB,CAAC;IAEF,2CAA2C;IAC3C,oFAAoF;IACpF,8DAA8D;IAC9D,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1D,MAAM,OAAO,GAAG,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC;IAE5C,IAAI,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,kBAAkB,GAAG,IAAA,gCAAmB,EAC5C,SAAS,EACT,uBAAA,IAAI,gCAAQ,CAAC,GAAG,CACjB,CAAC;QAEF,MAAM,eAAe,GAAG,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CACnE,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,kBAAkB,CAAC,CAC/D,CAAC;QAEF,wEAAwE;QACxE,uEAAuE;QACvE,sEAAsE;QACtE,iEAAiE;QACjE,MAAM,WAAW,GACf,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC;YACjE,eAAe,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,cAAc,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;IAEhD,YAAY;IACZ,MAAM,aAAa,GAAG,MAAM,IAAA,wBAAa,EACvC,YAAY,CAAC,KAAK,EAClB,uBAAA,IAAI,gCAAQ,CAAC,GAAG,EAChB,uBAAA,IAAI,gCAAQ,CAAC,QAAQ,CACtB,CAAC;IAEF,OAAO;IACP,MAAM,MAAM,GAAkB;QAC5B,OAAO;QACP,KAAK,EAAE,aAAa;KACrB,CAAC;IAEF,MAAM,uBAAA,IAAI,iCAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEtE,OAAO,MAAM,CAAC;AAChB,CAAC,oCAED,KAAK,0CAAgB,eAAwB;IAC3C,qEAAqE;IACrE,MAAM,aAAa,GAAG,uBAAA,IAAI,uCAAe,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC/D,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,6BAA6B;IAC7B,MAAM,YAAY,GAAG,uBAAA,IAAI,qEAAgB,MAApB,IAAI,EAAiB,eAAe,CAAC,CAAC;IAE3D,+BAA+B;IAC/B,uBAAA,IAAI,uCAAe,CAAC,GAAG,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IAEvD,IAAI,CAAC;QACH,iCAAiC;QACjC,OAAO,MAAM,YAAY,CAAC;IAC5B,CAAC;YAAS,CAAC;QACT,sDAAsD;QACtD,uBAAA,IAAI,uCAAe,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,qCAED,KAAK,2CAAiB,eAAwB;IAC5C,uDAAuD;IACvD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,GAAG,uBAAA,IAAI,yCAAiB,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC;YACH,OAAO,MAAM,uBAAA,IAAI,mEAAc,MAAlB,IAAI,EAAe,eAAe,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,wCAAwC;YACxC,IAAI,CAAC,yBAAgB,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,MAAM,CAAC,CAAC;YACV,CAAC;YAED,uCAAuC;YACvC,IAAI,OAAO,IAAI,uBAAA,IAAI,yCAAiB,EAAE,CAAC;gBACrC,MAAM,CAAC,CAAC;YACV,CAAC;YAED,2CAA2C;YAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,IAAI,uBAAA,IAAI,2CAAmB,CAAC;YACzD,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAE9B,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;AACrE,CAAC,mGAGC,KAAa,EACb,SAAiB;IAEjB,OAAO,YAAY,KAAK,IAAI,SAAS,EAAW,CAAC;AACnD,CAAC","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n pairProfiles,\n} from './services';\nimport type { PairProfilesResponse } from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport { computeIdentifierId } from './utils/identifier';\nimport * as timeUtils from './utils/time';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async pairSrpProfiles(\n accessTokens: string[],\n authAccessToken: string,\n ): Promise<PairProfilesResponse> {\n return await pairProfiles(accessTokens, authAccessToken, this.#config.env);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n // get canonical profile id from server if not present in the cached session\n if (!auth.profile.canonicalProfileId) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Resolve original profileId from aliases.\n // This is done mainly to preserve the original profileId for storage key derivation\n // until we migrate to the canonical profileId storage system.\n const canonicalProfileId = authResponse.profile.profileId;\n const profile = { ...authResponse.profile };\n\n if (authResponse.profileAliases?.length > 0) {\n const targetIdentifierId = computeIdentifierId(\n publicKey,\n this.#config.env,\n );\n\n const matchingAliases = authResponse.profileAliases.filter((alias) =>\n alias.identifierIds.some((id) => id.id === targetIdentifierId),\n );\n\n // Prefer the leaf alias (single identifier) — it's the original profile\n // created for this SRP. Multi-identifier aliases are former canonicals\n // that absorbed other profiles; they are correct only when this SRP's\n // original profile was itself a canonical before being absorbed.\n const targetAlias =\n matchingAliases.find((alias) => alias.identifierIds.length === 1) ??\n matchingAliases[0];\n\n if (targetAlias) {\n profile.profileId = targetAlias.aliasProfileId;\n }\n }\n\n profile.canonicalProfileId = canonicalProfileId;\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
|