import type { CapacitorElectronConfig } from '@capacitor-community/electron'; import { getCapacitorElectronConfig, setupElectronDeepLinking } from '@capacitor-community/electron'; import type { MenuItemConstructorOptions } from 'electron'; import { app, MenuItem } from 'electron'; import electronIsDev from 'electron-is-dev'; import unhandled from 'electron-unhandled'; import { autoUpdater } from 'electron-updater'; import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup'; import { initializeSQLite, setupSQLiteHandlers } from './rt/sqlite-init'; // Graceful handling of unhandled errors. unhandled(); // Define our menu templates (these are optional) const trayMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [new MenuItem({ label: 'Quit App', role: 'quit' })]; const appMenuBarMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [ { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' }, { role: 'viewMenu' }, ]; // Get Config options from capacitor.config const capacitorFileConfig: CapacitorElectronConfig = getCapacitorElectronConfig(); // Initialize our app. You can pass menu templates into the app here. const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig, trayMenuTemplate, appMenuBarMenuTemplate); // If deeplinking is enabled then we will set it up here. if (capacitorFileConfig.electron?.deepLinkingEnabled) { setupElectronDeepLinking(myCapacitorApp, { customProtocol: capacitorFileConfig.electron.deepLinkingCustomProtocol ?? 'mycapacitorapp', }); } // If we are in Dev mode, use the file watcher components. if (electronIsDev) { setupReloadWatcher(myCapacitorApp); } // Run Application (async () => { try { // Wait for electron app to be ready. await app.whenReady(); // Security - Set Content-Security-Policy based on whether or not we are in dev mode. setupContentSecurityPolicy(myCapacitorApp.getCustomURLScheme()); // Initialize SQLite and register handlers BEFORE app initialization console.log('[Main] Starting SQLite initialization...'); try { // Register handlers first to prevent "no handler" errors setupSQLiteHandlers(); console.log('[Main] SQLite handlers registered'); // Then initialize the plugin await initializeSQLite(); console.log('[Main] SQLite plugin initialized successfully'); } catch (error) { console.error('[Main] Failed to initialize SQLite:', error); // Don't proceed with app initialization if SQLite fails throw new Error(`SQLite initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } // Initialize our app, build windows, and load content. console.log('[Main] Starting app initialization...'); await myCapacitorApp.init(); console.log('[Main] App initialization complete'); // Check for updates if we are in a packaged app. if (!electronIsDev) { console.log('[Main] Checking for updates...'); autoUpdater.checkForUpdatesAndNotify(); } } catch (error) { console.error('[Main] Fatal error during app initialization:', error); // Ensure we notify the user before quitting const mainWindow = myCapacitorApp.getMainWindow(); if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('app-error', { type: 'initialization', error: error instanceof Error ? error.message : 'Unknown error' }); // Give the window time to show the error setTimeout(() => app.quit(), 5000); } else { app.quit(); } } })(); // Handle when all of our windows are close (platforms have their own expectations). app.on('window-all-closed', function () { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit(); } }); // When the dock icon is clicked. app.on('activate', async function () { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (myCapacitorApp.getMainWindow().isDestroyed()) { await myCapacitorApp.init(); } }); // Place all ipc or other electron api calls and custom functionality under this line