const { spawn } = require('child_process'); const DEV_SINGLE_INSTANCE_EXIT_CODE = 23; const DEV_SINGLE_INSTANCE_EXIT_CODE_ENV = 'METOYOU_SINGLE_INSTANCE_EXIT_CODE'; function isWaylandSession(env) { const sessionType = String(env.XDG_SESSION_TYPE || '').trim().toLowerCase(); if (sessionType === 'wayland') { return true; } return String(env.WAYLAND_DISPLAY || '').trim().length > 0; } function hasSwitch(args, switchName) { const normalizedSwitch = `--${switchName}`; return args.some((arg) => arg === normalizedSwitch || arg.startsWith(`${normalizedSwitch}=`)); } function resolveElectronBinary() { const electronModule = require('electron'); if (typeof electronModule === 'string') { return electronModule; } if (electronModule && typeof electronModule.default === 'string') { return electronModule.default; } throw new Error('Could not resolve the Electron executable.'); } function buildElectronArgs(argv) { const args = [...argv]; if ( process.platform === 'linux' && isWaylandSession(process.env) && !hasSwitch(args, 'ozone-platform') ) { args.push('--ozone-platform=wayland'); } return args; } function isDevelopmentLaunch(env) { return String(env.NODE_ENV || '').trim().toLowerCase() === 'development'; } function buildChildEnv(env) { const nextEnv = { ...env }; if (isDevelopmentLaunch(env)) { nextEnv[DEV_SINGLE_INSTANCE_EXIT_CODE_ENV] = String(DEV_SINGLE_INSTANCE_EXIT_CODE); } return nextEnv; } function keepProcessAliveForExistingInstance() { console.log( 'Electron is already running; keeping the dev services alive and routing links to the open window.' ); const intervalId = setInterval(() => {}, 60_000); const shutdown = () => { clearInterval(intervalId); process.exit(0); }; process.once('SIGINT', shutdown); process.once('SIGTERM', shutdown); } function main() { const electronBinary = resolveElectronBinary(); const args = buildElectronArgs(process.argv.slice(2)); const child = spawn(electronBinary, args, { env: buildChildEnv(process.env), stdio: 'inherit' }); child.on('error', (error) => { console.error(error instanceof Error ? error.message : String(error)); process.exit(1); }); child.on('exit', (code, signal) => { if (code === DEV_SINGLE_INSTANCE_EXIT_CODE) { keepProcessAliveForExistingInstance(); return; } if (signal) { process.kill(process.pid, signal); return; } process.exit(code ?? 0); }); } main();