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.
4.0 KiB
4.0 KiB
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()fromfeatures/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()checksim.paarrot.room.kindandm.forumtype
Testing
Manual
- Start Paarrot desktop (
npm run devor built app). curl http://127.0.0.1:33384/health→{ "status": "ok" }curl http://127.0.0.1:33384/statuswhile logged in.- Join a voice call;
POST /mute/toggleand verify UI state. POST /channelwith a room id; verify navigation.
Automated
node test-api.jsfrom repo root
Known issues & gotchas
- Mute/deafen only work when
CallServicehas an active call; otherwise handlers return a message, not an error. - API is Electron-only;
initPaarrotAPIno-ops whenwindow.electron.apiis missing (web/Tauri builds). - Adding endpoints requires changes in both
api-server.jsandpaarrot-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 — full endpoint reference
- API-QUICKSTART.md
- streamdeck HANDOFF
Add your extra things here
- Default port: 33384 (
PaarrotAPIServerconstructor inapi-server.js) isSpaceLikeRoomtreatsforum_spaceroom kind andm.forumcreate type as spaces for channel listing