From e29fabc3f14782dce335f7eb86c42ee5e714c465 Mon Sep 17 00:00:00 2001 From: Kartikeya <176560021+karti-ai@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:13:31 -0700 Subject: [PATCH] fix(livekit): stable identity + room auto-cleanup Use the member name as the LiveKit identity (was random per join) so a refresh/rejoin replaces the existing session instead of leaving a ghost participant in the room. Set roomConfig on the token (emptyTimeout 60s, departureTimeout 20s) so empty rooms and departed participants clean up promptly. Pods map 1:1 to a deterministic room name, so joins reuse the same room rather than spawning new ones. Co-Authored-By: Claude Opus 4.8 --- backend/src/server.ts | 5 ++++- frontend/src/App.tsx | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/server.ts b/backend/src/server.ts index a594b6a..60d77de 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -2,7 +2,7 @@ import express from 'express'; import cors from 'cors'; import { createServer } from 'node:http'; import { WebSocketServer } from 'ws'; -import { AccessToken } from 'livekit-server-sdk'; +import { AccessToken, RoomConfiguration } from 'livekit-server-sdk'; import { env } from './env.js'; import { createSyncPr } from './github/client.js'; import { recordOutcome, memoryStats } from './memory/store.js'; @@ -36,6 +36,9 @@ app.post('/api/token', async (req, res) => { metadata: JSON.stringify({ githubLogin: githubLogin ?? name }), }); at.addGrant({ roomJoin: true, room, canPublish: true, canSubscribe: true, canPublishData: true }); + // Auto-clean the room: close 60s after it empties, drop a participant 20s + // after they disconnect. Applied when LiveKit auto-creates the room. + at.roomConfig = new RoomConfiguration({ name: room, emptyTimeout: 60, departureTimeout: 20 }); res.json({ token: await at.toJwt(), url: env.LIVEKIT_URL }); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a7e2859..d5e3622 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -47,7 +47,9 @@ export default function App() { // Connect to a pod's LiveKit room and persist the session for refresh-resume. async function connectToPod(podId: string, who: string) { - const identity = `${who}-${Math.random().toString(36).slice(2, 7)}`; + // Stable identity per member so a refresh/rejoin replaces the existing + // session instead of leaving a ghost participant behind. + const identity = who; const result = await joinPod(podId, identity, who); setRoom(result.room); setDevMode(result.mode === 'dev');