Files
Max Litruv Boonzaayer e058165830 feat: upgrade toolchain and soften sync recovery after network blips
Bump Vite 8, matrix-js-sdk, and related deps; fix immer/vanilla-extract imports for new majors. Replace blocking sync error dialog with background recovery on wake/offline, and disable Vite auto-open in dev. Add feature handoff documentation index.
2026-07-09 01:55:09 +10:00

103 lines
4.0 KiB
Markdown

# Local HTTP API — handoff
## Summary
Paarrot exposes a localhost HTTP API (port **33384**) so external tools — Stream Deck, scripts, macros — can control the running desktop app: mute/deafen, switch rooms, send messages, and read status. The Electron main process runs an Express server; actions are forwarded to the renderer via IPC and executed against the live Matrix client and call service.
## User-facing behavior
- API starts automatically when the Electron app launches (no user setting).
- Only binds to `127.0.0.1` — not reachable from the network.
- No authentication today; security relies on localhost-only binding.
## Architecture
```
External client (curl, Stream Deck, script)
→ GET/POST http://127.0.0.1:33384/...
→ electron/api-server.js (Express)
→ IPC to renderer (executeAction)
→ cinny/src/app/paarrot-api.ts (initPaarrotAPI)
→ Matrix client / CallService / router navigate
```
Navigation for room changes uses `setPaarrotNavigate()` registered from the React router in `ClientNonUIFeatures.tsx`.
## Key files
| Path | Role |
|------|------|
| `electron/api-server.js` | Express routes, IPC bridge to renderer |
| `electron/main.js` | Starts `PaarrotAPIServer` with the main window |
| `cinny/src/app/paarrot-api.ts` | Action handlers (mute, deafen, channel, message, status) |
| `cinny/src/app/pages/client/ClientNonUIFeatures.tsx` | Calls `initPaarrotAPI()` and `setPaarrotNavigate()` |
| `test-api.js` / `test-api.sh` | Smoke tests for endpoints |
| `paarrot-api.postman_collection.json` | Postman collection (generated) |
## Data model
No persistent storage. Actions read/write ephemeral app state (current room, call mute/deafen).
### IPC actions (renderer)
| Action | Params | Returns |
|--------|--------|---------|
| `get-status` | — | mute, deafen, currentRoom, connected, userId |
| `toggle-mute` / `set-mute` | `{ muted? }` | `{ muted }` |
| `toggle-deafen` / `set-deafen` | `{ deafened? }` | `{ deafened }` |
| `change-channel` | `{ roomId }` | navigation result |
| `get-channels` | — | room list |
| `send-message` | `{ roomId, message }` | send result |
| `send-message-current` | `{ message }` | send to active room |
| `get-current-room` | — | current room id |
## Dependencies
- `express`, `cors`, `body-parser` (Electron)
- `matrix-js-sdk` (renderer)
- Call feature: `getCallService()` from `features/call/useCall.ts`
## Integration points
- **Voice calls**: mute/deafen actions delegate to `CallService`
- **Stream Deck**: `streamdeck-plugin/` consumes this API
- **Room navigation**: uses `getHomeRoomPath`, `getDirectRoomPath`, `getSpaceRoomPath`
- **Space detection**: `isSpaceLikeRoom()` checks `im.paarrot.room.kind` and `m.forum` type
## Testing
### Manual
1. Start Paarrot desktop (`npm run dev` or built app).
2. `curl http://127.0.0.1:33384/health``{ "status": "ok" }`
3. `curl http://127.0.0.1:33384/status` while logged in.
4. Join a voice call; `POST /mute/toggle` and verify UI state.
5. `POST /channel` with a room id; verify navigation.
### Automated
- `node test-api.js` from repo root
## Known issues & gotchas
- Mute/deafen only work when `CallService` has an active call; otherwise handlers return a message, not an error.
- API is Electron-only; `initPaarrotAPI` no-ops when `window.electron.api` is missing (web/Tauri builds).
- Adding endpoints requires changes in **both** `api-server.js` and `paarrot-api.ts`.
## Future work
- Optional auth token for local API
- WebSocket or SSE for status push (Stream Deck polling today)
- Document all endpoints in Postman collection generator (`scripts/generate-postman-collection.js`)
## Related docs
- [API.md](../../API.md) — full endpoint reference
- [API-QUICKSTART.md](../../API-QUICKSTART.md)
- [streamdeck HANDOFF](../streamdeck/HANDOFF.md)
## Add your extra things here
- Default port: **33384** (`PaarrotAPIServer` constructor in `api-server.js`)
- `isSpaceLikeRoom` treats `forum_space` room kind and `m.forum` create type as spaces for channel listing