187 lines
9.2 KiB
Markdown
187 lines
9.2 KiB
Markdown
# Desktop
|
|
|
|
The native gateway for our monorepo applications.
|
|
|
|
> This package serves as a secure, high-performance Electron wrapper that transforms our web-based assets into first-class desktop experiences. Built on top of **electron-vite** for near-instant development cycles and **electron-builder** for seamless cross-platform distribution.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# From the monorepo root
|
|
|
|
# Install dependencies
|
|
pnpm install
|
|
|
|
# Development (starts both the web dev server and Electron)
|
|
pnpm dev:desktop
|
|
|
|
# Build for production
|
|
pnpm build:desktop
|
|
|
|
# Package for distribution
|
|
pnpm package:desktop
|
|
```
|
|
|
|
---
|
|
|
|
## How It Works
|
|
|
|
| Environment | Operational Logic |
|
|
|---|---|
|
|
| **Development** | Bridges the Electron shell with the Vite Dev Server, enabling Hot Module Replacement (HMR) and real-time UI synchronization at `http://localhost:5173`. |
|
|
| **Production** | Orchestrates a Secure Custom Protocol (`app://`) to serve optimized static assets, ensuring seamless SPA client-side routing via an intelligent `index.html` fallback mechanism. |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
apps/desktop/
|
|
├── docs/ # Architecture & Operations Documentation
|
|
│ ├── CONFIGURATION.md # Target app switching, routing fallback procedures
|
|
│ ├── AUTO_UPDATER.md # Release lifecycle, CI/CD, code signing
|
|
│ └── IPC_ARCHITECTURE.md # Security model, extensibility patterns
|
|
├── scripts/
|
|
│ └── copy-web-dist.ts # Prebuild bridge: syncs web build → web-dist/
|
|
├── src/
|
|
│ ├── main/
|
|
│ │ └── index.ts # Main process: protocol, CORS, IPC, updater
|
|
│ ├── preload/
|
|
│ │ └── index.ts # Secure contextBridge API surface
|
|
│ └── renderer/
|
|
│ └── index.html # Renderer shell
|
|
├── .env # Runtime configuration
|
|
├── electron-builder.yml # Packaging & auto-update provider config
|
|
├── electron-vite.config.ts # Three-target build config (main, preload, renderer)
|
|
├── package.json
|
|
├── tsconfig.json
|
|
├── tsconfig.main.json
|
|
├── tsconfig.preload.json
|
|
└── tsconfig.renderer.json
|
|
```
|
|
|
|
---
|
|
|
|
## Scripts
|
|
|
|
### Development & Build
|
|
|
|
| Script | Description |
|
|
|---|---|
|
|
| `pnpm dev` | Launch the electron-vite development server with live reload |
|
|
| `pnpm build` | Compile main, preload, and renderer TypeScript modules → `out/` |
|
|
| `pnpm prebuild` | Synchronize the target web app's build output via `scripts/copy-web-dist.ts` — copies `apps/<DESKTOP_TARGET_APP>/dist/` → `web-dist/`. Invoked automatically before `pnpm build`. |
|
|
| `pnpm preview` | Preview the compiled Electron app locally without generating a distributable |
|
|
|
|
### 🚀 Packaging & Distribution
|
|
|
|
To generate a production-ready installer, execute from **within `apps/desktop/`** or use the root-level `pnpm package:*` commands, which orchestrate the full pipeline automatically:
|
|
|
|
| Command | Platform | Output Artifact |
|
|
|---|---|---|
|
|
| `pnpm package` | Current OS | Detects host OS and builds accordingly |
|
|
| `pnpm package:mac` | macOS | `.dmg` and `.zip` (supports x64 & arm64) |
|
|
| `pnpm package:win` | Windows | `.exe` (NSIS Installer) |
|
|
| `pnpm package:linux` | Linux | `.AppImage` |
|
|
|
|
All artifacts are emitted to the `release/` directory.
|
|
|
|
> [!IMPORTANT]
|
|
> **Deterministic Build Pipeline**: All `package:*` commands strictly enforce a deterministic build pipeline: compiling web assets via Turborepo, synchronizing the output via the `prebuild` bridge (`node --import tsx scripts/copy-web-dist.ts`), and finally generating the native binary through `electron-builder`.
|
|
>
|
|
> **Running locally within `apps/desktop/`**: These scripts assume the web app has already been compiled. Either run `pnpm build --filter=web` beforehand, or use the root-level `pnpm package:*` commands which handle the complete orchestration.
|
|
|
|
> [!WARNING]
|
|
> **macOS Code Signing**: Distributable macOS builds with Auto-Update capability **require** an Apple Developer Certificate. Provide the following environment variables:
|
|
> ```bash
|
|
> CSC_LINK=<base64-encoded .p12 certificate>
|
|
> CSC_KEY_PASSWORD=<certificate password>
|
|
> APPLE_ID=<your apple id>
|
|
> APPLE_APP_SPECIFIC_PASSWORD=<app-specific password>
|
|
> APPLE_TEAM_ID=<team id>
|
|
> ```
|
|
> Without valid code signing, macOS Gatekeeper will quarantine the application and `electron-updater` will reject update payloads. See [docs/AUTO_UPDATER.md](docs/AUTO_UPDATER.md) for the complete requirements.
|
|
|
|
> [!NOTE]
|
|
> **Cross-Compilation Advisory**: It is strongly recommended to build for each platform on its native OS. Cross-compilation (e.g., producing `.dmg` on Linux) may fail due to platform-specific toolchain dependencies. For CI, leverage a matrix strategy:
|
|
> ```yaml
|
|
> strategy:
|
|
> matrix:
|
|
> os: [macos-latest, windows-latest, ubuntu-latest]
|
|
> runs-on: ${{ matrix.os }}
|
|
> ```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
The target web application is configured via `.env`:
|
|
|
|
```env
|
|
DESKTOP_TARGET_APP=web
|
|
DESKTOP_DEV_SERVER_URL=http://localhost:5173
|
|
```
|
|
|
|
See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for comprehensive guidance on target app switching, protocol internals, and the HashRouter fallback procedure.
|
|
|
|
---
|
|
|
|
## Core Capabilities
|
|
|
|
### 🌐 Custom `app://` Protocol
|
|
|
|
Provides a secure file-serving layer with built-in **Path Traversal Protection** and automated **CSP Header Injection**. All requests to unknown paths are intelligently rerouted to `index.html`, enabling React Router to resolve routes client-side without blank screens or 404 errors.
|
|
|
|
### 🖨️ Hardware Bridge
|
|
|
|
Enables granular control over system peripherals — such as printers — through an asynchronous IPC communication layer. The React app can enumerate connected printers and dispatch print jobs via `window.electronAPI.getPrinters()` and `window.electronAPI.print()`, all without exposing native APIs to the renderer.
|
|
|
|
### 🔄 Auto-Update Engine
|
|
|
|
A fully managed update lifecycle powered by `electron-updater`. Background download progress is forwarded in real-time to the React UI via IPC event subscriptions, enabling rich notification experiences. See [docs/AUTO_UPDATER.md](docs/AUTO_UPDATER.md).
|
|
|
|
### 🛡️ CORS Bypass Proxy
|
|
|
|
A transparent proxy mechanism that handles cross-origin requests by sanitizing non-standard `app://` and `file://` Origin headers on outgoing requests and injecting permissive CORS response headers on incoming responses — allowing seamless integration with cloud APIs without server-side configuration changes.
|
|
|
|
### 🔒 Single Instance Lock & Data Integrity
|
|
|
|
The application enforces a **single running instance** via `app.requestSingleInstanceLock()`. If a user attempts to launch a second instance, the duplicate process is terminated immediately and the existing window is restored and focused. This mechanism serves two critical purposes:
|
|
|
|
- **Data Integrity**: Prevents race conditions and write conflicts in local databases (IndexedDB/PouchDB) that could arise from concurrent access by multiple Electron processes.
|
|
- **Resource Efficiency**: Avoids duplicate memory allocation, IPC handler registration, and protocol handler conflicts.
|
|
|
|
---
|
|
|
|
## Hardened Security Perimeter
|
|
|
|
The Desktop Wrapper enforces a **hardened security perimeter**, strictly isolating the Node.js Main Process from the Renderer Context. Our architecture is built upon the principle of **Least Privilege**, ensuring that the web application only interacts with system hardware through a verified, secure IPC bridge.
|
|
|
|
| Setting | Value | Purpose |
|
|
|---|---|---|
|
|
| `contextIsolation` | `true` | Preload executes in a hermetically sealed JavaScript context |
|
|
| `nodeIntegration` | `false` | Zero Node.js API surface exposed to the renderer |
|
|
| `sandbox` | `true` | Chromium OS-level sandbox enforced |
|
|
| `webSecurity` | `true` | Same-origin policy strictly upheld |
|
|
|
|
**Defense-in-depth protections in `src/main/index.ts`**:
|
|
|
|
- **Path Traversal Guard** — The `app://` protocol handler validates all resolved file paths remain within the `web-dist/` boundary using `normalize()` + `startsWith()`. Traversal attempts like `app://-/../../etc/passwd` are met with `403 Forbidden`.
|
|
- **CSP Header Injection** — Content-Security-Policy headers are injected as HTTP response headers on every HTML response served by the custom protocol — not via a `<meta>` tag — ensuring they cannot be stripped or bypassed by injected scripts.
|
|
- **Origin Sanitization** — `session.defaultSession.webRequest` intercepts all outgoing requests, stripping `app://` / `file://` Origin headers to prevent backend CORS rejections.
|
|
- **Navigation Guard** — The `will-navigate` event intercepts and blocks all navigation attempts to URLs outside the `app://` protocol and the authorized dev server origin.
|
|
|
|
See [docs/IPC_ARCHITECTURE.md](docs/IPC_ARCHITECTURE.md) for the full security model, the Three-Step Bridge pattern, and guidance on safely extending the app with new native features.
|
|
|
|
---
|
|
|
|
## Documentation
|
|
|
|
| Document | Scope |
|
|
|---|---|
|
|
| [CONFIGURATION.md](docs/CONFIGURATION.md) | Target app switching, `app://` protocol internals, HashRouter fallback procedure |
|
|
| [AUTO_UPDATER.md](docs/AUTO_UPDATER.md) | Release lifecycle, CI/CD variables, provider switching, code signing |
|
|
| [IPC_ARCHITECTURE.md](docs/IPC_ARCHITECTURE.md) | Security model, Three-Step Bridge pattern, existing IPC channels, extensibility guide |
|