import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import path from 'path'; import { fileURLToPath } from 'url'; import http from 'http'; import fs from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let mainWindow = null; let docsPath = ''; let port = 3001; const DEFAULT_PORT = 3001; function parseArgs() { const args = { port: DEFAULT_PORT, docs: null, headless: false }; const portIndex = process.argv.indexOf('--port'); if (portIndex !== -1 && process.argv[portIndex + 1]) { args.port = parseInt(process.argv[portIndex + 1], 10); } const docsIndex = process.argv.indexOf('--docs'); if (docsIndex !== -1 && process.argv[docsIndex + 1]) { args.docs = process.argv[docsIndex + 1]; } if (process.argv.includes('--headless')) { args.headless = true; } return args; } const args = parseArgs(); port = args.port; docsPath = args.docs || path.join(process.cwd(), 'src', 'docs'); function getDistPath() { if (app.isPackaged) { return path.join(__dirname, '..', 'dist'); } return path.join(__dirname, '..', 'dist'); } function loadDistServer() { const distPath = getDistPath(); const server = http.createServer((req, res) => { let filePath = path.join(distPath, req.url === '/' ? 'index.html' : req.url); if (!filePath.startsWith(distPath)) { res.writeHead(403); res.end('Forbidden'); return; } const ext = path.extname(filePath); const contentTypes = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml', '.md': 'text/markdown', }; if (fs.existsSync(filePath)) { const contentType = contentTypes[ext] || 'application/octet-stream'; res.writeHead(200, { 'Content-Type': contentType }); res.end(fs.readFileSync(filePath)); } else { res.writeHead(404); res.end('Not Found'); } }); server.listen(port, () => { console.log(`XCSDD Server running on http://localhost:${port}`); console.log(`Docs path: ${docsPath}`); if (args.headless) { console.log(`Headless mode: enabled`); } }); return server; } function createWindow() { if (args.headless) { loadDistServer(); return; } loadDistServer(); mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.mjs'), contextIsolation: true, nodeIntegration: false, }, }); mainWindow.loadURL(`http://localhost:${port}`); mainWindow.on('closed', () => { mainWindow = null; }); } ipcMain.handle('select-folder', async () => { if (!mainWindow) return null; const result = await dialog.showOpenDialog(mainWindow, { properties: ['openDirectory'], }); if (result.canceled || result.filePaths.length === 0) { return null; } docsPath = result.filePaths[0]; mainWindow.webContents.send('docs-path-changed', docsPath); return docsPath; }); ipcMain.handle('get-docs-path', () => { return docsPath; }); app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } });