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.
This commit is contained in:
102
docs/handoff/features/local-api/HANDOFF.md
Normal file
102
docs/handoff/features/local-api/HANDOFF.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user