fix(frontend): refresh WS token after connection failures and handle AI/repo events
Clear wsToken on auth-related close codes (3000-4999), connection timeout, and after 3 consecutive reconnect failures so the next connect attempt fetches a fresh token. Add onRoomAiUpdated and onRepoChanged callbacks that re-fetch AI configs and repo list when pushed via WS. Fix AI member list to never display raw UUID.
This commit is contained in:
parent
c8eba28e7a
commit
a26551343c
@ -171,7 +171,7 @@ export const DiscordMemberList = memo(function DiscordMemberList({
|
||||
icon={<Bot className="h-3 w-3" />}
|
||||
>
|
||||
{aiConfigs.map((ai) => {
|
||||
const label = ai.modelName ?? ai.model;
|
||||
const label = ai.modelName || 'Unknown AI';
|
||||
return (
|
||||
<button
|
||||
key={ai.model}
|
||||
|
||||
@ -195,6 +195,8 @@ export function RoomProvider({
|
||||
const [wsClient, setWsClient] = useState<RoomWsClient | null>(null);
|
||||
const wsClientRef = useRef<RoomWsClient | null>(null);
|
||||
const activeRoomIdRef = useRef<string | null>(activeRoomId);
|
||||
const fetchRoomAiConfigsRef = useRef<() => Promise<void>>(async () => {});
|
||||
const fetchProjectReposRef = useRef<() => Promise<void>>(async () => {});
|
||||
const [wsStatus, setWsStatus] = useState<RoomWsStatus>('idle');
|
||||
const [wsError, setWsError] = useState<string | null>(null);
|
||||
const [wsToken, setWsToken] = useState<string | null>(null);
|
||||
@ -723,6 +725,14 @@ export function RoomProvider({
|
||||
if (payload.room_id !== activeRoomIdRef.current) return;
|
||||
setPins((prev) => prev.filter((p) => p.message !== payload.message_id));
|
||||
},
|
||||
onRoomAiUpdated: (payload) => {
|
||||
if (payload.room_id && payload.room_id === activeRoomIdRef.current) {
|
||||
fetchRoomAiConfigsRef.current();
|
||||
}
|
||||
},
|
||||
onRepoChanged: () => {
|
||||
fetchProjectReposRef.current();
|
||||
},
|
||||
onUserPresence: (payload) => {
|
||||
if (payload.room_id !== activeRoomIdRef.current) return;
|
||||
setPresence((prev) => ({ ...prev, [payload.user_id]: payload.status }));
|
||||
@ -1303,6 +1313,9 @@ export function RoomProvider({
|
||||
}
|
||||
}, [activeRoomId]);
|
||||
|
||||
useEffect(() => { fetchRoomAiConfigsRef.current = fetchRoomAiConfigs; }, [fetchRoomAiConfigs]);
|
||||
useEffect(() => { fetchProjectReposRef.current = fetchProjectRepos; }, [fetchProjectRepos]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProjectRepos();
|
||||
}, [fetchProjectRepos]);
|
||||
|
||||
@ -81,6 +81,8 @@ export interface RoomWsCallbacks {
|
||||
onUserPresence?: (payload: UserPresencePayload) => void;
|
||||
onTypingStart?: (payload: import('./ws-protocol').TypingStartPayload) => void;
|
||||
onTypingStop?: (payload: import('./ws-protocol').TypingStopPayload) => void;
|
||||
onRoomAiUpdated?: (payload: ProjectEventPayload) => void;
|
||||
onRepoChanged?: (payload: ProjectEventPayload) => void;
|
||||
onStatusChange?: (status: RoomWsStatus) => void;
|
||||
onError?: (error: Error) => void;
|
||||
/** Called each time the client sends a heartbeat ping */
|
||||
@ -212,7 +214,8 @@ export class RoomWsClient {
|
||||
// Safety timeout: if not open within 10s, give up
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (this.status === 'connecting') {
|
||||
console.error(`[RoomWs] Connection timeout after 10s — closing`);
|
||||
console.error(`[RoomWs] Connection timeout after 10s — clearing token and closing`);
|
||||
this.wsToken = null;
|
||||
this.ws?.close();
|
||||
this.setStatus('error');
|
||||
reject(new Error('Connection timeout'));
|
||||
@ -246,6 +249,10 @@ export class RoomWsClient {
|
||||
req.reject(new Error(`WebSocket closed: ${ev.reason || 'unknown'}`));
|
||||
}
|
||||
this.pendingRequests.clear();
|
||||
// Auth-related close codes (3000-4999) — clear token so reconnect fetches a fresh one
|
||||
if (ev.code >= 3000 && ev.code < 5000) {
|
||||
this.wsToken = null;
|
||||
}
|
||||
if (this.shouldReconnect) {
|
||||
this.scheduleReconnect();
|
||||
}
|
||||
@ -1130,6 +1137,14 @@ export class RoomWsClient {
|
||||
room_id: event.room_id ?? '',
|
||||
} as import('./ws-protocol').MessageUnpinnedPayload);
|
||||
break;
|
||||
case 'room_ai_updated':
|
||||
this.callbacks.onRoomAiUpdated?.(event);
|
||||
break;
|
||||
case 'repo_created':
|
||||
case 'repo_updated':
|
||||
case 'repo_deleted':
|
||||
this.callbacks.onRepoChanged?.(event);
|
||||
break;
|
||||
default:
|
||||
// Other project events (member_joined, room_created, etc.)
|
||||
this.callbacks.onProjectEvent?.(event);
|
||||
@ -1178,8 +1193,15 @@ export class RoomWsClient {
|
||||
const delay = Math.floor(jitter);
|
||||
this.reconnectAttempt++;
|
||||
|
||||
// After 3 consecutive failures, clear token so next connect fetches a fresh one
|
||||
const forceNew = this.reconnectAttempt >= 3;
|
||||
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.reconnectTimer = null;
|
||||
if (forceNew) {
|
||||
this.wsToken = null;
|
||||
console.debug('[RoomWs] Clearing token after 3 reconnect failures, will fetch fresh');
|
||||
}
|
||||
this.connect().catch(() => {});
|
||||
}, delay);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user