import { app, BrowserWindow, shell, ipcMain, dialog, Menu } from 'electron'; import { autoUpdater } from 'electron-updater'; import { registerGlobalErrorHandlers, showErrorDialog } from './modules/errors'; import { startNextServer } from './modules/server'; import { createMainWindow } from './modules/window'; import { setupDeepLinks, handlePendingDeepLink } from './modules/deep-links'; registerGlobalErrorHandlers(); if (!setupDeepLinks()) { app.quit(); } const isDev = !app.isPackaged; // IPC handlers ipcMain.on('open-external', (_event, url: string) => { try { const parsed = new URL(url); if (parsed.protocol === 'http:' || parsed.protocol === 'https:') { shell.openExternal(url); } } catch { // invalid URL — ignore } }); ipcMain.handle('get-app-version', () => { return app.getVersion(); }); function setupAutoUpdater() { if (isDev) return; autoUpdater.autoDownload = true; autoUpdater.on('update-available', (info) => { console.log(`Update available: ${info.version}`); }); autoUpdater.on('update-downloaded', (info) => { console.log(`Update downloaded: ${info.version}`); dialog.showMessageBox({ type: 'info', buttons: ['Restart', 'Later'], defaultId: 0, title: 'Update Ready', message: `Version ${info.version} has been downloaded. Restart to apply the update.`, }).then(({ response }) => { if (response === 0) { autoUpdater.quitAndInstall(); } }); }); autoUpdater.on('error', (err) => { console.error('Auto-updater error:', err); }); autoUpdater.checkForUpdates(); } function setupMenu() { const isMac = process.platform === 'darwin'; const template: Electron.MenuItemConstructorOptions[] = [ ...(isMac ? [{ role: 'appMenu' as const }] : []), { role: 'fileMenu' as const }, { role: 'editMenu' as const }, { role: 'viewMenu' as const }, { role: 'windowMenu' as const }, ]; Menu.setApplicationMenu(Menu.buildFromTemplate(template)); } // App lifecycle app.whenReady().then(async () => { setupMenu(); try { await startNextServer(); } catch (error) { showErrorDialog('Failed to start SurfSense', error); setTimeout(() => app.quit(), 0); return; } createMainWindow(); setupAutoUpdater(); handlePendingDeepLink(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createMainWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('will-quit', () => { // Server runs in-process — no child process to kill });