205 lines
5.8 KiB
TypeScript
205 lines
5.8 KiB
TypeScript
const { app, BrowserWindow, ipcMain } = require('electron');
|
|
const path = require('path');
|
|
const os = require('os');
|
|
const spawn = require('child_process').spawn;
|
|
const { store: electronStore } = require('./store');
|
|
const { setupIpcHandlers } = require('./ipc/handlers');
|
|
const { MeiliSearch } = require('meilisearch');
|
|
|
|
const slugify = (str: string) => {
|
|
return str
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-|-$/g, '');
|
|
};
|
|
|
|
const { platform } = require('os');
|
|
import MeilisearchService from './services/meilisearchService';
|
|
|
|
const meilisearchService = new MeilisearchService();
|
|
(global as any).meilisearchService = meilisearchService;
|
|
|
|
// Initialize IPC handlers immediately
|
|
setupIpcHandlers();
|
|
|
|
function createWindow() {
|
|
const mainWindow = new BrowserWindow({
|
|
width: 1200,
|
|
height: 800,
|
|
minWidth: 1200, // Minimum width
|
|
minHeight: 800, // Minimum height
|
|
frame: false,
|
|
titleBarStyle: 'hidden',
|
|
webPreferences: {
|
|
nodeIntegration: false,
|
|
contextIsolation: true,
|
|
preload: path.join(__dirname, 'preload.js'),
|
|
sandbox: false,
|
|
webSecurity: true,
|
|
},
|
|
});
|
|
|
|
// Enable logging
|
|
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
|
console.error('Failed to load:', errorCode, errorDescription);
|
|
});
|
|
|
|
mainWindow.webContents.on('console-message', (event, level, message) => {
|
|
console.log('Renderer Console:', message);
|
|
});
|
|
|
|
// In development, use the Vite dev server
|
|
if (process.env.VITE_DEV_SERVER_URL) {
|
|
// Wait for dev server to be ready
|
|
const pollDevServer = async () => {
|
|
try {
|
|
const response = await fetch(process.env.VITE_DEV_SERVER_URL);
|
|
if (response.ok) {
|
|
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
|
|
//mainWindow.webContents.openDevTools();
|
|
} else {
|
|
setTimeout(pollDevServer, 500);
|
|
}
|
|
} catch {
|
|
setTimeout(pollDevServer, 500);
|
|
}
|
|
};
|
|
pollDevServer();
|
|
} else {
|
|
// In production, load the built files
|
|
const prodPath = path.join(__dirname, '../dist/index.html');
|
|
console.log('Production mode detected');
|
|
console.log('__dirname:', __dirname);
|
|
console.log('Attempting to load:', prodPath);
|
|
|
|
// Check if the file exists
|
|
try {
|
|
if (require('fs').existsSync(prodPath)) {
|
|
console.log('Found production build at:', prodPath);
|
|
mainWindow.loadFile(prodPath).catch(err => {
|
|
console.error('Failed to load production file:', err);
|
|
// Try alternative path
|
|
const altPath = path.join(process.cwd(), 'dist/index.html');
|
|
console.log('Trying alternative path:', altPath);
|
|
if (require('fs').existsSync(altPath)) {
|
|
mainWindow.loadFile(altPath).catch(err => {
|
|
console.error('Failed to load alternative path:', err);
|
|
});
|
|
} else {
|
|
console.error('Alternative path does not exist');
|
|
}
|
|
});
|
|
} else {
|
|
console.error('Production build not found at:', prodPath);
|
|
// Try alternative path
|
|
const altPath = path.join(process.cwd(), 'dist/index.html');
|
|
console.log('Trying alternative path:', altPath);
|
|
if (require('fs').existsSync(altPath)) {
|
|
mainWindow.loadFile(altPath).catch(err => {
|
|
console.error('Failed to load alternative path:', err);
|
|
});
|
|
} else {
|
|
console.error('Alternative path does not exist');
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('Error checking file existence:', err);
|
|
}
|
|
}
|
|
|
|
mainWindow.once('ready-to-show', () => {
|
|
mainWindow.show();
|
|
});
|
|
|
|
// Handle window state
|
|
const windowState = electronStore.get('windowState', {
|
|
width: 1200,
|
|
height: 800
|
|
});
|
|
mainWindow.setSize(windowState.width, windowState.height);
|
|
|
|
mainWindow.on('close', () => {
|
|
const { width, height } = mainWindow.getBounds();
|
|
electronStore.set('windowState', { width, height });
|
|
});
|
|
|
|
// Set up security headers
|
|
mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
|
|
callback({
|
|
responseHeaders: {
|
|
...details.responseHeaders,
|
|
'Content-Security-Policy': [
|
|
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"
|
|
]
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
app.whenReady().then(() => {
|
|
meilisearchService.startServer();
|
|
createWindow();
|
|
|
|
app.on('activate', () => {
|
|
if (BrowserWindow.getAllWindows().length === 0) {
|
|
createWindow();
|
|
}
|
|
});
|
|
});
|
|
|
|
app.on('window-all-closed', () => {
|
|
if (process.platform !== 'darwin') {
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
// IPC handlers for file system operations
|
|
ipcMain.handle('get-app-path', () => {
|
|
return app.getPath('userData');
|
|
});
|
|
|
|
// Window control handlers
|
|
ipcMain.handle('window-minimize', (event) => {
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
window?.minimize();
|
|
});
|
|
|
|
ipcMain.handle('window-maximize', (event) => {
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
if (window?.isMaximized()) {
|
|
window.unmaximize();
|
|
} else {
|
|
window?.maximize();
|
|
}
|
|
});
|
|
|
|
ipcMain.handle('window-close', (event) => {
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
window?.close();
|
|
});
|
|
|
|
ipcMain.handle('open-external', (_, url) => {
|
|
return require('electron').shell.openExternal(url);
|
|
});
|
|
|
|
// Launch the server
|
|
if (process.env.NODE_ENV !== 'development') {
|
|
const serverProcess = spawn('node', [path.join(__dirname, '../scripts/dev.cjs')], {
|
|
stdio: 'inherit',
|
|
});
|
|
|
|
serverProcess.on('close', (code) => {
|
|
console.log(`Server process exited with code ${code}`);
|
|
});
|
|
|
|
serverProcess.on('error', (err) => {
|
|
console.error('Failed to start server process:', err);
|
|
});
|
|
}
|
|
|
|
app.on('will-quit', () => {
|
|
meilisearchService.stopServer();
|
|
});
|
|
|
|
module.exports = app;
|