diff --git a/client/package.json b/client/package.json index db73454..bf19e6c 100644 --- a/client/package.json +++ b/client/package.json @@ -35,10 +35,9 @@ "test": "react-scripts test", "eject": "react-scripts eject", "type-check": "tsc --noEmit", - "generate-schema": "cd ../server && python3 generate_schema_simple.py", "generate-types": "npx openapi-typescript openapi-schema.json -o src/api-types.ts", "update-api-client": "node update-api-client.js", - "generate-api-types": "npm run generate-schema && npm run generate-types && npm run update-api-client", + "generate-api-types": "npm run generate-types && npm run update-api-client", "check-api-evolution": "node check-api-evolution.js", "test-dynamic-paths": "node test-dynamic-paths.js", "prebuild": "npm run generate-api-types" diff --git a/client/src/App.tsx b/client/src/App.tsx index 56d278a..7bcc43b 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -30,6 +30,7 @@ const LobbyView: React.FC = (props: LobbyProps) => { const [socketUrl, setSocketUrl] = useState(null); const [creatingLobby, setCreatingLobby] = useState(false); const [reconnectAttempt, setReconnectAttempt] = useState(0); + const [shouldRetryLobby, setShouldRetryLobby] = useState(false); // Check if lobbyName looks like a lobby ID (32 hex characters) and redirect to default useEffect(() => { @@ -112,6 +113,15 @@ const LobbyView: React.FC = (props: LobbyProps) => { console.log("app - WebSocket connection status: ", readyState); }, [readyState]); + // Retry lobby creation when session is restored after a failure + useEffect(() => { + if (session && shouldRetryLobby && !lobby && !creatingLobby) { + console.log("Lobby - Session restored, retrying lobby creation"); + setShouldRetryLobby(false); + // The main lobby creation effect will trigger automatically due to session change + } + }, [session, shouldRetryLobby, lobby, creatingLobby]); + useEffect(() => { if (!session || !lobbyName || creatingLobby || (lobby && lobby.name === lobbyName)) { return; @@ -148,6 +158,15 @@ const LobbyView: React.FC = (props: LobbyProps) => { const errorMessage = err instanceof Error ? err.message : "Failed to create/join lobby"; console.error("Lobby creation error:", errorMessage); setError(errorMessage); + + // If it's a server error (5xx), mark for retry when session is restored + if ( + err instanceof Error && + (err.message.includes("502") || err.message.includes("503") || err.message.includes("500")) + ) { + console.log("Lobby - Server error detected, will retry when session is restored"); + setShouldRetryLobby(true); + } } }; @@ -156,7 +175,6 @@ const LobbyView: React.FC = (props: LobbyProps) => { setCreatingLobby(false); }); }, [session, lobbyName, lobby, setLobby, setError]); - const setName = (name: string) => { sendJsonMessage({ type: "set_name", diff --git a/client/src/UserList.tsx b/client/src/UserList.tsx index ff32595..82e4b65 100644 --- a/client/src/UserList.tsx +++ b/client/src/UserList.tsx @@ -178,14 +178,15 @@ const UserList: React.FC = (props: UserListProps) => { /> ) : user.name && user.live && user.has_media === false ? (
diff --git a/client/src/api-client.ts b/client/src/api-client.ts index c4859b7..667b59d 100644 --- a/client/src/api-client.ts +++ b/client/src/api-client.ts @@ -128,10 +128,16 @@ export class ApiClient { if (!response.ok) { let errorData; + // Clone the response before trying to read it, in case JSON parsing fails + const responseClone = response.clone(); try { errorData = await response.json(); } catch { - errorData = await response.text(); + try { + errorData = await responseClone.text(); + } catch { + errorData = `HTTP ${response.status}: ${response.statusText}`; + } } throw new ApiError(response.status, response.statusText, errorData); }