import { app, BrowserWindow } from "electron"; import path from "path"; import fs from "fs"; // Simple logger implementation const logger = { // eslint-disable-next-line no-console log: (...args: unknown[]) => console.log(...args), // eslint-disable-next-line no-console error: (...args: unknown[]) => console.error(...args), // eslint-disable-next-line no-console info: (...args: unknown[]) => console.info(...args), // eslint-disable-next-line no-console warn: (...args: unknown[]) => console.warn(...args), // eslint-disable-next-line no-console debug: (...args: unknown[]) => console.debug(...args), }; // Check if running in dev mode const isDev = process.argv.includes("--inspect"); async function createWindow(): Promise { // Add before createWindow function const preloadPath = app.isPackaged ? path.join(app.getAppPath(), "dist-electron", "preload.js") : path.join(__dirname, "preload.js"); logger.log("Checking preload path:", preloadPath); logger.log("Preload exists:", fs.existsSync(preloadPath)); // Log environment and paths logger.log("process.cwd():", process.cwd()); logger.log("__dirname:", __dirname); logger.log("app.getAppPath():", app.getAppPath()); logger.log("app.isPackaged:", app.isPackaged); // List files in __dirname and __dirname/www try { logger.log("Files in __dirname:", fs.readdirSync(__dirname)); const wwwDir = path.join(__dirname, "www"); if (fs.existsSync(wwwDir)) { logger.log("Files in www:", fs.readdirSync(wwwDir)); } else { logger.log("www directory does not exist in __dirname"); } } catch (e) { logger.error("Error reading directories:", e); } // Create the browser window. const mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: false, contextIsolation: true, webSecurity: true, allowRunningInsecureContent: false, preload: preloadPath, }, }); // Always open DevTools for now mainWindow.webContents.openDevTools(); // Intercept requests to robustly fix asset paths for Electron mainWindow.webContents.session.webRequest.onBeforeRequest( { urls: ["*://*/*"] }, (details, callback) => { const url = details.url; logger.log('[main.ts] Intercepted request:', url); // Match both file:///assets/... and /assets/... const assetMatch = url.match(/(?:file:\/\/\/|file:\/\/|https?:\/\/[^\/]+)?\/assets\/(.+)/); if (assetMatch) { const assetRelPath = assetMatch[1]; const assetAbsPath = path.join(app.getAppPath(), "dist-electron", "www", "assets", assetRelPath); logger.log('[main.ts] Asset request detected:', { originalUrl: url, assetRelPath, assetAbsPath, exists: fs.existsSync(assetAbsPath) }); if (fs.existsSync(assetAbsPath)) { const newUrl = `file://${assetAbsPath}`; logger.log('[main.ts] Redirecting to:', newUrl); callback({ redirectURL: newUrl }); return; } else { logger.error('[main.ts] Asset file not found:', assetAbsPath); } } callback({}); } ); if (isDev) { // Debug info logger.log("Debug Info:"); logger.log("Running in dev mode:", isDev); logger.log("App is packaged:", app.isPackaged); logger.log("Process resource path:", process.resourcesPath); logger.log("App path:", app.getAppPath()); logger.log("__dirname:", __dirname); logger.log("process.cwd():", process.cwd()); } let indexPath: string; if (app.isPackaged) { indexPath = path.join( app.getAppPath(), "dist-electron", "www", "index.html", ); logger.log("[main.ts] Using packaged indexPath:", indexPath); } else { indexPath = path.resolve( process.cwd(), "dist-electron", "www", "index.html", ); logger.log("[main.ts] Using dev indexPath:", indexPath); if (!fs.existsSync(indexPath)) { logger.error("[main.ts] Dev index.html not found:", indexPath); throw new Error("Index file not found"); } } if (isDev) { logger.log("Loading index from:", indexPath); logger.log("www path:", path.join(__dirname, "www")); logger.log("www assets path:", path.join(__dirname, "www", "assets")); } // Add CSP headers to allow API connections mainWindow.webContents.session.webRequest.onHeadersReceived( (details, callback) => { callback({ responseHeaders: { ...details.responseHeaders, "Content-Security-Policy": [ "default-src 'self';" + "connect-src 'self' https://api.endorser.ch https://*.timesafari.app;" + "img-src 'self' data: https: blob:;" + "script-src 'self' 'unsafe-inline' 'unsafe-eval';" + "style-src 'self' 'unsafe-inline';" + "font-src 'self' data:;", ], }, }); }, ); // Load the index.html with the correct base URL for assets const baseURL = `file://${path.dirname(indexPath)}/`; logger.log('[main.ts] Loading with base URL:', baseURL); try { await mainWindow.loadURL(`file://${indexPath}`); logger.log("Successfully loaded index.html"); if (isDev) { mainWindow.webContents.openDevTools(); logger.log("DevTools opened - running in dev mode"); } } catch (err) { logger.error("Failed to load index.html:", err); logger.error("Attempted path:", indexPath); } // Listen for console messages from the renderer mainWindow.webContents.on("console-message", (_event, _level, message) => { logger.log("Renderer Console:", message); }); // Add right after creating the BrowserWindow mainWindow.webContents.on( "did-fail-load", (_event, errorCode, errorDescription) => { logger.error("Page failed to load:", errorCode, errorDescription); }, ); mainWindow.webContents.on("preload-error", (_event, preloadPath, error) => { logger.error("Preload script error:", preloadPath, error); }); mainWindow.webContents.on( "console-message", (_event, _level, message, line, sourceId) => { logger.log("Renderer Console:", line, sourceId, message); }, ); // Enable remote debugging when in dev mode if (isDev) { mainWindow.webContents.openDevTools(); } } // Handle app ready app.whenReady().then(createWindow); // Handle all windows closed app.on("window-all-closed", () => { if (process.platform !== "darwin") { app.quit(); } }); app.on("activate", () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // Handle any errors process.on("uncaughtException", (error) => { logger.error("Uncaught Exception:", error); });