import { getLoginUrl } from "@/const"; import { trpc } from "@/lib/trpc"; import { TRPCClientError } from "@trpc/client"; import { useCallback, useEffect, useMemo } from "react"; const ACCESS_KEY_STORAGE = "access_key_verified"; // Mock user for access key authentication (no cookies needed) // ID must match DEMO_USER_ID in importTestSamples.ts const ACCESS_KEY_USER = { id: 1, name: "Demo User", email: "demo@aimusic.attribution", }; type UseAuthOptions = { redirectOnUnauthenticated?: boolean; redirectPath?: string; }; export function useAuth(options?: UseAuthOptions) { const { redirectOnUnauthenticated = false, redirectPath = getLoginUrl() } = options ?? {}; const utils = trpc.useUtils(); // Check if access key is verified (works in Safari iframe, no cookies needed) const accessKeyVerified = typeof window !== "undefined" && sessionStorage.getItem(ACCESS_KEY_STORAGE) === "true"; const meQuery = trpc.auth.me.useQuery(undefined, { retry: false, refetchOnWindowFocus: false, // Skip query if access key is verified - we don't need cookie auth enabled: !accessKeyVerified, }); const logoutMutation = trpc.auth.logout.useMutation({ onSuccess: () => { utils.auth.me.setData(undefined, null); }, }); const logout = useCallback(async () => { try { await logoutMutation.mutateAsync(); } catch (error: unknown) { if ( error instanceof TRPCClientError && error.data?.code === "UNAUTHORIZED" ) { return; } throw error; } finally { // Also clear access key on logout sessionStorage.removeItem(ACCESS_KEY_STORAGE); utils.auth.me.setData(undefined, null); await utils.auth.me.invalidate(); } }, [logoutMutation, utils]); const state = useMemo(() => { // If access key is verified, use mock user (no cookies needed - Safari iframe fix) const effectiveUser = accessKeyVerified ? ACCESS_KEY_USER : meQuery.data; localStorage.setItem( "manus-runtime-user-info", JSON.stringify(effectiveUser) ); return { user: effectiveUser ?? null, loading: !accessKeyVerified && (meQuery.isLoading || logoutMutation.isPending), error: meQuery.error ?? logoutMutation.error ?? null, isAuthenticated: Boolean(effectiveUser), }; }, [ accessKeyVerified, meQuery.data, meQuery.error, meQuery.isLoading, logoutMutation.error, logoutMutation.isPending, ]); useEffect(() => { if (!redirectOnUnauthenticated) return; if (meQuery.isLoading || logoutMutation.isPending) return; if (state.user) return; if (typeof window === "undefined") return; if (window.location.pathname === redirectPath) return; window.location.href = redirectPath }, [ redirectOnUnauthenticated, redirectPath, logoutMutation.isPending, meQuery.isLoading, state.user, ]); return { ...state, refresh: () => meQuery.refetch(), logout, }; }