@ -45,7 +45,6 @@ import type {
PlatformCapabilities ,
} from "@/services/PlatformService" ;
import {
MASTER_SETTINGS_KEY ,
type Settings ,
type SettingsWithJsonStrings ,
} from "@/db/tables/settings" ;
@ -58,8 +57,6 @@ import {
generateInsertStatement ,
generateUpdateStatement ,
} from "@/utils/sqlHelpers" ;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { ActiveIdentity } from "@/db/tables/activeIdentity" ;
// =================================================
// TYPESCRIPT INTERFACES
@ -198,6 +195,80 @@ export const PlatformServiceMixin = {
// SELF-CONTAINED UTILITY METHODS (no databaseUtil dependency)
// =================================================
/ * *
* Ensure active_identity table is populated with data from settings
* This is a one - time fix for the migration gap
* /
async $ensureActiveIdentityPopulated ( ) : Promise < void > {
try {
logger . info (
"[PlatformServiceMixin] $ensureActiveIdentityPopulated() called" ,
) ;
// Check if active_identity has data
const activeIdentity = await this . $dbQuery (
"SELECT activeDid FROM active_identity WHERE id = 1" ,
) ;
const currentActiveDid = activeIdentity ? . values ? . [ 0 ] ? . [ 0 ] as string ;
logger . info (
"[PlatformServiceMixin] Current active_identity table state:" ,
{ currentActiveDid , hasData : ! ! currentActiveDid } ,
) ;
if ( ! currentActiveDid ) {
logger . info (
"[PlatformServiceMixin] Active identity table empty, populating from settings" ,
) ;
// Get activeDid from settings (any row with accountDid)
const settings = await this . $dbQuery (
"SELECT accountDid FROM settings WHERE accountDid IS NOT NULL LIMIT 1" ,
) ;
const settingsAccountDid = settings ? . values ? . [ 0 ] ? . [ 0 ] as string ;
logger . info ( "[PlatformServiceMixin] Found settings accountDid:" , {
settingsAccountDid ,
} ) ;
if ( settingsAccountDid ) {
await this . $dbExec (
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1" ,
[ settingsAccountDid ] ,
) ;
logger . info (
` [PlatformServiceMixin] Populated active_identity with: ${ settingsAccountDid } ` ,
) ;
} else {
// If no settings found, try to get any account DID
const accounts = await this . $dbQuery (
"SELECT did FROM accounts LIMIT 1" ,
) ;
const accountDid = accounts ? . values ? . [ 0 ] ? . [ 0 ] as string ;
if ( accountDid ) {
await this . $dbExec (
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1" ,
[ accountDid ] ,
) ;
logger . info (
` [PlatformServiceMixin] Populated active_identity with account DID: ${ accountDid } ` ,
) ;
} else {
logger . warn (
"[PlatformServiceMixin] No accountDid found in settings or accounts table" ,
) ;
}
}
}
} catch ( error ) {
logger . warn (
"[PlatformServiceMixin] Failed to populate active_identity:" ,
error ,
) ;
}
} ,
/ * *
* Update the current activeDid and trigger change detection
* This method should be called when the user switches identities
@ -213,22 +284,18 @@ export const PlatformServiceMixin = {
` [PlatformServiceMixin] ActiveDid updated from ${ oldDid } to ${ newDid } ` ,
) ;
// Dual-write to both tables for backward compatibility
// Write only to active_identity table (single source of truth)
try {
await this . $dbExec (
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1" ,
[ newDid || "" ] ,
) ;
await this . $dbExec ( "UPDATE settings SET activeDid = ? WHERE id = ?" , [
newDid || "" ,
MASTER_SETTINGS_KEY ,
] ) ;
logger . debug (
` [PlatformServiceMixin] ActiveDid dual-write completed for ${ newDid } ` ,
` [PlatformServiceMixin] ActiveDid updated in active_identity table: ${ newDid } ` ,
) ;
} catch ( error ) {
logger . error (
` [PlatformServiceMixin] Error in dual-write for activeDid ${ newDid } : ` ,
` [PlatformServiceMixin] Error updating activeDid in active_identity table ${ newDid } : ` ,
error ,
) ;
// Continue with in-memory update even if database write fails
@ -468,10 +535,18 @@ export const PlatformServiceMixin = {
fallback : Settings | null = null ,
) : Promise < Settings | null > {
try {
// Master settings: query by id
// Get current active identity
const activeIdentity = await this . $getActiveIdentity ( ) ;
const activeDid = activeIdentity . activeDid ;
if ( ! activeDid ) {
return fallback ;
}
// Get identity-specific settings
const result = await this . $dbQuery (
"SELECT * FROM settings WHERE id = ?" ,
[ MASTER_SETTINGS_KEY ] ,
"SELECT * FROM settings WHERE accountD id = ?" ,
[ activeDid ] ,
) ;
if ( ! result ? . values ? . length ) {
@ -508,7 +583,6 @@ export const PlatformServiceMixin = {
* Handles the common pattern of layered settings
* /
async $getMergedSettings (
defaultKey : string ,
accountDid? : string ,
defaultFallback : Settings = { } ,
) : Promise < Settings > {
@ -564,7 +638,6 @@ export const PlatformServiceMixin = {
return mergedSettings ;
} catch ( error ) {
logger . error ( ` [Settings Trace] ❌ Failed to get merged settings: ` , {
defaultKey ,
accountDid ,
error ,
} ) ;
@ -578,12 +651,29 @@ export const PlatformServiceMixin = {
* /
async $getActiveIdentity ( ) : Promise < { activeDid : string } > {
try {
logger . info (
"[PlatformServiceMixin] $getActiveIdentity() called - API layer verification" ,
) ;
// Ensure the table is populated before reading
await this . $ensureActiveIdentityPopulated ( ) ;
logger . debug (
"[PlatformServiceMixin] Getting active identity from active_identity table" ,
) ;
const result = await this . $dbQuery (
"SELECT activeDid FROM active_identity WHERE id = 1" ,
) ;
if ( result ? . values ? . length ) {
const activeDid = result . values [ 0 ] [ 0 ] as string ;
logger . debug ( "[PlatformServiceMixin] Active identity found:" , {
activeDid ,
} ) ;
logger . info (
"[PlatformServiceMixin] $getActiveIdentity(): activeDid resolved" ,
{ activeDid } ,
) ;
// Validate activeDid exists in accounts
if ( activeDid ) {
@ -593,9 +683,15 @@ export const PlatformServiceMixin = {
) ;
if ( accountExists ? . values ? . length ) {
logger . debug (
"[PlatformServiceMixin] Active identity validated in accounts" ,
) ;
return { activeDid } ;
} else {
// Clear corrupted activeDid
logger . warn (
"[PlatformServiceMixin] Active identity not found in accounts, clearing" ,
) ;
await this . $dbExec (
"UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" ,
) ;
@ -604,6 +700,9 @@ export const PlatformServiceMixin = {
}
}
logger . debug (
"[PlatformServiceMixin] No active identity found, returning empty" ,
) ;
return { activeDid : "" } ;
} catch ( error ) {
logger . error (
@ -825,14 +924,14 @@ export const PlatformServiceMixin = {
return defaults ;
}
// FIXED: Remove forced override - respect user preferences
// FIXED: Set default apiServer for all platforms, not just Electron
// Only set default if no user preference exists
if ( ! settings . apiServer && process . env . VITE_PLATFORM === "electron" ) {
if ( ! settings . apiServer ) {
// Import constants dynamically to get platform-specific values
const { DEFAULT_ENDORSER_API_SERVER } = await import (
"../constants/app"
) ;
// Only set if user hasn't specified a preference
// Set default for all platforms when apiServer is empty
settings . apiServer = DEFAULT_ENDORSER_API_SERVER ;
}
@ -858,10 +957,9 @@ export const PlatformServiceMixin = {
return defaults ;
}
// Determine which DID to use - prioritize new active_identity table, fallback to settings
// Get DID from active_identity table (single source of truth)
const activeIdentity = await this . $getActiveIdentity ( ) ;
const targetDid =
did || activeIdentity . activeDid || defaultSettings . activeDid ;
const targetDid = did || activeIdentity . activeDid ;
// If no target DID, return default settings
if ( ! targetDid ) {
@ -870,27 +968,29 @@ export const PlatformServiceMixin = {
// Get merged settings using existing method
const mergedSettings = await this . $getMergedSettings (
MASTER_SETTINGS_KEY ,
targetDid ,
defaultSettings ,
) ;
// Ensure activeDid comes from new table when available
if ( activeIdentity . activeDid ) {
// Set activeDid from active_identity table (single source of truth)
mergedSettings . activeDid = activeIdentity . activeDid ;
}
logger . debug (
"[PlatformServiceMixin] Using activeDid from active_identity table:" ,
{ activeDid : activeIdentity.activeDid } ,
) ;
logger . info (
"[PlatformServiceMixin] $accountSettings() returning activeDid:" ,
{ activeDid : mergedSettings.activeDid } ,
) ;
// FIXED: Remove forced override - respect user preferences
// FIXED: Set default apiServer for all platforms, not just Electron
// Only set default if no user preference exists
if (
! mergedSettings . apiServer &&
process . env . VITE_PLATFORM === "electron"
) {
if ( ! mergedSettings . apiServer ) {
// Import constants dynamically to get platform-specific values
const { DEFAULT_ENDORSER_API_SERVER } = await import (
"../constants/app"
) ;
// Only set if user hasn't specified a preference
// Set default for all platforms when apiServer is empty
mergedSettings . apiServer = DEFAULT_ENDORSER_API_SERVER ;
}
@ -928,16 +1028,36 @@ export const PlatformServiceMixin = {
async $saveSettings ( changes : Partial < Settings > ) : Promise < boolean > {
try {
// Remove fields that shouldn't be updated
const { accountDid , id , . . . safeChanges } = changes ;
const {
accountDid ,
id ,
activeDid : activeDidField ,
. . . safeChanges
} = changes ;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void accountDid ;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void id ;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void activeDidField ;
logger . debug (
"[PlatformServiceMixin] $saveSettings - Original changes:" ,
changes ,
) ;
logger . debug (
"[PlatformServiceMixin] $saveSettings - Safe changes:" ,
safeChanges ,
) ;
if ( Object . keys ( safeChanges ) . length === 0 ) return true ;
// Convert settings for database storage (handles searchBoxes conversion)
const convertedChanges = this . _convertSettingsForStorage ( safeChanges ) ;
logger . debug (
"[PlatformServiceMixin] $saveSettings - Converted changes:" ,
convertedChanges ,
) ;
const setParts : string [ ] = [ ] ;
const params : unknown [ ] = [ ] ;
@ -949,17 +1069,33 @@ export const PlatformServiceMixin = {
}
} ) ;
logger . debug (
"[PlatformServiceMixin] $saveSettings - Set parts:" ,
setParts ,
) ;
logger . debug ( "[PlatformServiceMixin] $saveSettings - Params:" , params ) ;
if ( setParts . length === 0 ) return true ;
params . push ( MASTER_SETTINGS_KEY ) ;
// Get current active DID and update that identity's settings
const activeIdentity = await this . $getActiveIdentity ( ) ;
const currentActiveDid = activeIdentity . activeDid ;
if ( currentActiveDid ) {
params . push ( currentActiveDid ) ;
await this . $dbExec (
` UPDATE settings SET ${ setParts . join ( ", " ) } WHERE id = ? ` ,
` UPDATE settings SET ${ setParts . join ( ", " ) } WHERE accountD id = ? ` ,
params ,
) ;
} else {
logger . warn (
"[PlatformServiceMixin] No active DID found, cannot save settings" ,
) ;
}
// Update activeDid tracking if it changed
if ( changes . activeDid !== undefined ) {
await this . $updateActiveDid ( changes . activeDid ) ;
if ( activeDidFiel d !== undefined ) {
await this . $updateActiveDid ( activeDidFiel d ) ;
}
return true ;
@ -1409,13 +1545,16 @@ export const PlatformServiceMixin = {
fields : string [ ] ,
did? : string ,
) : Promise < unknown [ ] | undefined > {
// Use correct settings table schema
const whereClause = did ? "WHERE accountDid = ?" : "WHERE id = ?" ;
const params = did ? [ did ] : [ MASTER_SETTINGS_KEY ] ;
// Use current active DID if no specific DID provided
const targetDid = did || ( await this . $getActiveIdentity ( ) ) . activeDid ;
if ( ! targetDid ) {
return undefined ;
}
return await this . $one (
` SELECT ${ fields . join ( ", " ) } FROM settings ${ whereClause } ` ,
params ,
` SELECT ${ fields . join ( ", " ) } FROM settings WHERE accountDid = ? ` ,
[ targetDid ] ,
) ;
} ,
@ -1655,7 +1794,6 @@ export const PlatformServiceMixin = {
// Get merged settings
const mergedSettings = await this . $getMergedSettings (
MASTER_SETTINGS_KEY ,
did ,
defaultSettings || { } ,
) ;
@ -1697,6 +1835,7 @@ export interface IPlatformServiceMixin {
accountDid? : string ,
defaultFallback? : Settings ,
) : Promise < Settings > ;
$getActiveIdentity ( ) : Promise < { activeDid : string } > ;
$withTransaction < T > ( callback : ( ) = > Promise < T > ) : Promise < T > ;
isCapacitor : boolean ;
isWeb : boolean ;