PR #4 of the multi-device roadmap — desktop client groundwork. The shell compiles and runs end-to-end on top of a v2.2.0 node; sections are placeholders that later alphas fill in with real chat / feed / wallet / contacts / settings content shared with the mobile client-app. Scaffold: * Vite + React + TypeScript renderer; Electron main/preload TS compiled via a separate tsconfig. * npm scripts — `dev` (concurrent Vite + Electron), `build` (installer via electron-builder), `typecheck`. * electron-builder targets: .dmg / .exe / .AppImage + .deb. * CSP pins script-src 'self'; connect-src left open so the renderer can hit any configured node. Electron main + preload: * Frame-less window, hiddenInset on macOS, custom-overlay on Windows, drag region via CSS -webkit-app-region: drag on our TitleBar. * contextIsolation on, nodeIntegration off, sandbox off (needed for safeStorage in preload). * window.dchain.keyfile.{load,save,delete,encryptionAvailable} — keyfile lives in the OS keychain via Electron safeStorage, with a plaintext fallback for OSes without an encryption backend. * window.dchain.dialog.{openFile,saveFile}, .fs.{readText,writeText}, .app.{version,platform}. Everything else still goes over plain fetch() in the renderer. Shell (src/shell/): * TitleBar — draggable 32px strip; DChain brand. * NavBar — left 72px rail, six sections + Cmd+1..5 keybinds. * StatusBar — ● online/connecting/offline dot, node URL, current chain height (polls /api/netstats every 5s). * Shell — composes the 3 panes; picks { List, Detail } by active section. Sections (all stubs — filling in alpha5+): * Messages, Feed, Contacts, Profile — SectionPlaceholder with notes. * Wallet — shows the balance reading from /api/address/{pub} as a first real data binding. * Settings — node-URL card with live ping + commit, identity card (shows pub key), about card (reads Electron app.version via IPC). Auth (src/auth/Welcome.tsx): * Create — generates Ed25519 + X25519 via tweetnacl, saves via IPC. * Import — Electron dialog.openFile → parses node.json → saves. * Pair — stub routed; real poll loop reuses the mobile flow in alpha5. Lib (src/lib/): * types.ts — KeyFile / Contact / Message / NodeSettings mirroring client-app wire formats. * storage.ts — keyfile via IPC, settings + contacts + device-registered marker via localStorage. * api.ts — fetch wrapper with setNodeUrl + onNodeUrlChange; getNetStats, getIdentity, fetchDevices, getBalance bindings. * store.ts — zustand { booted, keyFile, settings, contacts, section }. docs/ROADMAP.md — desktop subsection updated with per-alpha breakdown. Next (alpha5): Messages section wired to the relay mailbox, full conversation view, and the pairing poll loop.
77 lines
3.3 KiB
Markdown
77 lines
3.3 KiB
Markdown
# DChain Desktop
|
|
|
|
Electron shell for the DChain messenger and social feed.
|
|
|
|
Same functionality as the mobile client-app, re-imagined with a
|
|
keyboard-first, 3-panel desktop layout:
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ DChain │ titlebar (drag)
|
|
├──────┬───────────────────┬────────────────────────────────┤
|
|
│ nav │ list │ detail │
|
|
│ 72px │ 340px fixed │ flex 1 │
|
|
├──────┴───────────────────┴────────────────────────────────┤
|
|
│ ● online · node.example:8080 · height 10942 │ status bar
|
|
└──────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Sections (left rail): **Messages · Feed · Wallet · Contacts · Settings · Profile**.
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
cd desktop
|
|
npm install
|
|
npm run dev # concurrently: Vite dev server + Electron
|
|
```
|
|
|
|
The first boot will show the Welcome screen. Pick Create to generate
|
|
fresh keys, or Import a `node.json` exported from the mobile client.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
npm run build # produces dist/ (renderer) + dist-electron/ (main) + installers
|
|
```
|
|
|
|
Default installers are built with `electron-builder`: `.dmg` on macOS,
|
|
NSIS `.exe` on Windows, AppImage + `.deb` on Linux. Adjust `build.*` in
|
|
`package.json` for signing / notarisation.
|
|
|
|
## Layout
|
|
|
|
- `electron/` — main + preload. TypeScript, compiled to `dist-electron/`
|
|
by `tsc -p electron/tsconfig.json`.
|
|
- `src/` — renderer. React + Vite. `@/` aliases to `src/`.
|
|
- `src/shell/` — 3-panel chrome.
|
|
- `src/sections/` — one folder per nav section, each exports `{ List, Detail }`.
|
|
- `src/auth/Welcome.tsx` — shown when no key is loaded.
|
|
- `src/lib/` — api, storage, store, types. Mirrors (without React-Native
|
|
deps) the relevant pieces of `../client-app/lib/`.
|
|
|
|
## Security model
|
|
|
|
Master Ed25519 priv lives in the OS keychain via Electron `safeStorage`
|
|
(macOS Keychain / Windows DPAPI / libsecret). A renderer compromise
|
|
cannot read or exfiltrate the key — it always travels through
|
|
`window.dchain.keyfile.*` IPC, which main.ts validates and mediates.
|
|
|
|
`contextIsolation: true`, `nodeIntegration: false`. CSP in `index.html`
|
|
pins script sources to `'self'` while allowing `connect-src *` so the
|
|
renderer can hit any node the user configures.
|
|
|
|
## Pairing (v2.2.0-alpha5+)
|
|
|
|
Desktop will reuse the same 6-digit-code + relay-envelope handshake as
|
|
the mobile client. The scaffold in `src/auth/Welcome.tsx` stubs the
|
|
button until the polling loop lands.
|
|
|
|
## Multi-device fan-out
|
|
|
|
When the node is at v2.2.0-alpha1+, `lib/api.ts:fetchDevices` returns
|
|
every linked X25519 pub for a given identity; the sender then encrypts
|
|
one envelope per device. Legacy nodes return an empty array and the
|
|
client falls back to `IdentityInfo.x25519_pub`, preserving the
|
|
pre-multi-device behaviour.
|