UNPKG

nuxt-supabase-team-auth

Version:

Drop-in Nuxt 3 module for team-based authentication with Supabase

105 lines (104 loc) 2.94 kB
import { ref, readonly } from "vue"; import { useSupabaseClient } from "./useSupabaseComposables.js"; const sessionCache = ref(null); const sessionPromise = ref(null); const lastFetch = ref(0); const CACHE_DURATION = 3e4; let cachedClient = null; let authListener = null; function getClient() { if (!cachedClient) { cachedClient = useSupabaseClient(); if (!cachedClient) { throw new Error("Supabase client not available - check your Supabase setup"); } } return cachedClient; } function setupAuthListener() { if (authListener || !import.meta.client) return; try { const client = getClient(); authListener = client.auth.onAuthStateChange((event, session) => { if (event === "SIGNED_IN" || event === "SIGNED_OUT" || event === "TOKEN_REFRESHED") { sessionCache.value = session; lastFetch.value = Date.now(); } }); } catch { console.debug("Auth listener setup deferred - client not ready"); } } export function useSession() { const getSession = async (force = false) => { if (!authListener && import.meta.client) { setupAuthListener(); } const now = Date.now(); if (!force && sessionCache.value && now - lastFetch.value < CACHE_DURATION) { return sessionCache.value; } if (sessionPromise.value) { return await sessionPromise.value; } sessionPromise.value = fetchSession(); try { const result = await sessionPromise.value; return result; } finally { sessionPromise.value = null; } }; const fetchSession = async () => { try { const { data: { session }, error } = await getClient().auth.getSession(); if (error) { console.warn("Session fetch error:", error); return null; } sessionCache.value = session; lastFetch.value = Date.now(); return session; } catch (error) { console.error("Failed to fetch session:", error); return null; } }; const clearSession = () => { sessionCache.value = null; lastFetch.value = 0; sessionPromise.value = null; }; const invalidateSession = async () => { clearSession(); return await getSession(true); }; const getCachedSession = () => sessionCache.value; const hasCachedSession = () => { const now = Date.now(); return sessionCache.value && now - lastFetch.value < CACHE_DURATION; }; return { getSession, clearSession, invalidateSession, getCachedSession, hasCachedSession, // Expose readonly cache for reactive use sessionCache: readonly(sessionCache) }; } export function resetSessionState() { sessionCache.value = null; sessionPromise.value = null; lastFetch.value = 0; cachedClient = null; if (authListener) { if (typeof authListener === "function") { authListener(); } else if (authListener?.unsubscribe) { authListener.unsubscribe(); } authListener = null; } }