Spaces:
Runtime error
Runtime error
| # OmniRoute Electron Desktop App | |
| This directory contains the Electron desktop application wrapper for OmniRoute. | |
| ## Architecture (v1.6.4) | |
| ``` | |
| electron/ | |
| βββ main.js # Main process β window, tray, server lifecycle, CSP, IPC | |
| βββ preload.js # Preload script β secure IPC bridge with disposer pattern | |
| βββ package.json # Electron-specific dependencies & electron-builder config | |
| βββ types.d.ts # TypeScript definitions (AppInfo, ServerStatus, ElectronAPI) | |
| βββ assets/ # Application icons and resources | |
| src/shared/hooks/ | |
| βββ useElectron.ts # React hooks β useSyncExternalStore, zero re-renders | |
| ``` | |
| ## Key Design Decisions | |
| | Decision | Rationale | | |
| | ----------------------------- | ------------------------------------------------------------------------------------------------ | | |
| | `waitForServer()` polling | Prevents blank screen on cold start β polls `http://localhost:PORT` before loading | | |
| | `stdio: 'pipe'` | Captures server stdout/stderr for logging + readiness detection (not `inherit`) | | |
| | Disposer pattern | `onServerStatus()` returns `() => void` for precise listener cleanup (no `removeAllListeners`) | | |
| | `useSyncExternalStore` | Zero re-renders for `useIsElectron()` β no `useState` + `useEffect` cycle | | |
| | CSP via session headers | `Content-Security-Policy` restricts `script-src`, `connect-src` etc. per Electron best practices | | |
| | Platform-conditional titlebar | `titleBarStyle: 'hiddenInset'` only on macOS; `default` on Windows/Linux | | |
| ## Development | |
| ### Prerequisites | |
| 1. Build the Next.js app first: | |
| ```bash | |
| npm run build | |
| ``` | |
| 2. Install Electron dependencies: | |
| ```bash | |
| cd electron | |
| npm install | |
| ``` | |
| ### Running in Development | |
| 1. Start the Next.js development server: | |
| ```bash | |
| npm run dev | |
| ``` | |
| 2. In another terminal, start Electron: | |
| ```bash | |
| cd electron | |
| npm run dev | |
| ``` | |
| ### Running in Production Mode | |
| 1. Build Next.js in standalone mode: | |
| ```bash | |
| npm run build | |
| ``` | |
| 2. Start Electron: | |
| ```bash | |
| cd electron | |
| npm start | |
| ``` | |
| ## Building | |
| ### Build for Current Platform | |
| ```bash | |
| cd electron | |
| npm run build | |
| ``` | |
| ### Build for Specific Platforms | |
| ```bash | |
| # Windows | |
| npm run build:win | |
| # macOS (x64 + arm64) | |
| npm run build:mac | |
| # Linux | |
| npm run build:linux | |
| ``` | |
| ## Output | |
| Built applications are placed in `dist-electron/`: | |
| - Windows: `.exe` installer (NSIS) + portable `.exe` | |
| - macOS: `.dmg` installer (Intel + Apple Silicon) | |
| - Linux: `.AppImage` | |
| ## Installation | |
| ### macOS | |
| 1. Download the latest `.dmg` from the [Releases](https://github.com/diegosouzapw/OmniRoute/releases) page. | |
| 2. Open the `.dmg` file. | |
| 3. Drag `OmniRoute.app` to the Applications folder. | |
| 4. Launch from Applications. | |
| > β οΈ **Note:** The app is not signed with an Apple Developer certificate yet. If macOS blocks the app, run: | |
| > ```bash | |
| > xattr -cr /Applications/OmniRoute.app | |
| > ``` | |
| > Or right-click the app β Open β Open (to bypass Gatekeeper on first launch). | |
| ### Windows | |
| **Installer (Recommended):** | |
| 1. Download `OmniRoute.Setup.*.exe` from [Releases](https://github.com/diegosouzapw/OmniRoute/releases). | |
| 2. Run the installer. | |
| 3. Launch from Start Menu or Desktop shortcut. | |
| **Portable (No Installation):** | |
| 1. Download `OmniRoute.exe` from [Releases](https://github.com/diegosouzapw/OmniRoute/releases). | |
| 2. Run directly from any folder. | |
| ### Linux | |
| 1. Download the `.AppImage` from [Releases](https://github.com/diegosouzapw/OmniRoute/releases). | |
| 2. Make it executable: | |
| ```bash | |
| chmod +x OmniRoute-*.AppImage | |
| ``` | |
| 3. Run: | |
| ```bash | |
| ./OmniRoute-*.AppImage | |
| ``` | |
| ## Features | |
| - **Server Readiness** β Waits for health check before showing window | |
| - **System Tray** β Minimize to tray with quick actions (open, port change, quit) | |
| - **Port Management** β Change port from tray menu (server restarts automatically) | |
| - **Window Controls** β Custom minimize, maximize, close via IPC | |
| - **Content Security Policy** β Restrictive CSP via session headers | |
| - **Offline Support** β Bundled Next.js standalone server | |
| - **Single Instance** β Only one app instance can run at a time | |
| ## Configuration | |
| ### Environment Variables | |
| | Variable | Default | Description | | |
| | --------------------- | ------------ | --------------------------------- | | |
| | `OMNIROUTE_PORT` | `20128` | Server port | | |
| | `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (64β16384 MB) | | |
| | `NODE_ENV` | `production` | Set to `development` for dev mode | | |
| ### Custom Icon | |
| Place your icons in `assets/`: | |
| - `icon.ico` β Windows icon (256Γ256) | |
| - `icon.icns` β macOS icon bundle | |
| - `icon.png` β Linux/general use (512Γ512) | |
| - `tray-icon.png` β System tray icon (16Γ16 or 32Γ32) | |
| ## IPC Channels | |
| ### Invoke (Renderer β Main, async) | |
| | Channel | Returns | Description | | |
| | ---------------- | ------------- | --------------------------------------------- | | |
| | `get-app-info` | `AppInfo` | App name, version, platform, isDev, port | | |
| | `open-external` | `void` | Open URL in default browser (http/https only) | | |
| | `get-data-dir` | `string` | Get userData directory path | | |
| | `restart-server` | `{ success }` | Stop + restart server (5s timeout + SIGKILL) | | |
| ### Send (Renderer β Main, fire-and-forget) | |
| | Channel | Description | | |
| | ----------------- | ------------------------------- | | |
| | `window-minimize` | Minimize window | | |
| | `window-maximize` | Toggle maximize/restore | | |
| | `window-close` | Close window (minimize to tray) | | |
| ### Receive (Main β Renderer, events) | |
| | Channel | Payload | Emitted When | | |
| | --------------- | -------------- | ----------------------------------------- | | |
| | `server-status` | `ServerStatus` | Server starts, stops, errors, or restarts | | |
| | `port-changed` | `number` | Port change via tray menu | | |
| > **Note**: Listeners return disposer functions for precise cleanup. See `useServerStatus` and `usePortChanged` hooks. | |
| ## Security | |
| | Feature | Implementation | | |
| | ----------------- | ------------------------------------------------------------------------------- | | |
| | Context Isolation | `contextIsolation: true` β renderer cannot access Node.js | | |
| | Node Integration | `nodeIntegration: false` β no `require()` in renderer | | |
| | IPC Whitelist | Channel names validated in preload via `safeInvoke`/`safeSend`/`safeOn` | | |
| | URL Validation | `shell.openExternal()` only allows `http:` / `https:` protocols | | |
| | CSP | `Content-Security-Policy` header set via `session.webRequest.onHeadersReceived` | | |
| | Web Security | `webSecurity: true` β same-origin policy enforced | | |
| ## React Hooks | |
| | Hook | Returns | Description | | |
| | ---------------------- | ------------------------------- | ------------------------------------------------ | | |
| | `useIsElectron()` | `boolean` | Zero-render detection via `useSyncExternalStore` | | |
| | `useElectronAppInfo()` | `{ appInfo, loading, error }` | App info from main process | | |
| | `useDataDir()` | `{ dataDir, loading, error }` | User data directory | | |
| | `useWindowControls()` | `{ minimize, maximize, close }` | Window control actions | | |
| | `useOpenExternal()` | `{ openExternal }` | Open URLs in browser | | |
| | `useServerControls()` | `{ restart, restarting }` | Server restart control | | |
| | `useServerStatus(cb)` | Disposer | Listen for server status events | | |
| | `usePortChanged(cb)` | Disposer | Listen for port change events | | |
| ## Troubleshooting | |
| ### App Won't Start | |
| 1. Check if port 20128 is available: `lsof -i :20128` | |
| 2. Check console logs for `[Electron]` prefix | |
| 3. Verify the build output exists in `.build/next/standalone` | |
| ### White Screen | |
| 1. Verify Next.js build exists β server readiness waits 30s max | |
| 2. Check `[Server]` and `[Server:err]` log output | |
| 3. Look for CSP violations in developer console | |
| ### Build Fails | |
| Ensure you have build tools installed: | |
| - Windows: Visual Studio Build Tools | |
| - macOS: Xcode Command Line Tools | |
| - Linux: `build-essential`, `libsecret-1-dev` | |
| ## License | |
| MIT | |