diff --git a/www/app/[roomName]/components/DailyRoom.tsx b/www/app/[roomName]/components/DailyRoom.tsx index 2faedb90..41105be3 100644 --- a/www/app/[roomName]/components/DailyRoom.tsx +++ b/www/app/[roomName]/components/DailyRoom.tsx @@ -11,6 +11,7 @@ import { recordingTypeRequiresConsent, } from "../../lib/consent"; import { useRoomJoinMeeting } from "../../lib/apiHooks"; +import { assertExists } from "../../lib/utils"; type Meeting = components["schemas"]["Meeting"]; @@ -22,16 +23,16 @@ export default function DailyRoom({ meeting }: DailyRoomProps) { const router = useRouter(); const params = useParams(); const auth = useAuth(); - const status = auth.status; + const authStatus = auth.status; + const authLastUserId = auth.lastUserId; const containerRef = useRef(null); const joinMutation = useRoomJoinMeeting(); const [joinedMeeting, setJoinedMeeting] = useState(null); const roomName = params?.roomName as string; - // Always call /join to get a fresh token with user_id useEffect(() => { - if (status === "loading" || !meeting?.id || !roomName) return; + if (authLastUserId === null || !meeting?.id || !roomName) return; const join = async () => { try { @@ -50,18 +51,16 @@ export default function DailyRoom({ meeting }: DailyRoomProps) { }; join(); - }, [meeting?.id, roomName, status]); + }, [meeting?.id, roomName, authLastUserId]); const roomUrl = joinedMeeting?.host_room_url || joinedMeeting?.room_url; - const isLoading = - status === "loading" || joinMutation.isPending || !joinedMeeting; const handleLeave = useCallback(() => { router.push("/browse"); }, [router]); useEffect(() => { - if (isLoading || !roomUrl || !containerRef.current) return; + if (!authLastUserId || !roomUrl || !containerRef.current) return; let frame: DailyCall | null = null; let destroyed = false; @@ -90,9 +89,14 @@ export default function DailyRoom({ meeting }: DailyRoomProps) { frame.on("left-meeting", handleLeave); + // TODO this method must not ignore no-recording option + // TODO this method is here to make dev environments work in some cases (not examined which) frame.on("joined-meeting", async () => { try { - await frame.startRecording({ type: "raw-tracks" }); + assertExists( + frame, + "frame object got lost somewhere after frame.on was called", + ).startRecording({ type: "raw-tracks" }); } catch (error) { console.error("Failed to start recording:", error); } @@ -104,7 +108,9 @@ export default function DailyRoom({ meeting }: DailyRoomProps) { } }; - createAndJoin(); + createAndJoin().catch((error) => { + console.error("Failed to create and join meeting:", error); + }); return () => { destroyed = true; @@ -114,9 +120,9 @@ export default function DailyRoom({ meeting }: DailyRoomProps) { }); } }; - }, [roomUrl, isLoading, handleLeave]); + }, [roomUrl, authLastUserId, handleLeave]); - if (isLoading) { + if (!authLastUserId) { return (
diff --git a/www/app/lib/AuthProvider.tsx b/www/app/lib/AuthProvider.tsx index e1eabf99..6a0b9f82 100644 --- a/www/app/lib/AuthProvider.tsx +++ b/www/app/lib/AuthProvider.tsx @@ -1,6 +1,6 @@ "use client"; -import { createContext, useContext } from "react"; +import { createContext, useContext, useRef } from "react"; import { useSession as useNextAuthSession } from "next-auth/react"; import { signOut, signIn } from "next-auth/react"; import { configureApiAuth } from "./apiClient"; @@ -25,6 +25,8 @@ type AuthContextType = ( update: () => Promise; signIn: typeof signIn; signOut: typeof signOut; + // TODO probably rename isLoading to isReloading and make THIS field "isLoading" + lastUserId: CustomSession["user"]["id"] | null; }; const AuthContext = createContext(undefined); @@ -41,10 +43,13 @@ const noopAuthContext: AuthContextType = { signOut: async () => { throw new Error("signOut not supposed to be called"); }, + lastUserId: null, }; export function AuthProvider({ children }: { children: React.ReactNode }) { const { data: session, status, update } = useNextAuthSession(); + // referential comparison done in component, must be primitive /or cached + const lastUserId = useRef(null); const contextValue: AuthContextType = isAuthEnabled ? { @@ -78,6 +83,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { status: "unauthenticated" as const, }; } else if (customSession?.accessToken) { + // updates anyways with updated properties below + // warning! execution order conscience, must be ran before reading lastUserId.current below + lastUserId.current = customSession.user.id; return { status, accessToken: customSession.accessToken, @@ -103,6 +111,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { update, signIn, signOut, + // for optimistic cases when we assume "loading" doesn't immediately invalidate the user + lastUserId: lastUserId.current, } : noopAuthContext; diff --git a/www/app/lib/authBackend.ts b/www/app/lib/authBackend.ts index c28ee224..e439e1b0 100644 --- a/www/app/lib/authBackend.ts +++ b/www/app/lib/authBackend.ts @@ -148,7 +148,7 @@ export const authOptions = (): AuthOptions => }, async session({ session, token }) { const extendedToken = token as JWTWithAccessToken; - + console.log("extendedToken", extendedToken); const userId = await getUserId(extendedToken.accessToken); return {