docs: update electron/README.md, USER_GUIDE.md, FEATURES.md with desktop app docs

This commit is contained in:
diegosouzapw
2026-02-28 08:33:55 -03:00
parent d624ddde03
commit 9a3d72c6a2
3 changed files with 171 additions and 41 deletions
+16
View File
@@ -75,3 +75,19 @@ Real-time request logging with filtering by provider, model, account, and API ke
Your unified API endpoint with capability breakdown: Chat Completions, Embeddings, Image Generation, Reranking, Audio Transcription, and registered API keys.
![Endpoint Dashboard](screenshots/09-endpoint.png)
---
## 🖥️ Desktop Application
Native Electron desktop app for Windows, macOS, and Linux. Run OmniRoute as a standalone application with system tray integration, offline support, and one-click install.
Key features:
- Server readiness polling (no blank screen on cold start)
- System tray with port management
- Content Security Policy
- Single-instance lock
- Platform-conditional UI (macOS traffic lights, Windows/Linux default titlebar)
📖 See [`electron/README.md`](../electron/README.md) for full documentation.
+52
View File
@@ -755,3 +755,55 @@ Access via **Dashboard → Health**. Real-time system health overview with 6 car
| **Latency Telemetry** | p50/p95/p99 latency aggregation per provider |
**Pro Tip:** The Health page auto-refreshes every 10 seconds. Use the circuit breaker card to identify which providers are experiencing issues.
---
## 🖥️ Desktop Application (Electron)
OmniRoute is available as a native desktop application for Windows, macOS, and Linux.
### Installation
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Building Installers
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Output → `electron/dist-electron/`
### Key Features
| Feature | Description |
| --------------------------- | ---------------------------------------------------- |
| **Server Readiness** | Polls server before showing window (no blank screen) |
| **System Tray** | Minimize to tray, change port, quit from tray menu |
| **Port Management** | Change server port from tray (auto-restarts server) |
| **Content Security Policy** | Restrictive CSP via session headers |
| **Single Instance** | Only one app instance can run at a time |
| **Offline Mode** | Bundled Next.js server works without internet |
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------- | -------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
📖 Full documentation: [`electron/README.md`](../electron/README.md)
+103 -41
View File
@@ -2,27 +2,43 @@
This directory contains the Electron desktop application wrapper for OmniRoute.
## Structure
## Architecture (v1.6.4)
```
electron/
├── main.js # Main process (window management, IPC)
├── preload.js # Preload script (secure bridge to renderer)
├── package.json # Electron-specific dependencies
├── types.d.ts # TypeScript definitions
├── 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
@@ -31,11 +47,13 @@ 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
@@ -44,11 +62,13 @@ 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
@@ -57,6 +77,7 @@ npm start
## Building
### Build for Current Platform
```bash
cd electron
npm run build
@@ -68,7 +89,7 @@ npm run build
# Windows
npm run build:win
# macOS
# macOS (x64 + arm64)
npm run build:mac
# Linux
@@ -78,72 +99,113 @@ npm run build:linux
## Output
Built applications are placed in `dist-electron/`:
- Windows: `.exe` installer (NSIS)
- macOS: `.dmg` installer
- macOS: `.dmg` installer (universal)
- Linux: `.AppImage`
## Features
- **System Tray Integration**: Minimize to tray, quick actions
- **Native Notifications**: Desktop notifications
- **Window Management**: Minimize, maximize, close
- **Auto-start**: Option to launch on system startup
- **Offline Support**: Local server bundled with the app
- **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
The Electron app respects these environment variables:
- `OMNIROUTE_PORT`: Server port (default: 20128)
- `NODE_ENV`: Set to 'production' for production builds
| Variable | Default | Description |
| --------------------- | ------------ | --------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
| `NODE_ENV` | `production` | Set to `development` for dev mode |
### Custom Icon
Place your icons in `assets/`:
- `icon.ico` - Windows icon (256x256)
- `icon.icns` - macOS icon bundle
- `icon.png` - Linux/general use (512x512)
- `tray-icon.png` - System tray icon (16x16 or 32x32)
- `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
| Channel | Direction | Description |
|---------|-----------|-------------|
| `get-app-info` | Renderer → Main | Get app name, version, platform |
| `open-external` | Renderer → Main | Open URL in default browser |
| `get-data-dir` | Renderer → Main | Get data directory path |
| `restart-server` | Renderer → Main | Restart the internal server |
| `server-status` | Main → Renderer | Server status updates |
| `port-changed` | Main → Renderer | Port change notifications |
### 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
- `contextIsolation: true` - Isolates renderer from Node.js
- `nodeIntegration: false` - No direct Node.js access in renderer
- Preload script validates IPC channels
- No remote code execution
| 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
2. Check logs in the console
3. Verify the build output exists
1. Check if port 20128 is available: `lsof -i :20128`
2. Check console logs for `[Electron]` prefix
3. Verify the build output exists in `.next/standalone`
### White Screen
1. Verify Next.js build exists
2. Check the server URL in main.js
3. Check for console errors
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
1. Ensure you have build tools installed:
- Windows: Visual Studio Build Tools
- macOS: Xcode Command Line Tools
- Linux: build-essential, libsecret-1-dev
Ensure you have build tools installed:
- Windows: Visual Studio Build Tools
- macOS: Xcode Command Line Tools
- Linux: `build-essential`, `libsecret-1-dev`
## License