|  | @ -26,12 +26,11 @@ import "dexie-export-import"; | 
			
		
	
		
		
			
				
					|  |  | import { PlatformServiceFactory } from "./PlatformServiceFactory"; |  |  | import { PlatformServiceFactory } from "./PlatformServiceFactory"; | 
			
		
	
		
		
			
				
					|  |  | import { db, accountsDBPromise } from "../db/index"; |  |  | import { db, accountsDBPromise } from "../db/index"; | 
			
		
	
		
		
			
				
					|  |  | import { Contact, ContactMethod } from "../db/tables/contacts"; |  |  | import { Contact, ContactMethod } from "../db/tables/contacts"; | 
			
		
	
		
		
			
				
					
					|  |  | import { Settings, MASTER_SETTINGS_KEY, SettingsWithJsonStrings, BoundingBox } from "../db/tables/settings"; |  |  | import { Settings, MASTER_SETTINGS_KEY, BoundingBox } from "../db/tables/settings"; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | import { Account, AccountEncrypted } from "../db/tables/accounts"; |  |  | import { Account } from "../db/tables/accounts"; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  | import { logger } from "../utils/logger"; |  |  | import { logger } from "../utils/logger"; | 
			
		
	
		
		
			
				
					
					|  |  | import { mapColumnsToValues, parseJsonField } from "../db/databaseUtil"; |  |  | import { mapColumnsToValues, parseJsonField, generateUpdateStatement, generateInsertStatement } from "../db/databaseUtil"; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  | import { importFromMnemonic } from "../libs/util"; |  |  | import { importFromMnemonic } from "../libs/util"; | 
			
		
	
		
		
			
				
					|  |  | import { IIdentifier } from "@veramo/core"; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | /** |  |  | /** | 
			
		
	
		
		
			
				
					|  |  |  * Interface for data comparison results between Dexie and SQLite databases |  |  |  * Interface for data comparison results between Dexie and SQLite databases | 
			
		
	
	
		
		
			
				
					|  | @ -1028,228 +1027,47 @@ export async function migrateSettings( | 
			
		
	
		
		
			
				
					|  |  |   try { |  |  |   try { | 
			
		
	
		
		
			
				
					|  |  |     const dexieSettings = await getDexieSettings(); |  |  |     const dexieSettings = await getDexieSettings(); | 
			
		
	
		
		
			
				
					|  |  |     const platformService = PlatformServiceFactory.getInstance(); |  |  |     const platformService = PlatformServiceFactory.getInstance(); | 
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |     // loop through dexieSettings,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     // Group settings by DID to handle duplicates
 |  |  |     // load the one with the matching accountDid from sqlite,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     const settingsByDid = new Map<string, { |  |  |     // and if one doesn't exist then insert it,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |       master?: Settings; |  |  |     // otherwise, update the fields
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |       account?: Settings; |  |  |     dexieSettings.forEach(async (setting) => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     }>(); |  |  |       const sqliteSettingRaw = await platformService.dbQuery( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |         "SELECT * FROM settings WHERE accountDid = ?", | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     // Organize settings by DID
 |  |  |         [setting.accountDid] | 
			
				
				
			
		
	
		
		
			
				
					|  |  |     dexieSettings.forEach(setting => { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       const isMasterSetting = setting.id === MASTER_SETTINGS_KEY; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       const did = isMasterSetting ? setting.activeDid : setting.accountDid; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |        |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       if (!did) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         result.warnings.push(`Setting ${setting.id} has no DID, skipping`); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         return; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       if (!settingsByDid.has(did)) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         settingsByDid.set(did, {}); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       const didSettings = settingsByDid.get(did)!; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       if (isMasterSetting) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         didSettings.master = setting; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         logger.info("[MigrationService] Found master settings", {  |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           id: setting.id, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           firstName: setting.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           isRegistered: setting.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           profileImageUrl: setting.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           showShortcutBvc: setting.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           searchBoxes: setting.searchBoxes |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       } else { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         didSettings.account = setting; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         logger.info("[MigrationService] Found account settings", {  |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           id: setting.id, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           firstName: setting.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           isRegistered: setting.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           profileImageUrl: setting.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           showShortcutBvc: setting.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           searchBoxes: setting.searchBoxes |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       } |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     // Process each unique DID's settings
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     for (const [did, didSettings] of settingsByDid.entries()) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       try { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         // Process master settings
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         if (didSettings.master) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           const masterData = { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             id: MASTER_SETTINGS_KEY, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             activeDid: did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             accountDid: "", // Empty for master settings
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             apiServer: didSettings.master.apiServer || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             filterFeedByNearby: didSettings.master.filterFeedByNearby || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             filterFeedByVisible: didSettings.master.filterFeedByVisible || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             finishedOnboarding: didSettings.master.finishedOnboarding || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             firstName: didSettings.master.firstName || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             hideRegisterPromptOnNewContact: didSettings.master.hideRegisterPromptOnNewContact || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             isRegistered: didSettings.master.isRegistered || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             lastName: didSettings.master.lastName || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             profileImageUrl: didSettings.master.profileImageUrl || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             searchBoxes: didSettings.master.searchBoxes || [], |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             showShortcutBvc: didSettings.master.showShortcutBvc || false |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           // Check if master setting exists
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           const existingMaster = await platformService.dbQuery( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             "SELECT id FROM settings WHERE id = ? AND activeDid = ? AND accountDid = ''", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             [MASTER_SETTINGS_KEY, did] |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           ); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           if (existingMaster?.values?.length) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             logger.info("[MigrationService] Updating master settings", { did, masterData }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             await platformService.dbQuery( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               `UPDATE settings SET 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 activeDid = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountDid = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 firstName = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 isRegistered = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 profileImageUrl = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 showShortcutBvc = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 searchBoxes = ? |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               WHERE id = ?`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.activeDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 JSON.stringify(masterData.searchBoxes), |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 MASTER_SETTINGS_KEY |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ] |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |       ); |  |  |       ); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |       if (sqliteSettingRaw?.values?.length) { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         // should cover the master settings, were accountDid is null
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         const sqliteSetting = mapColumnsToValues(sqliteSettingRaw.columns, sqliteSettingRaw.values) as unknown as Settings; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         let conditional: string; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         let preparams: unknown[]; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         if (!setting.accountDid) { | 
			
		
	
		
		
			
				
					|  |  |  |  |  |           conditional = "accountDid is null"; | 
			
		
	
		
		
			
				
					|  |  |  |  |  |           preparams = []; | 
			
		
	
		
		
			
				
					|  |  |         } else { |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |             logger.info("[MigrationService] Inserting master settings", { did, masterData }); |  |  |           conditional = "accountDid = ?"; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |             await platformService.dbQuery( |  |  |           preparams = [setting.accountDid]; | 
			
				
				
			
		
	
		
		
			
				
					|  |  |               `INSERT INTO settings (
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 id, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 activeDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 searchBoxes |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 MASTER_SETTINGS_KEY, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.activeDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 masterData.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 JSON.stringify(masterData.searchBoxes) |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ] |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             ); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           } |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           result.settingsMigrated++; |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |         const { sql, params } = generateUpdateStatement( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         // Process account settings
 |  |  |           sqliteSetting as unknown as Record<string, unknown>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         if (didSettings.account) { |  |  |           "settings", | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |           const accountData = { |  |  |           conditional, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |             id: 2, // Account settings always use id 2
 |  |  |           preparams | 
			
				
				
			
		
	
		
		
			
				
					|  |  |             activeDid: "", // Empty for account settings
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             accountDid: did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             apiServer: didSettings.account.apiServer || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             filterFeedByNearby: didSettings.account.filterFeedByNearby || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             filterFeedByVisible: didSettings.account.filterFeedByVisible || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             finishedOnboarding: didSettings.account.finishedOnboarding || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             firstName: didSettings.account.firstName || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             hideRegisterPromptOnNewContact: didSettings.account.hideRegisterPromptOnNewContact || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             isRegistered: didSettings.account.isRegistered || false, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             lastName: didSettings.account.lastName || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             profileImageUrl: didSettings.account.profileImageUrl || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             searchBoxes: didSettings.account.searchBoxes || [], |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             showShortcutBvc: didSettings.account.showShortcutBvc || false |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           // Check if account setting exists
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           const existingAccount = await platformService.dbQuery( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             "SELECT id FROM settings WHERE id = ? AND accountDid = ? AND activeDid = ''", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             [2, did] |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           ); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           if (existingAccount?.values?.length) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             logger.info("[MigrationService] Updating account settings", { did, accountData }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             await platformService.dbQuery( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               `UPDATE settings SET 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 activeDid = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountDid = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 firstName = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 isRegistered = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 profileImageUrl = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 showShortcutBvc = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 searchBoxes = ? |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               WHERE id = ?`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.activeDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 JSON.stringify(accountData.searchBoxes), |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 2 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ] |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |         ); |  |  |         ); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         await platformService.dbExec(sql, params); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         result.settingsMigrated++; | 
			
		
	
		
		
			
				
					|  |  |       } else { |  |  |       } else { | 
			
		
	
		
		
			
				
					
					|  |  |             logger.info("[MigrationService] Inserting account settings", { did, accountData }); |  |  |         // insert new setting
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |             await platformService.dbQuery( |  |  |         delete setting.activeDid; // ensure we don't set the activeDid (since master settings are an update and don't hit this case)
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |               `INSERT INTO settings (
 |  |  |         const { sql, params } = generateInsertStatement( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |                 id, |  |  |           setting as unknown as Record<string, unknown>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |                 activeDid, |  |  |           "settings" | 
			
				
				
			
		
	
		
		
			
				
					|  |  |                 accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 searchBoxes |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 2, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.activeDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.accountDid, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.firstName, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.isRegistered, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.profileImageUrl, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 accountData.showShortcutBvc, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |                 JSON.stringify(accountData.searchBoxes) |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               ] |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |         ); |  |  |         ); | 
			
		
	
		
		
			
				
					
					|  |  |           } |  |  |         await platformService.dbExec(sql, params); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |         result.settingsMigrated++; |  |  |         result.settingsMigrated++; | 
			
		
	
		
		
			
				
					|  |  |       } |  |  |       } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         logger.info("[MigrationService] Successfully migrated settings for DID", { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           masterMigrated: !!didSettings.master, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           accountMigrated: !!didSettings.account |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     }); |  |  |     }); | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |       } catch (error) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         const errorMessage = `Failed to migrate settings for DID ${did}: ${error}`; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         result.errors.push(errorMessage); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         logger.error("[MigrationService] Settings migration failed:", { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           error, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           did |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       } |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (result.errors.length > 0) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       result.success = false; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     return result; |  |  |     return result; | 
			
		
	
		
		
			
				
					|  |  |   } catch (error) { |  |  |   } catch (error) { | 
			
		
	
		
		
			
				
					|  |  |     const errorMessage = `Settings migration failed: ${error}`; |  |  |     const errorMessage = `Settings migration failed: ${error}`; | 
			
		
	
	
		
		
			
				
					|  | @ -1277,7 +1095,6 @@ export async function migrateSettings( | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  * | 
			
		
	
		
		
			
				
					|  |  |  * @async |  |  |  * @async | 
			
		
	
		
		
			
				
					|  |  |  * @function migrateAccounts |  |  |  * @function migrateAccounts | 
			
		
	
		
		
			
				
					|  |  |  * @param {boolean} [overwriteExisting=false] - Whether to overwrite existing accounts in SQLite |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {Promise<MigrationResult>} Detailed results of the migration operation |  |  |  * @returns {Promise<MigrationResult>} Detailed results of the migration operation | 
			
		
	
		
		
			
				
					|  |  |  * @throws {Error} If the migration process fails completely |  |  |  * @throws {Error} If the migration process fails completely | 
			
		
	
		
		
			
				
					|  |  |  * @example |  |  |  * @example | 
			
		
	
	
		
		
			
				
					|  | @ -1294,12 +1111,8 @@ export async function migrateSettings( | 
			
		
	
		
		
			
				
					|  |  |  * } |  |  |  * } | 
			
		
	
		
		
			
				
					|  |  |  * ``` |  |  |  * ``` | 
			
		
	
		
		
			
				
					|  |  |  */ |  |  |  */ | 
			
		
	
		
		
			
				
					
					|  |  | export async function migrateAccounts( |  |  | export async function migrateAccounts(): Promise<MigrationResult> { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |   overwriteExisting: boolean = false, |  |  |   logger.info("[MigrationService] Starting account migration"); | 
			
				
				
			
		
	
		
		
			
				
					|  |  | ): Promise<MigrationResult> { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   logger.info("[MigrationService] Starting account migration", { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     overwriteExisting, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   }); |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |   const result: MigrationResult = { |  |  |   const result: MigrationResult = { | 
			
		
	
		
		
			
				
					|  |  |     success: true, |  |  |     success: true, | 
			
		
	
	
		
		
			
				
					|  | @ -1335,67 +1148,17 @@ export async function migrateAccounts( | 
			
		
	
		
		
			
				
					|  |  |           [did] |  |  |           [did] | 
			
		
	
		
		
			
				
					|  |  |         ); |  |  |         ); | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |         if (existingResult?.values?.length && !overwriteExisting) { |  |  |         if (existingResult?.values?.length) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |           result.warnings.push(`Account with DID ${did} already exists, skipping`); |  |  |           result.warnings.push(`Account with DID ${did} already exists, skipping`); | 
			
		
	
		
		
			
				
					|  |  |           continue; |  |  |           continue; | 
			
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |         if (account.mnemonic) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         // Map Dexie fields to SQLite fields
 |  |  |           await importFromMnemonic(account.mnemonic, account.derivationPath); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         const accountData = { |  |  |           result.accountsMigrated++; | 
			
				
				
			
		
	
		
		
			
				
					|  |  |           did: account.did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           dateCreated: account.dateCreated, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           derivationPath: account.derivationPath || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           identityEncrBase64: account.identity || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           mnemonicEncrBase64: account.mnemonic || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           passkeyCredIdHex: account.passkeyCredIdHex || "", |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           publicKeyHex: account.publicKeyHex || "" |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         // Insert or update the account
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         if (existingResult?.values?.length) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           await platformService.dbQuery( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             `UPDATE accounts SET 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               dateCreated = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               derivationPath = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               identityEncrBase64 = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               mnemonicEncrBase64 = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               passkeyCredIdHex = ?, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               publicKeyHex = ? |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             WHERE did = ?`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.dateCreated, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.derivationPath, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.identityEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.mnemonicEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.passkeyCredIdHex, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.publicKeyHex, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               did |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             ] |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           ); |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |         } else { |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |           await platformService.dbQuery( |  |  |           result.errors.push(`Account with DID ${did} has no mnemonic, skipping`); | 
			
				
				
			
		
	
		
		
			
				
					|  |  |             `INSERT INTO accounts (
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               dateCreated, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               derivationPath, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               identityEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               mnemonicEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               passkeyCredIdHex, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               publicKeyHex |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             ) VALUES (?, ?, ?, ?, ?, ?, ?)`,
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             [ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               did, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.dateCreated, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.derivationPath, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.identityEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.mnemonicEncrBase64, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.passkeyCredIdHex, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |               accountData.publicKeyHex |  |  |  | 
			
		
	
		
		
			
				
					|  |  |             ] |  |  |  | 
			
		
	
		
		
			
				
					|  |  |           ); |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |         result.accountsMigrated++; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         logger.info("[MigrationService] Successfully migrated account", { |  |  |         logger.info("[MigrationService] Successfully migrated account", { | 
			
		
	
		
		
			
				
					|  |  |           did, |  |  |           did, | 
			
		
	
		
		
			
				
					|  |  |           dateCreated: account.dateCreated |  |  |           dateCreated: account.dateCreated | 
			
		
	
	
		
		
			
				
					|  | @ -1424,99 +1187,6 @@ export async function migrateAccounts( | 
			
		
	
		
		
			
				
					|  |  |   } |  |  |   } | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | /** |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * Generates SQL INSERT statement and parameters from a model object |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * This helper function creates a parameterized SQL INSERT statement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * from a JavaScript object. It filters out undefined values and |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * creates the appropriate SQL syntax with placeholders. |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * The function is used internally by the migration functions to |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * safely insert data into the SQLite database. |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @function generateInsertStatement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {Record<string, unknown>} model - The model object containing fields to insert |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {string} tableName - The name of the table to insert into |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {Object} Object containing the SQL statement and parameters array |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {string} returns.sql - The SQL INSERT statement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {unknown[]} returns.params - Array of parameter values |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @example |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * ```typescript
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * const contact = { did: 'did:example:123', name: 'John Doe' }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * const { sql, params } = generateInsertStatement(contact, 'contacts'); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * // sql: "INSERT INTO contacts (did, name) VALUES (?, ?)"
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * // params: ['did:example:123', 'John Doe']
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * ``` |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  */ |  |  |  | 
			
		
	
		
		
			
				
					|  |  | function generateInsertStatement( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   model: Record<string, unknown>, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   tableName: string, |  |  |  | 
			
		
	
		
		
			
				
					|  |  | ): { sql: string; params: unknown[] } { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const columns = Object.keys(model).filter((key) => model[key] !== undefined); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const values = Object.values(model).filter((value) => value !== undefined); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const placeholders = values.map(() => "?").join(", "); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   return { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     sql: insertSql, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     params: values, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | /** |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * Generates SQL UPDATE statement and parameters from a model object |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * This helper function creates a parameterized SQL UPDATE statement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * from a JavaScript object. It filters out undefined values and |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * creates the appropriate SQL syntax with placeholders. |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * The function is used internally by the migration functions to |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * safely update data in the SQLite database. |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @function generateUpdateStatement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {Record<string, unknown>} model - The model object containing fields to update |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {string} tableName - The name of the table to update |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {string} whereClause - The WHERE clause for the update (e.g. "id = ?") |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @param {unknown[]} [whereParams=[]] - Parameters for the WHERE clause |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {Object} Object containing the SQL statement and parameters array |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {string} returns.sql - The SQL UPDATE statement |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @returns {unknown[]} returns.params - Array of parameter values |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * @example |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * ```typescript
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * const contact = { name: 'Jane Doe' }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * const { sql, params } = generateUpdateStatement(contact, 'contacts', 'did = ?', ['did:example:123']); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * // sql: "UPDATE contacts SET name = ? WHERE did = ?"
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * // params: ['Jane Doe', 'did:example:123']
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * ``` |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  */ |  |  |  | 
			
		
	
		
		
			
				
					|  |  | function generateUpdateStatement( |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   model: Record<string, unknown>, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   tableName: string, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   whereClause: string, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   whereParams: unknown[] = [], |  |  |  | 
			
		
	
		
		
			
				
					|  |  | ): { sql: string; params: unknown[] } { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const setClauses: string[] = []; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const params: unknown[] = []; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   Object.entries(model).forEach(([key, value]) => { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (value !== undefined) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       setClauses.push(`${key} = ?`); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |       params.push(value); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   }); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   if (setClauses.length === 0) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     throw new Error("No valid fields to update"); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   const sql = `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE ${whereClause}`; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   return { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     sql, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     params: [...params, ...whereParams], |  |  |  | 
			
		
	
		
		
			
				
					|  |  |   }; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | /** |  |  | /** | 
			
		
	
		
		
			
				
					|  |  |  * Migrates all data from Dexie to SQLite in the proper order |  |  |  * Migrates all data from Dexie to SQLite in the proper order | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  * | 
			
		
	
	
		
		
			
				
					|  | @ -1551,7 +1221,7 @@ export async function migrateAll( | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     // Step 1: Migrate Accounts (foundational)
 |  |  |     // Step 1: Migrate Accounts (foundational)
 | 
			
		
	
		
		
			
				
					|  |  |     logger.info("[MigrationService] Step 1: Migrating accounts..."); |  |  |     logger.info("[MigrationService] Step 1: Migrating accounts..."); | 
			
		
	
		
		
			
				
					
					|  |  |     const accountsResult = await migrateAccounts(overwriteExisting); |  |  |     const accountsResult = await migrateAccounts(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |     if (!accountsResult.success) { |  |  |     if (!accountsResult.success) { | 
			
		
	
		
		
			
				
					|  |  |       result.errors.push( |  |  |       result.errors.push( | 
			
		
	
		
		
			
				
					|  |  |         `Account migration failed: ${accountsResult.errors.join(", ")}`, |  |  |         `Account migration failed: ${accountsResult.errors.join(", ")}`, | 
			
		
	
	
		
		
			
				
					|  | 
 |