diff --git a/src/electron/main.ts b/src/electron/main.ts index dd2c5823..797f5f0f 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -75,27 +75,30 @@ try { const getAppDataPath = async (): Promise => { try { // Read config file directly - const configPath = path.join(__dirname, '..', 'capacitor.config.json'); - const configContent = await fs.promises.readFile(configPath, 'utf-8'); + const configPath = path.join(__dirname, "..", "capacitor.config.json"); + const configContent = await fs.promises.readFile(configPath, "utf-8"); const config = JSON.parse(configContent); const linuxPath = config?.plugins?.CapacitorSQLite?.electronLinuxLocation; - + if (linuxPath) { // Expand ~ to home directory - const expandedPath = linuxPath.replace(/^~/, process.env.HOME || ''); + const expandedPath = linuxPath.replace(/^~/, process.env.HOME || ""); logger.info("[Electron] Using configured database path:", expandedPath); return expandedPath; } - + // Fallback to app.getPath if config path is not available - const userDataPath = app.getPath('userData'); + const userDataPath = app.getPath("userData"); logger.info("[Electron] Using fallback user data path:", userDataPath); return userDataPath; } catch (error) { logger.error("[Electron] Error getting app data path:", error); // Fallback to app.getPath if anything fails - const userDataPath = app.getPath('userData'); - logger.info("[Electron] Using fallback user data path after error:", userDataPath); + const userDataPath = app.getPath("userData"); + logger.info( + "[Electron] Using fallback user data path after error:", + userDataPath, + ); return userDataPath; } }; @@ -103,30 +106,32 @@ const getAppDataPath = async (): Promise => { const validateAndNormalizePath = async (filePath: string): Promise => { // Resolve any relative paths const resolvedPath = path.resolve(filePath); - + // Ensure it's an absolute path if (!path.isAbsolute(resolvedPath)) { throw new Error(`Database path must be absolute: ${resolvedPath}`); } - + // Ensure it's within the app data directory const appDataPath = await getAppDataPath(); if (!resolvedPath.startsWith(appDataPath)) { - throw new Error(`Database path must be within app data directory: ${resolvedPath}`); + throw new Error( + `Database path must be within app data directory: ${resolvedPath}`, + ); } - + // Normalize the path const normalizedPath = path.normalize(resolvedPath); - + logger.info("[Electron] Validated database path:", { original: filePath, resolved: resolvedPath, normalized: normalizedPath, appDataPath, isAbsolute: path.isAbsolute(normalizedPath), - isWithinAppData: normalizedPath.startsWith(appDataPath) + isWithinAppData: normalizedPath.startsWith(appDataPath), }); - + return normalizedPath; }; @@ -134,34 +139,46 @@ const ensureDirectoryExists = async (dirPath: string): Promise => { try { // Normalize the path first const normalizedPath = path.normalize(dirPath); - + // Check if directory exists if (!fs.existsSync(normalizedPath)) { logger.info("[Electron] Creating database directory:", normalizedPath); await fs.promises.mkdir(normalizedPath, { recursive: true }); } - + // Verify directory permissions try { - await fs.promises.access(normalizedPath, fs.constants.R_OK | fs.constants.W_OK); - logger.info("[Electron] Database directory permissions verified:", normalizedPath); + await fs.promises.access( + normalizedPath, + fs.constants.R_OK | fs.constants.W_OK, + ); + logger.info( + "[Electron] Database directory permissions verified:", + normalizedPath, + ); } catch (error) { logger.error("[Electron] Database directory permission error:", error); throw new Error(`Database directory not accessible: ${normalizedPath}`); } - + // Test write permissions - const testFile = path.join(normalizedPath, '.write-test'); + const testFile = path.join(normalizedPath, ".write-test"); try { - await fs.promises.writeFile(testFile, 'test'); + await fs.promises.writeFile(testFile, "test"); await fs.promises.unlink(testFile); - logger.info("[Electron] Database directory write test passed:", normalizedPath); + logger.info( + "[Electron] Database directory write test passed:", + normalizedPath, + ); } catch (error) { logger.error("[Electron] Database directory write test failed:", error); throw new Error(`Database directory not writable: ${normalizedPath}`); } } catch (error) { - logger.error("[Electron] Failed to ensure database directory exists:", error); + logger.error( + "[Electron] Failed to ensure database directory exists:", + error, + ); throw error; } }; @@ -177,35 +194,43 @@ const initializeDatabasePaths = async (): Promise => { if (dbPathInitializationPromise) { return dbPathInitializationPromise; } - + if (dbPathInitialized) { return; } - + dbPathInitializationPromise = (async () => { try { // Get the base directory from config dbDir = await getAppDataPath(); logger.info("[Electron] Database directory:", dbDir); - + // Ensure the directory exists and is writable await ensureDirectoryExists(dbDir); - + // Construct the database path - dbPath = await validateAndNormalizePath(path.join(dbDir, 'timesafari.db')); + dbPath = await validateAndNormalizePath( + path.join(dbDir, "timesafari.db"), + ); logger.info("[Electron] Database path initialized:", dbPath); - + // Verify the database file if it exists if (fs.existsSync(dbPath)) { try { - await fs.promises.access(dbPath, fs.constants.R_OK | fs.constants.W_OK); - logger.info("[Electron] Existing database file permissions verified:", dbPath); + await fs.promises.access( + dbPath, + fs.constants.R_OK | fs.constants.W_OK, + ); + logger.info( + "[Electron] Existing database file permissions verified:", + dbPath, + ); } catch (error) { logger.error("[Electron] Database file permission error:", error); throw new Error(`Database file not accessible: ${dbPath}`); } } - + dbPathInitialized = true; } catch (error) { logger.error("[Electron] Failed to initialize database paths:", error); @@ -214,7 +239,7 @@ const initializeDatabasePaths = async (): Promise => { dbPathInitializationPromise = null; } })(); - + return dbPathInitializationPromise; }; @@ -228,27 +253,27 @@ async function initializeSQLite() { if (sqliteInitializationPromise) { return sqliteInitializationPromise; } - + if (sqliteInitialized) { return; } - + sqliteInitializationPromise = (async () => { try { logger.info("[Electron] Initializing SQLite plugin..."); sqlitePlugin = new CapacitorSQLite(); - + // Initialize database paths first await initializeDatabasePaths(); - + if (!dbPath) { throw new Error("Database path not initialized"); } - + // Test the plugin const echoResult = await sqlitePlugin.echo({ value: "test" }); logger.info("[Electron] SQLite plugin echo test:", echoResult); - + // Initialize database connection using validated dbPath const connectionOptions = { database: dbPath, @@ -256,34 +281,42 @@ async function initializeSQLite() { readOnly: false, encryption: "no-encryption", useNative: true, - mode: "rwc" // Force read-write-create mode + mode: "rwc", // Force read-write-create mode }; - - logger.info("[Electron] Creating initial connection with options:", connectionOptions); - + + logger.info( + "[Electron] Creating initial connection with options:", + connectionOptions, + ); + // Log the actual path being used logger.info("[Electron] Using database path:", dbPath); logger.info("[Electron] Path exists:", fs.existsSync(dbPath)); logger.info("[Electron] Path is absolute:", path.isAbsolute(dbPath)); - + const db = await sqlitePlugin.createConnection(connectionOptions); - - if (!db || typeof db !== 'object') { - throw new Error(`Failed to create database connection - invalid response. Path used: ${dbPath}`); + + if (!db || typeof db !== "object") { + throw new Error( + `Failed to create database connection - invalid response. Path used: ${dbPath}`, + ); } - + // Wait a moment for the connection to be fully established - await new Promise(resolve => setTimeout(resolve, 100)); - + await new Promise((resolve) => setTimeout(resolve, 100)); + // Verify the connection is working try { const result = await db.query("PRAGMA journal_mode;"); logger.info("[Electron] Database connection verified:", result); } catch (error) { - logger.error("[Electron] Database connection verification failed:", error); + logger.error( + "[Electron] Database connection verification failed:", + error, + ); throw error; } - + sqliteInitialized = true; logger.info("[Electron] SQLite plugin initialized successfully"); } catch (error) { @@ -293,42 +326,45 @@ async function initializeSQLite() { sqliteInitializationPromise = null; } })(); - + return sqliteInitializationPromise; } // Initialize app when ready app.whenReady().then(async () => { logger.info("App is ready, starting initialization..."); - + // Create window first const mainWindow = createWindow(); - + // Initialize database in background initializeSQLite().catch((error) => { - logger.error("[Electron] Database initialization failed, but continuing:", error); + logger.error( + "[Electron] Database initialization failed, but continuing:", + error, + ); // Notify renderer about database status if (!mainWindow.isDestroyed()) { - mainWindow.webContents.send('database-status', { - status: 'error', - error: error.message + mainWindow.webContents.send("database-status", { + status: "error", + error: error.message, }); } }); // Handle window close - mainWindow.on('closed', () => { + mainWindow.on("closed", () => { logger.info("[Electron] Main window closed"); }); // Handle window close request - mainWindow.on('close', (event) => { + mainWindow.on("close", (event) => { logger.info("[Electron] Window close requested"); // Prevent immediate close if we're in the middle of something if (mainWindow.webContents.isLoading()) { event.preventDefault(); logger.info("[Electron] Deferring window close due to loading state"); - mainWindow.webContents.once('did-finish-load', () => { + mainWindow.webContents.once("did-finish-load", () => { mainWindow.close(); }); } @@ -378,25 +414,32 @@ function createWindow(): BrowserWindow { sandbox: false, preload: preloadPath, webSecurity: true, - allowRunningInsecureContent: false + allowRunningInsecureContent: false, }, }); // Show window when ready - mainWindow.once('ready-to-show', () => { + mainWindow.once("ready-to-show", () => { logger.info("[Electron] Window ready to show"); mainWindow.show(); }); // Handle window errors - mainWindow.webContents.on('render-process-gone', (_event, details) => { + mainWindow.webContents.on("render-process-gone", (_event, details) => { logger.error("[Electron] Render process gone:", details); }); - mainWindow.webContents.on('did-fail-load', (_event, errorCode, errorDescription) => { - logger.error("[Electron] Page failed to load:", errorCode, errorDescription); - logger.error("[Electron] Failed URL:", mainWindow.webContents.getURL()); - }); + mainWindow.webContents.on( + "did-fail-load", + (_event, errorCode, errorDescription) => { + logger.error( + "[Electron] Page failed to load:", + errorCode, + errorDescription, + ); + logger.error("[Electron] Failed URL:", mainWindow.webContents.getURL()); + }, + ); // Load the index.html let indexPath: string; @@ -405,11 +448,15 @@ function createWindow(): BrowserWindow { if (app.isPackaged) { indexPath = path.join(process.resourcesPath, "www", "index.html"); fileUrl = `file://${indexPath}`; - logger.info("[Electron] App is packaged. Using process.resourcesPath for index.html"); + logger.info( + "[Electron] App is packaged. Using process.resourcesPath for index.html", + ); } else { indexPath = path.resolve(__dirname, "www", "index.html"); fileUrl = `file://${indexPath}`; - logger.info("[Electron] App is not packaged. Using __dirname for index.html"); + logger.info( + "[Electron] App is not packaged. Using __dirname for index.html", + ); } logger.info("[Electron] Resolved index.html path:", indexPath); @@ -417,14 +464,16 @@ function createWindow(): BrowserWindow { // Load the index.html with retry logic const loadIndexHtml = async (retryCount = 0): Promise => { - try { + try { if (mainWindow.isDestroyed()) { - logger.error("[Electron] Window was destroyed before loading index.html"); + logger.error( + "[Electron] Window was destroyed before loading index.html", + ); return; } - const exists = fs.existsSync(indexPath); - logger.info(`[Electron] fs.existsSync for index.html: ${exists}`); + const exists = fs.existsSync(indexPath); + logger.info(`[Electron] fs.existsSync for index.html: ${exists}`); if (!exists) { throw new Error(`index.html not found at path: ${indexPath}`); @@ -436,7 +485,7 @@ function createWindow(): BrowserWindow { size: stats.size, mode: stats.mode, uid: stats.uid, - gid: stats.gid + gid: stats.gid, }); // Try loadURL first @@ -445,22 +494,28 @@ function createWindow(): BrowserWindow { await mainWindow.loadURL(fileUrl); logger.info("[Electron] Successfully loaded index.html via loadURL"); } catch (loadUrlError) { - logger.warn("[Electron] loadURL failed, trying loadFile:", loadUrlError); + logger.warn( + "[Electron] loadURL failed, trying loadFile:", + loadUrlError, + ); // Fallback to loadFile await mainWindow.loadFile(indexPath); logger.info("[Electron] Successfully loaded index.html via loadFile"); } } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + const errorMessage = + error instanceof Error ? error.message : "Unknown error occurred"; logger.error("[Electron] Error loading index.html:", errorMessage); - + // Retry logic if (retryCount < 3 && !mainWindow.isDestroyed()) { - logger.info(`[Electron] Retrying index.html load (attempt ${retryCount + 1})`); - await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second + logger.info( + `[Electron] Retrying index.html load (attempt ${retryCount + 1})`, + ); + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second return loadIndexHtml(retryCount + 1); } - + // If we've exhausted retries, show error in window if (!mainWindow.isDestroyed()) { const errorHtml = ` @@ -472,7 +527,9 @@ function createWindow(): BrowserWindow { `; - await mainWindow.loadURL(`data:text/html,${encodeURIComponent(errorHtml)}`); + await mainWindow.loadURL( + `data:text/html,${encodeURIComponent(errorHtml)}`, + ); } } }; @@ -520,7 +577,12 @@ ipcMain.handle("sqlite-echo", async (_event, value) => { try { return await sqlitePlugin.echo({ value }); } catch (error) { - logger.error("Error in sqlite-echo:", error, JSON.stringify(error), (error as any)?.stack); + logger.error( + "Error in sqlite-echo:", + error, + JSON.stringify(error), + (error as any)?.stack, + ); throw error; } }); @@ -529,11 +591,11 @@ ipcMain.handle("sqlite-create-connection", async (_event, options) => { try { // Ensure database is initialized await initializeSQLite(); - + if (!dbPath) { throw new Error("Database path not initialized"); } - + // Override any provided database path with our resolved path const connectionOptions = { ...options, @@ -541,31 +603,40 @@ ipcMain.handle("sqlite-create-connection", async (_event, options) => { readOnly: false, mode: "rwc", // Force read-write-create mode encryption: "no-encryption", - useNative: true + useNative: true, }; - - logger.info("[Electron] Creating database connection with options:", connectionOptions); + + logger.info( + "[Electron] Creating database connection with options:", + connectionOptions, + ); const result = await sqlitePlugin.createConnection(connectionOptions); - - if (!result || typeof result !== 'object') { - throw new Error("Failed to create database connection - invalid response"); + + if (!result || typeof result !== "object") { + throw new Error( + "Failed to create database connection - invalid response", + ); } - + // Wait a moment for the connection to be fully established - await new Promise(resolve => setTimeout(resolve, 100)); - + await new Promise((resolve) => setTimeout(resolve, 100)); + try { // Verify connection is not read-only - const testResult = await result.query({ statement: "PRAGMA journal_mode;" }); + const testResult = await result.query({ + statement: "PRAGMA journal_mode;", + }); if (testResult?.values?.[0]?.journal_mode === "off") { - logger.error("[Electron] Connection opened in read-only mode despite options"); + logger.error( + "[Electron] Connection opened in read-only mode despite options", + ); throw new Error("Database connection opened in read-only mode"); } } catch (queryError) { logger.error("[Electron] Error verifying connection:", queryError); throw queryError; } - + logger.info("[Electron] Database connection created successfully"); return result; } catch (error) { @@ -578,7 +649,12 @@ ipcMain.handle("sqlite-execute", async (_event, options) => { try { return await sqlitePlugin.execute(options); } catch (error) { - logger.error("Error in sqlite-execute:", error, JSON.stringify(error), (error as any)?.stack); + logger.error( + "Error in sqlite-execute:", + error, + JSON.stringify(error), + (error as any)?.stack, + ); throw error; } }); @@ -587,7 +663,12 @@ ipcMain.handle("sqlite-query", async (_event, options) => { try { return await sqlitePlugin.query(options); } catch (error) { - logger.error("Error in sqlite-query:", error, JSON.stringify(error), (error as any)?.stack); + logger.error( + "Error in sqlite-query:", + error, + JSON.stringify(error), + (error as any)?.stack, + ); throw error; } }); @@ -596,7 +677,12 @@ ipcMain.handle("sqlite-close-connection", async (_event, options) => { try { return await sqlitePlugin.closeConnection(options); } catch (error) { - logger.error("Error in sqlite-close-connection:", error, JSON.stringify(error), (error as any)?.stack); + logger.error( + "Error in sqlite-close-connection:", + error, + JSON.stringify(error), + (error as any)?.stack, + ); throw error; } }); diff --git a/src/electron/preload.js b/src/electron/preload.js index 1efda7e3..c7ffdffc 100644 --- a/src/electron/preload.js +++ b/src/electron/preload.js @@ -98,44 +98,55 @@ try { } catch (error) { lastError = error; if (attempt < MAX_RETRIES) { - logger.warn(`SQLite operation failed (attempt ${attempt}/${MAX_RETRIES}), retrying...`, error); - await new Promise(resolve => setTimeout(resolve, RETRY_DELAY)); + logger.warn( + `SQLite operation failed (attempt ${attempt}/${MAX_RETRIES}), retrying...`, + error, + ); + await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY)); } } } - throw new Error(`SQLite operation failed after ${MAX_RETRIES} attempts: ${lastError?.message || 'Unknown error'}`); + throw new Error( + `SQLite operation failed after ${MAX_RETRIES} attempts: ${lastError?.message || "Unknown error"}`, + ); }; const wrapOperation = (method) => { return async (...args) => { try { - return await withRetry(ipcRenderer.invoke, 'sqlite-' + method, ...args); + return await withRetry( + ipcRenderer.invoke, + "sqlite-" + method, + ...args, + ); } catch (error) { logger.error(`SQLite ${method} failed:`, error); - throw new Error(`Database operation failed: ${error.message || 'Unknown error'}`); + throw new Error( + `Database operation failed: ${error.message || "Unknown error"}`, + ); } }; }; // Create a proxy that matches the CapacitorSQLite interface return { - echo: wrapOperation('echo'), - createConnection: wrapOperation('create-connection'), - closeConnection: wrapOperation('close-connection'), - execute: wrapOperation('execute'), - query: wrapOperation('query'), - run: wrapOperation('run'), - isAvailable: wrapOperation('is-available'), - getPlatform: () => Promise.resolve('electron'), + echo: wrapOperation("echo"), + createConnection: wrapOperation("create-connection"), + closeConnection: wrapOperation("close-connection"), + execute: wrapOperation("execute"), + query: wrapOperation("query"), + run: wrapOperation("run"), + isAvailable: wrapOperation("is-available"), + getPlatform: () => Promise.resolve("electron"), // Add other methods as needed }; }; // Expose only the CapacitorSQLite proxy - contextBridge.exposeInMainWorld('CapacitorSQLite', createSQLiteProxy()); + contextBridge.exposeInMainWorld("CapacitorSQLite", createSQLiteProxy()); // Remove the duplicate electron.sqlite bridge - contextBridge.exposeInMainWorld('electron', { + contextBridge.exposeInMainWorld("electron", { // Keep other electron APIs but remove sqlite getPath, send: (channel, data) => { diff --git a/src/main.electron.ts b/src/main.electron.ts index c9e35d9e..e7f3cceb 100644 --- a/src/main.electron.ts +++ b/src/main.electron.ts @@ -12,22 +12,30 @@ async function initializeSQLite() { try { const isAvailable = await window.CapacitorSQLite.isAvailable(); if (isAvailable) { - logger.info("[Electron] SQLite plugin bridge initialized successfully"); + logger.info( + "[Electron] SQLite plugin bridge initialized successfully", + ); return true; } } catch (error) { - logger.warn(`[Electron] SQLite not available yet (attempt ${retries + 1}/${maxRetries}):`, error); + logger.warn( + `[Electron] SQLite not available yet (attempt ${retries + 1}/${maxRetries}):`, + error, + ); } - + retries++; if (retries < maxRetries) { - await new Promise(resolve => setTimeout(resolve, retryDelay)); + await new Promise((resolve) => setTimeout(resolve, retryDelay)); } } throw new Error("SQLite plugin not available after maximum retries"); } catch (error) { - logger.error("[Electron] Failed to initialize SQLite plugin bridge:", error); + logger.error( + "[Electron] Failed to initialize SQLite plugin bridge:", + error, + ); throw error; } } @@ -52,11 +60,12 @@ initializeSQLite() logger.info("[Electron] SQLite initialized, mounting app..."); app.mount("#app"); }) - .catch(error => { + .catch((error) => { logger.error("[Electron] Failed to initialize app:", error); // Show error to user const errorDiv = document.createElement("div"); - errorDiv.style.cssText = "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #ffebee; color: #c62828; padding: 20px; border-radius: 4px; text-align: center; max-width: 80%;"; + errorDiv.style.cssText = + "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #ffebee; color: #c62828; padding: 20px; border-radius: 4px; text-align: center; max-width: 80%;"; errorDiv.innerHTML = `

Failed to Initialize Database

There was an error initializing the database. Please try restarting the application.

diff --git a/src/services/platforms/ElectronPlatformService.ts b/src/services/platforms/ElectronPlatformService.ts index 815cabb8..b86d5ee4 100644 --- a/src/services/platforms/ElectronPlatformService.ts +++ b/src/services/platforms/ElectronPlatformService.ts @@ -49,7 +49,7 @@ export class ElectronPlatformService implements PlatformService { try { await this.db.close(); } catch (e) { - logger.warn('Error closing existing connection:', e); + logger.warn("Error closing existing connection:", e); } this.db = null; } @@ -61,9 +61,9 @@ export class ElectronPlatformService implements PlatformService { this.dbConnectionErrorLogged = false; // Wait a moment for cleanup - await new Promise(resolve => setTimeout(resolve, 500)); + await new Promise((resolve) => setTimeout(resolve, 500)); } catch (error) { - logger.error('Error resetting connection:', error); + logger.error("Error resetting connection:", error); throw error; } } @@ -71,7 +71,7 @@ export class ElectronPlatformService implements PlatformService { private async initializeDatabase(): Promise { // If we have a fatal error, try to recover if (this.dbFatalError) { - logger.info('Attempting to recover from fatal error state...'); + logger.info("Attempting to recover from fatal error state..."); await this.resetConnection(); } @@ -99,30 +99,32 @@ export class ElectronPlatformService implements PlatformService { logger.info("Calling createConnection with:", { dbName: this.dbName, readOnly: false, - encryption: 'no-encryption', + encryption: "no-encryption", version: 1, - useNative: true + useNative: true, }); // Create connection this.db = await this.sqlite.createConnection( - this.dbName, // database name - false, // readOnly - 'no-encryption', // encryption - 1, // version - true // useNative + this.dbName, // database name + false, // readOnly + "no-encryption", // encryption + 1, // version + true, // useNative ); logger.info("createConnection result:", this.db); - if (!this.db || typeof this.db.execute !== 'function') { + if (!this.db || typeof this.db.execute !== "function") { throw new Error("Failed to create a valid database connection"); } // Verify connection is not read-only - const journalMode = await this.db.query('PRAGMA journal_mode;'); - if (journalMode?.values?.[0]?.journal_mode === 'off') { - throw new Error('Database opened in read-only mode despite options'); + const journalMode = await this.db.query("PRAGMA journal_mode;"); + if (journalMode?.values?.[0]?.journal_mode === "off") { + throw new Error( + "Database opened in read-only mode despite options", + ); } // Run migrations @@ -133,14 +135,18 @@ export class ElectronPlatformService implements PlatformService { this.dbConnectionErrorLogged = false; this.initialized = true; return; - } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); retryCount++; if (retryCount < this.MAX_RETRIES) { - logger.warn(`Database initialization attempt ${retryCount}/${this.MAX_RETRIES} failed:`, error); - await new Promise(resolve => setTimeout(resolve, this.RETRY_DELAY)); + logger.warn( + `Database initialization attempt ${retryCount}/${this.MAX_RETRIES} failed:`, + error, + ); + await new Promise((resolve) => + setTimeout(resolve, this.RETRY_DELAY), + ); await this.resetConnection(); } } @@ -149,12 +155,18 @@ export class ElectronPlatformService implements PlatformService { // If we get here, all retries failed this.dbFatalError = true; if (!this.dbConnectionErrorLogged) { - logger.error("[Electron] Error initializing SQLite database after all retries:", lastError); + logger.error( + "[Electron] Error initializing SQLite database after all retries:", + lastError, + ); this.dbConnectionErrorLogged = true; } this.initialized = false; this.initializationPromise = null; - throw lastError || new Error("Failed to initialize database after all retries"); + throw ( + lastError || + new Error("Failed to initialize database after all retries") + ); })(); return this.initializationPromise; @@ -413,7 +425,9 @@ export class ElectronPlatformService implements PlatformService { params?: unknown[], ): Promise<{ changes: number; lastId?: number }> { if (this.dbFatalError) { - throw new Error("Database is in a fatal error state. Please restart the app."); + throw new Error( + "Database is in a fatal error state. Please restart the app.", + ); } try { await this.initializeDatabase(); @@ -440,22 +454,26 @@ export class ElectronPlatformService implements PlatformService { try { await this.initializeDatabase(); } catch (error) { - console.error('Failed to initialize database:', error); - throw new Error(`Database initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + logger.error("Failed to initialize database:", error); + throw new Error( + `Database initialization failed: ${error instanceof Error ? error.message : "Unknown error"}`, + ); } } async query(sql: string, params: any[] = []): Promise { if (this.dbFatalError) { - throw new Error("Database is in a fatal error state. Please restart the app."); + throw new Error( + "Database is in a fatal error state. Please restart the app.", + ); } if (!this.initialized) { - throw new Error('Database not initialized. Call initialize() first.'); + throw new Error("Database not initialized. Call initialize() first."); } return this.initializeDatabase().then(() => { if (!this.db) { - throw new Error('Database not initialized after initialization'); + throw new Error("Database not initialized after initialization"); } return this.db.query(sql, params).then((result) => { if (!result?.values) { @@ -468,7 +486,7 @@ export class ElectronPlatformService implements PlatformService { async execute(sql: string, params: any[] = []): Promise { if (!this.initialized) { - throw new Error('Database not initialized. Call initialize() first.'); + throw new Error("Database not initialized. Call initialize() first."); } await this.initializeDatabase().then(() => { @@ -486,8 +504,10 @@ export class ElectronPlatformService implements PlatformService { this.initialized = false; this.db = null; } catch (error) { - console.error('Failed to close database:', error); - throw new Error(`Failed to close database: ${error instanceof Error ? error.message : 'Unknown error'}`); + logger.error("Failed to close database:", error); + throw new Error( + `Failed to close database: ${error instanceof Error ? error.message : "Unknown error"}`, + ); } } }