feat: soundboard, account menu, and call timer
CI / Build & test (Node 20) (push) Canceled after 0s
CI / Build & test (Node 24) (push) Canceled after 0s
CI / Build & test (push) Canceled after 0s
CodeQL / Analyze (javascript-typescript) (push) Canceled after 0s
Security / Secret scan (gitleaks) (push) Canceled after 0s
Security / Dependency scan (OSV-Scanner) (push) Canceled after 0s
Security / IaC/config scan (Trivy) (push) Canceled after 0s
Security / License compliance scan (Trivy) (push) Canceled after 0s
OpenSSF Scorecard / Scorecard analysis (push) Canceled after 0s

Soundboard: the trigger travels over the WebSocket and every client in the
call plays the clip locally, instead of mixing it into the presser's
microphone or publishing a LiveKit track. No upstream bandwidth, no media
stack changes, and the clip is not degraded by voice processing.

Fan-out uses a new sendToRoomParticipants rather than sendToRoom: the latter
broadcasts a space room to the whole space, which is right for the presence
the sidebar shows and wrong for anything audible. The cooldown is enforced
server-side — a client-side one only slows down people not trying to abuse it,
and a soundboard is the easiest thing here to turn into a weapon. Playing is
open to anyone in the call; deciding what the buttons are needs MANAGE_SPACE.

Account menu: the name in the user bar had cursor-pointer and no handler, so
the interface was already promising a click that did nothing. Offers profile,
status and copy-id — not the Clips or account switching the reference design
shows, which would be dead UI here.

Call timer: startedAt comes from the server, so a late joiner sees the call's
age rather than their own arrival. Empty space rooms are destroyed already,
which is what makes the next call start from zero — no reset logic needed.
This commit is contained in:
2026-08-31 13:45:18 -03:00
parent ef5545465d
commit f5451e1b14
22 changed files with 5026 additions and 11 deletions
+2
View File
@@ -18,6 +18,7 @@ import { livekitRoutes } from './routes/livekit.js';
import { spotifyRoutes } from './routes/spotify.js';
import { auditRoutes } from './routes/audit.js';
import { statsRoutes } from './routes/stats.js';
import { soundboardRoutes } from './routes/soundboard.js';
import { closeOrphanedVoiceSessions } from './utils/voiceSessions.js';
import { socialRoutes } from './routes/social.js';
import { settingsRoutes } from './routes/settings.js';
@@ -137,6 +138,7 @@ async function main(): Promise<void> {
await app.register(spotifyRoutes);
await app.register(auditRoutes);
await app.register(statsRoutes);
await app.register(soundboardRoutes);
await app.register(socialRoutes);
await app.register(settingsRoutes);
await app.register(utilRoutes);