@ -15,58 +15,100 @@ if (pwa_enabled) {
// Initialize app and SQLite
const app = initializeApp ( ) ;
/ * *
* SQLite initialization configuration
* Defines timeouts and retry settings for database operations
*
* @author Matthew Raymer
* /
const SQLITE_CONFIG = {
INITIALIZATION : {
TIMEOUT_MS : 10000 , // 10 seconds for initial setup
RETRY_ATTEMPTS : 3 ,
RETRY_DELAY_MS : 1000
} ,
OPERATIONS : {
TIMEOUT_MS : 5000 , // 5 seconds for regular operations
RETRY_ATTEMPTS : 2 ,
RETRY_DELAY_MS : 500
} ,
CONNECTION : {
MAX_CONNECTIONS : 5 ,
IDLE_TIMEOUT_MS : 30000
}
} ;
// Create a promise that resolves when SQLite is ready
const sqliteReady = new Promise < void > ( ( resolve , reject ) = > {
// Set a timeout to prevent hanging
const timeout = setTimeout ( ( ) = > {
logger . error ( "[Main Electron] SQLite initialization timeout" ) ;
reject ( new Error ( "SQLite initialization timeout" ) ) ;
} , 30000 ) ; // 30 second timeout
// Wait for electron bridge to be available
const checkElectronBridge = ( ) = > {
if ( window . electron ? . ipcRenderer ) {
logger . info ( "[Main Electron] IPC renderer bridge available" ) ;
// Listen for SQLite ready signal
window . electron . ipcRenderer . once ( 'sqlite-ready' , ( ) = > {
clearTimeout ( timeout ) ;
logger . info ( "[Main Electron] Received SQLite ready signal" ) ;
resolve ( ) ;
} ) ;
let retryCount = 0 ;
let initializationTimeout : NodeJS.Timeout ;
const attemptInitialization = ( ) = > {
// Clear any existing timeout
if ( initializationTimeout ) {
clearTimeout ( initializationTimeout ) ;
}
// Set timeout for this attempt
initializationTimeout = setTimeout ( ( ) = > {
if ( retryCount < SQLITE_CONFIG . INITIALIZATION . RETRY_ATTEMPTS ) {
retryCount ++ ;
logger . warn ( ` [Main Electron] SQLite initialization attempt ${ retryCount } timed out, retrying... ` ) ;
setTimeout ( attemptInitialization , SQLITE_CONFIG . INITIALIZATION . RETRY_DELAY_MS ) ;
} else {
logger . error ( "[Main Electron] SQLite initialization failed after all retries" ) ;
reject ( new Error ( "SQLite initialization timeout after all retries" ) ) ;
}
} , SQLITE_CONFIG . INITIALIZATION . TIMEOUT_MS ) ;
// Also listen for database errors
window . electron . ipcRenderer . once ( 'database-status' , ( . . . args : unknown [ ] ) = > {
clearTimeout ( timeout ) ;
const status = args [ 0 ] as { status : string ; error? : string } ;
if ( status . status === 'error' ) {
logger . error ( "[Main Electron] Database error:" , status . error ) ;
reject ( new Error ( status . error || 'Database initialization failed' ) ) ;
}
} ) ;
// Wait for electron bridge to be available
const checkElectronBridge = ( ) = > {
if ( window . electron ? . ipcRenderer ) {
logger . info ( "[Main Electron] IPC renderer bridge available" ) ;
// Listen for SQLite ready signal
window . electron . ipcRenderer . once ( 'sqlite-ready' , ( ) = > {
clearTimeout ( initializationTimeout ) ;
logger . info ( "[Main Electron] Received SQLite ready signal" ) ;
resolve ( ) ;
} ) ;
// Check if SQLite is already available
window . electron . ipcRenderer . invoke ( 'sqlite-is-available' )
. then ( ( result : unknown ) = > {
const isAvailable = Boolean ( result ) ;
if ( isAvailable ) {
logger . info ( "[Main Electron] SQLite is already available" ) ;
// Don't resolve here - wait for the ready signal
// This prevents race conditions where the ready signal arrives after this check
// Also listen for database errors
window . electron . ipcRenderer . once ( 'database-status' , ( . . . args : unknown [ ] ) = > {
clearTimeout ( initializationTimeout ) ;
const status = args [ 0 ] as { status : string ; error? : string } ;
if ( status . status === 'error' ) {
logger . error ( "[Main Electron] Database error:" , status . error ) ;
reject ( new Error ( status . error || 'Database initialization failed' ) ) ;
}
} )
. catch ( ( error : Error ) = > {
logger . error ( "[Main Electron] Failed to check SQLite availability:" , error ) ;
// Don't reject here - wait for either ready signal or timeout
} ) ;
} else {
// Check again in 100ms if bridge isn't ready
setTimeout ( checkElectronBridge , 100 ) ;
}
// Check if SQLite is already available
window . electron . ipcRenderer . invoke ( 'sqlite-is-available' )
. then ( ( result : unknown ) = > {
const isAvailable = Boolean ( result ) ;
if ( isAvailable ) {
logger . info ( "[Main Electron] SQLite is already available" ) ;
// Don't resolve here - wait for the ready signal
// This prevents race conditions where the ready signal arrives after this check
}
} )
. catch ( ( error : Error ) = > {
logger . error ( "[Main Electron] Failed to check SQLite availability:" , error ) ;
// Don't reject here - wait for either ready signal or timeout
} ) ;
} else {
// Check again in 100ms if bridge isn't ready
setTimeout ( checkElectronBridge , 100 ) ;
}
} ;
// Start checking for bridge
checkElectronBridge ( ) ;
} ;
// Start checking for bridge
checkElectronBridge ( ) ;
// Start first initialization attempt
attemptInitialization ( ) ;
} ) ;
// Wait for SQLite to be ready before mounting