|
|
@ -26,11 +26,12 @@ import "dexie-export-import"; |
|
|
|
import { PlatformServiceFactory } from "./PlatformServiceFactory"; |
|
|
|
import { db, accountsDBPromise } from "../db/index"; |
|
|
|
import { Contact, ContactMethod } from "../db/tables/contacts"; |
|
|
|
import { Settings, MASTER_SETTINGS_KEY } from "../db/tables/settings"; |
|
|
|
import { Account } from "../db/tables/accounts"; |
|
|
|
import { Settings, MASTER_SETTINGS_KEY, SettingsWithJsonStrings, BoundingBox } from "../db/tables/settings"; |
|
|
|
import { Account, AccountEncrypted } from "../db/tables/accounts"; |
|
|
|
import { logger } from "../utils/logger"; |
|
|
|
import { parseJsonField } from "../db/databaseUtil"; |
|
|
|
import { mapColumnsToValues, parseJsonField } from "../db/databaseUtil"; |
|
|
|
import { importFromMnemonic } from "../libs/util"; |
|
|
|
import { IIdentifier } from "@veramo/core"; |
|
|
|
|
|
|
|
/** |
|
|
|
* Interface for data comparison results between Dexie and SQLite databases |
|
|
@ -66,22 +67,24 @@ export interface DataComparison { |
|
|
|
dexieSettings: Settings[]; |
|
|
|
sqliteSettings: Settings[]; |
|
|
|
dexieAccounts: Account[]; |
|
|
|
sqliteAccounts: Account[]; |
|
|
|
sqliteAccounts: string[]; |
|
|
|
differences: { |
|
|
|
contacts: { |
|
|
|
added: Contact[]; |
|
|
|
modified: Contact[]; |
|
|
|
unmodified: Contact[]; |
|
|
|
missing: Contact[]; |
|
|
|
}; |
|
|
|
settings: { |
|
|
|
added: Settings[]; |
|
|
|
modified: Settings[]; |
|
|
|
unmodified: Settings[]; |
|
|
|
missing: Settings[]; |
|
|
|
}; |
|
|
|
accounts: { |
|
|
|
added: Account[]; |
|
|
|
modified: Account[]; |
|
|
|
missing: Account[]; |
|
|
|
unmodified: Account[]; |
|
|
|
missing: string[]; |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
@ -184,22 +187,14 @@ export async function getSqliteContacts(): Promise<Contact[]> { |
|
|
|
|
|
|
|
let contacts: Contact[] = []; |
|
|
|
if (result?.values?.length) { |
|
|
|
contacts = result.values.map((row) => { |
|
|
|
const contact = parseJsonField(row, {}) as Contact; |
|
|
|
return { |
|
|
|
did: contact.did || "", |
|
|
|
name: contact.name || "", |
|
|
|
contactMethods: parseJsonField( |
|
|
|
contact.contactMethods, |
|
|
|
[], |
|
|
|
) as ContactMethod[], |
|
|
|
nextPubKeyHashB64: contact.nextPubKeyHashB64 || "", |
|
|
|
notes: contact.notes || "", |
|
|
|
profileImageUrl: contact.profileImageUrl || "", |
|
|
|
publicKeyBase64: contact.publicKeyBase64 || "", |
|
|
|
seesMe: contact.seesMe || false, |
|
|
|
registered: contact.registered || false, |
|
|
|
} as Contact; |
|
|
|
const preContacts = mapColumnsToValues(result.columns, result.values) as unknown as Contact[]; |
|
|
|
// This is redundant since absurd-sql auto-parses JSON strings to objects.
|
|
|
|
// But we started it, and it should be known everywhere, so we're keeping it.
|
|
|
|
contacts = preContacts.map((contact) => { |
|
|
|
if (contact.contactMethods) { |
|
|
|
contact.contactMethods = parseJsonField(contact.contactMethods, []) as ContactMethod[]; |
|
|
|
} |
|
|
|
return contact; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
@ -281,37 +276,16 @@ export async function getSqliteSettings(): Promise<Settings[]> { |
|
|
|
|
|
|
|
let settings: Settings[] = []; |
|
|
|
if (result?.values?.length) { |
|
|
|
settings = result.values.map((row) => { |
|
|
|
const setting = parseJsonField(row, {}) as Settings; |
|
|
|
return { |
|
|
|
id: setting.id, |
|
|
|
accountDid: setting.accountDid || "", |
|
|
|
activeDid: setting.activeDid || "", |
|
|
|
apiServer: setting.apiServer || "", |
|
|
|
filterFeedByNearby: setting.filterFeedByNearby || false, |
|
|
|
filterFeedByVisible: setting.filterFeedByVisible || false, |
|
|
|
finishedOnboarding: setting.finishedOnboarding || false, |
|
|
|
firstName: setting.firstName || "", |
|
|
|
hideRegisterPromptOnNewContact: setting.hideRegisterPromptOnNewContact || false, |
|
|
|
isRegistered: setting.isRegistered || false, |
|
|
|
lastName: setting.lastName || "", |
|
|
|
lastAckedOfferToUserJwtId: setting.lastAckedOfferToUserJwtId || "", |
|
|
|
lastAckedOfferToUserProjectsJwtId: setting.lastAckedOfferToUserProjectsJwtId || "", |
|
|
|
lastNotifiedClaimId: setting.lastNotifiedClaimId || "", |
|
|
|
lastViewedClaimId: setting.lastViewedClaimId || "", |
|
|
|
notifyingNewActivityTime: setting.notifyingNewActivityTime || "", |
|
|
|
notifyingReminderMessage: setting.notifyingReminderMessage || "", |
|
|
|
notifyingReminderTime: setting.notifyingReminderTime || "", |
|
|
|
partnerApiServer: setting.partnerApiServer || "", |
|
|
|
passkeyExpirationMinutes: setting.passkeyExpirationMinutes, |
|
|
|
profileImageUrl: setting.profileImageUrl || "", |
|
|
|
searchBoxes: parseJsonField(setting.searchBoxes, []), |
|
|
|
showContactGivesInline: setting.showContactGivesInline || false, |
|
|
|
showGeneralAdvanced: setting.showGeneralAdvanced || false, |
|
|
|
showShortcutBvc: setting.showShortcutBvc || false, |
|
|
|
vapid: setting.vapid || "", |
|
|
|
} as Settings; |
|
|
|
}); |
|
|
|
const presettings = |
|
|
|
mapColumnsToValues(result.columns, result.values) as Settings[]; |
|
|
|
// This is redundant since absurd-sql auto-parses JSON strings to objects.
|
|
|
|
// But we started it, and it should be known everywhere, so we're keeping it.
|
|
|
|
settings = presettings.map((setting) => { |
|
|
|
if (setting.searchBoxes) { |
|
|
|
setting.searchBoxes = parseJsonField(setting.searchBoxes, []) as Array<{ name: string, bbox: BoundingBox }>; |
|
|
|
} |
|
|
|
return setting; |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
logger.info( |
|
|
@ -336,7 +310,7 @@ export async function getSqliteSettings(): Promise<Settings[]> { |
|
|
|
* |
|
|
|
* @async |
|
|
|
* @function getSqliteAccounts |
|
|
|
* @returns {Promise<Account[]>} Array of all accounts from SQLite database |
|
|
|
* @returns {Promise<string[]>} Array of all accounts from SQLite database |
|
|
|
* @throws {Error} If database query fails or data conversion fails |
|
|
|
* @example |
|
|
|
* ```typescript
|
|
|
@ -348,32 +322,20 @@ export async function getSqliteSettings(): Promise<Settings[]> { |
|
|
|
* } |
|
|
|
* ``` |
|
|
|
*/ |
|
|
|
export async function getSqliteAccounts(): Promise<Account[]> { |
|
|
|
export async function getSqliteAccounts(): Promise<string[]> { |
|
|
|
try { |
|
|
|
const platformService = PlatformServiceFactory.getInstance(); |
|
|
|
const result = await platformService.dbQuery("SELECT * FROM accounts"); |
|
|
|
const result = await platformService.dbQuery("SELECT did FROM accounts"); |
|
|
|
|
|
|
|
let accounts: Account[] = []; |
|
|
|
let dids: string[] = []; |
|
|
|
if (result?.values?.length) { |
|
|
|
accounts = result.values.map((row) => { |
|
|
|
const account = parseJsonField(row, {}) as Account; |
|
|
|
return { |
|
|
|
id: account.id, |
|
|
|
dateCreated: account.dateCreated || "", |
|
|
|
derivationPath: account.derivationPath || "", |
|
|
|
did: account.did || "", |
|
|
|
identity: account.identity || "", |
|
|
|
mnemonic: account.mnemonic || "", |
|
|
|
passkeyCredIdHex: account.passkeyCredIdHex || "", |
|
|
|
publicKeyHex: account.publicKeyHex || "", |
|
|
|
} as Account; |
|
|
|
}); |
|
|
|
dids = result.values.map((row) => row[0] as string); |
|
|
|
} |
|
|
|
|
|
|
|
logger.info( |
|
|
|
`[MigrationService] Retrieved ${accounts.length} accounts from SQLite`, |
|
|
|
`[MigrationService] Retrieved ${dids.length} accounts from SQLite`, |
|
|
|
); |
|
|
|
return accounts; |
|
|
|
return dids; |
|
|
|
} catch (error) { |
|
|
|
logger.error("[MigrationService] Error retrieving SQLite accounts:", error); |
|
|
|
throw new Error(`Failed to retrieve SQLite accounts: ${error}`); |
|
|
@ -532,6 +494,7 @@ export async function compareDatabases(): Promise<DataComparison> { |
|
|
|
function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) { |
|
|
|
const added: Contact[] = []; |
|
|
|
const modified: Contact[] = []; |
|
|
|
const unmodified: Contact[] = []; |
|
|
|
const missing: Contact[] = []; |
|
|
|
|
|
|
|
// Find contacts that exist in Dexie but not in SQLite
|
|
|
@ -543,6 +506,8 @@ function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) { |
|
|
|
added.push(dexieContact); |
|
|
|
} else if (!contactsEqual(dexieContact, sqliteContact)) { |
|
|
|
modified.push(dexieContact); |
|
|
|
} else { |
|
|
|
unmodified.push(dexieContact); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -554,7 +519,7 @@ function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { added, modified, missing }; |
|
|
|
return { added, modified, unmodified, missing }; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -588,27 +553,30 @@ function compareSettings( |
|
|
|
) { |
|
|
|
const added: Settings[] = []; |
|
|
|
const modified: Settings[] = []; |
|
|
|
const unmodified: Settings[] = []; |
|
|
|
const missing: Settings[] = []; |
|
|
|
|
|
|
|
// Find settings that exist in Dexie but not in SQLite
|
|
|
|
for (const dexieSetting of dexieSettings) { |
|
|
|
const sqliteSetting = sqliteSettings.find((s) => s.id === dexieSetting.id); |
|
|
|
const sqliteSetting = sqliteSettings.find((s) => s.accountDid === dexieSetting.accountDid); |
|
|
|
if (!sqliteSetting) { |
|
|
|
added.push(dexieSetting); |
|
|
|
} else if (!settingsEqual(dexieSetting, sqliteSetting)) { |
|
|
|
modified.push(dexieSetting); |
|
|
|
} else { |
|
|
|
unmodified.push(dexieSetting); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Find settings that exist in SQLite but not in Dexie
|
|
|
|
for (const sqliteSetting of sqliteSettings) { |
|
|
|
const dexieSetting = dexieSettings.find((s) => s.id === sqliteSetting.id); |
|
|
|
const dexieSetting = dexieSettings.find((s) => s.accountDid === sqliteSetting.accountDid); |
|
|
|
if (!dexieSetting) { |
|
|
|
missing.push(sqliteSetting); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { added, modified, missing }; |
|
|
|
return { added, modified, unmodified, missing }; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -623,11 +591,11 @@ function compareSettings( |
|
|
|
* |
|
|
|
* @function compareAccounts |
|
|
|
* @param {Account[]} dexieAccounts - Accounts from Dexie database |
|
|
|
* @param {Account[]} sqliteAccounts - Accounts from SQLite database |
|
|
|
* @param {Account[]} sqliteDids - Accounts from SQLite database |
|
|
|
* @returns {Object} Object containing added, modified, and missing accounts |
|
|
|
* @returns {Account[]} returns.added - Accounts in Dexie but not SQLite |
|
|
|
* @returns {Account[]} returns.modified - Accounts that differ between databases |
|
|
|
* @returns {Account[]} returns.missing - Accounts in SQLite but not Dexie |
|
|
|
* @returns {Account[]} returns.modified - always 0 because we don't check |
|
|
|
* @returns {string[]} returns.missing - Accounts in SQLite but not Dexie |
|
|
|
* @example |
|
|
|
* ```typescript
|
|
|
|
* const differences = compareAccounts(dexieAccounts, sqliteAccounts); |
|
|
@ -636,30 +604,30 @@ function compareSettings( |
|
|
|
* console.log(`Missing: ${differences.missing.length}`); |
|
|
|
* ``` |
|
|
|
*/ |
|
|
|
function compareAccounts(dexieAccounts: Account[], sqliteAccounts: Account[]) { |
|
|
|
function compareAccounts(dexieAccounts: Account[], sqliteDids: string[]) { |
|
|
|
const added: Account[] = []; |
|
|
|
const modified: Account[] = []; |
|
|
|
const missing: Account[] = []; |
|
|
|
const unmodified: Account[] = []; |
|
|
|
const missing: string[] = []; |
|
|
|
|
|
|
|
// Find accounts that exist in Dexie but not in SQLite
|
|
|
|
for (const dexieAccount of dexieAccounts) { |
|
|
|
const sqliteAccount = sqliteAccounts.find((a) => a.id === dexieAccount.id); |
|
|
|
if (!sqliteAccount) { |
|
|
|
const sqliteDid = sqliteDids.find((a) => a === dexieAccount.did); |
|
|
|
if (!sqliteDid) { |
|
|
|
added.push(dexieAccount); |
|
|
|
} else if (!accountsEqual(dexieAccount, sqliteAccount)) { |
|
|
|
modified.push(dexieAccount); |
|
|
|
} else { |
|
|
|
unmodified.push(dexieAccount); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Find accounts that exist in SQLite but not in Dexie
|
|
|
|
for (const sqliteAccount of sqliteAccounts) { |
|
|
|
const dexieAccount = dexieAccounts.find((a) => a.id === sqliteAccount.id); |
|
|
|
for (const sqliteDid of sqliteDids) { |
|
|
|
const dexieAccount = dexieAccounts.find((a) => a.did === sqliteDid); |
|
|
|
if (!dexieAccount) { |
|
|
|
missing.push(sqliteAccount); |
|
|
|
missing.push(sqliteDid); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { added, modified, missing }; |
|
|
|
return { added, unmodified, missing }; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -688,15 +656,15 @@ function compareAccounts(dexieAccounts: Account[], sqliteAccounts: Account[]) { |
|
|
|
*/ |
|
|
|
function contactsEqual(contact1: Contact, contact2: Contact): boolean { |
|
|
|
return ( |
|
|
|
contact1.did === contact2.did && |
|
|
|
contact1.name === contact2.name && |
|
|
|
contact1.notes === contact2.notes && |
|
|
|
contact1.profileImageUrl === contact2.profileImageUrl && |
|
|
|
contact1.publicKeyBase64 === contact2.publicKeyBase64 && |
|
|
|
contact1.nextPubKeyHashB64 === contact2.nextPubKeyHashB64 && |
|
|
|
contact1.seesMe === contact2.seesMe && |
|
|
|
contact1.registered === contact2.registered && |
|
|
|
JSON.stringify(contact1.contactMethods) === |
|
|
|
contact1.did == contact2.did && |
|
|
|
contact1.name == contact2.name && |
|
|
|
contact1.notes == contact2.notes && |
|
|
|
contact1.profileImageUrl == contact2.profileImageUrl && |
|
|
|
contact1.publicKeyBase64 == contact2.publicKeyBase64 && |
|
|
|
contact1.nextPubKeyHashB64 == contact2.nextPubKeyHashB64 && |
|
|
|
contact1.seesMe == contact2.seesMe && |
|
|
|
contact1.registered == contact2.registered && |
|
|
|
JSON.stringify(contact1.contactMethods) == |
|
|
|
JSON.stringify(contact2.contactMethods) |
|
|
|
); |
|
|
|
} |
|
|
@ -727,38 +695,38 @@ function contactsEqual(contact1: Contact, contact2: Contact): boolean { |
|
|
|
*/ |
|
|
|
function settingsEqual(settings1: Settings, settings2: Settings): boolean { |
|
|
|
return ( |
|
|
|
settings1.id === settings2.id && |
|
|
|
settings1.accountDid === settings2.accountDid && |
|
|
|
settings1.activeDid === settings2.activeDid && |
|
|
|
settings1.apiServer === settings2.apiServer && |
|
|
|
settings1.filterFeedByNearby === settings2.filterFeedByNearby && |
|
|
|
settings1.filterFeedByVisible === settings2.filterFeedByVisible && |
|
|
|
settings1.finishedOnboarding === settings2.finishedOnboarding && |
|
|
|
settings1.firstName === settings2.firstName && |
|
|
|
settings1.hideRegisterPromptOnNewContact === |
|
|
|
settings1.id == settings2.id && |
|
|
|
settings1.accountDid == settings2.accountDid && |
|
|
|
settings1.activeDid == settings2.activeDid && |
|
|
|
settings1.apiServer == settings2.apiServer && |
|
|
|
settings1.filterFeedByNearby == settings2.filterFeedByNearby && |
|
|
|
settings1.filterFeedByVisible == settings2.filterFeedByVisible && |
|
|
|
settings1.finishedOnboarding == settings2.finishedOnboarding && |
|
|
|
settings1.firstName == settings2.firstName && |
|
|
|
settings1.hideRegisterPromptOnNewContact == |
|
|
|
settings2.hideRegisterPromptOnNewContact && |
|
|
|
settings1.isRegistered === settings2.isRegistered && |
|
|
|
settings1.lastName === settings2.lastName && |
|
|
|
settings1.lastAckedOfferToUserJwtId === |
|
|
|
settings1.isRegistered == settings2.isRegistered && |
|
|
|
settings1.lastName == settings2.lastName && |
|
|
|
settings1.lastAckedOfferToUserJwtId == |
|
|
|
settings2.lastAckedOfferToUserJwtId && |
|
|
|
settings1.lastAckedOfferToUserProjectsJwtId === |
|
|
|
settings1.lastAckedOfferToUserProjectsJwtId == |
|
|
|
settings2.lastAckedOfferToUserProjectsJwtId && |
|
|
|
settings1.lastNotifiedClaimId === settings2.lastNotifiedClaimId && |
|
|
|
settings1.lastViewedClaimId === settings2.lastViewedClaimId && |
|
|
|
settings1.notifyingNewActivityTime === settings2.notifyingNewActivityTime && |
|
|
|
settings1.notifyingReminderMessage === settings2.notifyingReminderMessage && |
|
|
|
settings1.notifyingReminderTime === settings2.notifyingReminderTime && |
|
|
|
settings1.partnerApiServer === settings2.partnerApiServer && |
|
|
|
settings1.passkeyExpirationMinutes === settings2.passkeyExpirationMinutes && |
|
|
|
settings1.profileImageUrl === settings2.profileImageUrl && |
|
|
|
settings1.showContactGivesInline === settings2.showContactGivesInline && |
|
|
|
settings1.showGeneralAdvanced === settings2.showGeneralAdvanced && |
|
|
|
settings1.showShortcutBvc === settings2.showShortcutBvc && |
|
|
|
settings1.vapid === settings2.vapid && |
|
|
|
settings1.warnIfProdServer === settings2.warnIfProdServer && |
|
|
|
settings1.warnIfTestServer === settings2.warnIfTestServer && |
|
|
|
settings1.webPushServer === settings2.webPushServer && |
|
|
|
JSON.stringify(settings1.searchBoxes) === |
|
|
|
settings1.lastNotifiedClaimId == settings2.lastNotifiedClaimId && |
|
|
|
settings1.lastViewedClaimId == settings2.lastViewedClaimId && |
|
|
|
settings1.notifyingNewActivityTime == settings2.notifyingNewActivityTime && |
|
|
|
settings1.notifyingReminderMessage == settings2.notifyingReminderMessage && |
|
|
|
settings1.notifyingReminderTime == settings2.notifyingReminderTime && |
|
|
|
settings1.partnerApiServer == settings2.partnerApiServer && |
|
|
|
settings1.passkeyExpirationMinutes == settings2.passkeyExpirationMinutes && |
|
|
|
settings1.profileImageUrl == settings2.profileImageUrl && |
|
|
|
settings1.showContactGivesInline == settings2.showContactGivesInline && |
|
|
|
settings1.showGeneralAdvanced == settings2.showGeneralAdvanced && |
|
|
|
settings1.showShortcutBvc == settings2.showShortcutBvc && |
|
|
|
settings1.vapid == settings2.vapid && |
|
|
|
settings1.warnIfProdServer == settings2.warnIfProdServer && |
|
|
|
settings1.warnIfTestServer == settings2.warnIfTestServer && |
|
|
|
settings1.webPushServer == settings2.webPushServer && |
|
|
|
JSON.stringify(settings1.searchBoxes) == |
|
|
|
JSON.stringify(settings2.searchBoxes) |
|
|
|
); |
|
|
|
} |
|
|
@ -830,23 +798,25 @@ export function generateComparisonYaml(comparison: DataComparison): string { |
|
|
|
dexieSettings: comparison.dexieSettings.length, |
|
|
|
sqliteSettings: comparison.sqliteSettings.filter(s => s.accountDid || s.activeDid).length, |
|
|
|
dexieAccounts: comparison.dexieAccounts.length, |
|
|
|
sqliteAccounts: comparison.sqliteAccounts.filter(a => a.did).length, |
|
|
|
sqliteAccounts: comparison.sqliteAccounts.filter(a => a).length, |
|
|
|
}, |
|
|
|
differences: { |
|
|
|
contacts: { |
|
|
|
added: comparison.differences.contacts.added.length, |
|
|
|
modified: comparison.differences.contacts.modified.length, |
|
|
|
unmodified: comparison.differences.contacts.unmodified.length, |
|
|
|
missing: comparison.differences.contacts.missing.filter(c => c.did).length, |
|
|
|
}, |
|
|
|
settings: { |
|
|
|
added: comparison.differences.settings.added.length, |
|
|
|
modified: comparison.differences.settings.modified.length, |
|
|
|
unmodified: comparison.differences.settings.unmodified.length, |
|
|
|
missing: comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length, |
|
|
|
}, |
|
|
|
accounts: { |
|
|
|
added: comparison.differences.accounts.added.length, |
|
|
|
modified: comparison.differences.accounts.modified.length, |
|
|
|
missing: comparison.differences.accounts.missing.filter(a => a.did).length, |
|
|
|
unmodified: comparison.differences.accounts.unmodified.length, |
|
|
|
missing: comparison.differences.accounts.missing.filter(a => a).length, |
|
|
|
}, |
|
|
|
}, |
|
|
|
details: { |
|
|
@ -888,15 +858,9 @@ export function generateComparisonYaml(comparison: DataComparison): string { |
|
|
|
hasIdentity: !!a.identity, |
|
|
|
hasMnemonic: !!a.mnemonic, |
|
|
|
})), |
|
|
|
sqlite: comparison.sqliteAccounts |
|
|
|
.filter(a => a.did) |
|
|
|
.map((a) => ({ |
|
|
|
id: a.id, |
|
|
|
did: a.did, |
|
|
|
dateCreated: a.dateCreated, |
|
|
|
hasIdentity: !!a.identity, |
|
|
|
hasMnemonic: !!a.mnemonic, |
|
|
|
})), |
|
|
|
sqlite: comparison.sqliteAccounts.map((a) => ({ |
|
|
|
did: a, |
|
|
|
})), |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|