using System; using System.Threading.Tasks; using Newtonsoft.Json; using Supabase; using UnityEngine; using UnityEngine.Events; public class SupabaseManager : MonoBehaviour { public Client Supa; public SupabaseConfig supabaseConfig; [Header("Supabase Auth Events")] public UnityEvent OnSessionRestored; public UnityEvent OnSessionMissing; public UnityEvent OnSessionInvalid; public UnityEvent OnOtpSent; public UnityEvent OnOtpSendFailed; public UnityEvent OnOtpVerified; public UnityEvent OnOtpVerifyFailed; public UnityEvent OnSessionExpired; public UnityEvent OnLoggedOut; public bool KeepTempSession = true; private void Start() { DontDestroyOnLoad(gameObject); #if UNITY_WEBGL && !UNITY_EDITOR InitWebGL(); #else InitNative(); #endif } #if UNITY_WEBGL && !UNITY_EDITOR private void InitWebGL() { SupabaseWebGLWrapper.Supabase_Init( supabaseConfig.projectUrl, supabaseConfig.anonPublicKey ); SupabaseWebGLWrapper.Supabase_RestoreSession(); } #else private async void InitNative() { var options = new SupabaseOptions { AutoConnectRealtime = false, AutoRefreshToken = true, SessionHandler = new UnitySupabaseSessionHandler() }; Supa = new Client( supabaseConfig.projectUrl, supabaseConfig.anonPublicKey, options ); await Supa.InitializeAsync(); Supa.Auth.LoadSession(); await Task.Yield(); var session = await Supa.Auth.RetrieveSessionAsync(); if (session == null) { Debug.LogError("[Supabase] No active session."); OnSessionExpired?.Invoke(); } else { Debug.LogError("[Supabase] Session restored."); OnSessionRestored?.Invoke(); Debug.LogError("Access Token Expires At (UTC): " + session.ExpiresAt()); Debug.LogError("Access Token Expires At (IST): " + session.ExpiresAt().ToLocalTime()); Debug.LogError("Access Token Expires At (IST): " + session.RefreshToken); Debug.LogError("Refresh Token: " + session.RefreshToken); } } #endif public void SendOtp(string email) { #if UNITY_WEBGL && !UNITY_EDITOR Debug.Log("[Supabase] WebGL SendOtp()"); SupabaseWebGLWrapper.Supabase_SendOtp(email); #else Debug.Log("[Supabase] Native SendOtp()"); SendEmailOtp(email); #endif } public void VerifyOtp(string email, string code) { #if UNITY_WEBGL && !UNITY_EDITOR Debug.Log("[Supabase] WebGL VerifyOtp()"); SupabaseWebGLWrapper.Supabase_VerifyOtp(email, code); #else Debug.Log("[Supabase] Native VerifyOtp()"); VerifyEmailOtp(email, code); #endif } public void AutoLogin() { #if UNITY_WEBGL && !UNITY_EDITOR SupabaseWebGLWrapper.Supabase_RestoreSession(); #else LoginWithToken(); #endif } public void Logout() { #if UNITY_WEBGL && !UNITY_EDITOR SupabaseWebGLWrapper.Supabase_Logout(); #else SignOut(); #endif } public void WebGL_OtpSent() { Debug.Log("[Supabase/WebGL] OTP sent"); OnOtpSent?.Invoke(); } public void WebGL_OtpSendFailed(string error) { Debug.LogError("[Supabase/WebGL] OTP send failed: " + error); OnOtpSendFailed?.Invoke(); } public void WebGL_OtpVerified(string json) { Debug.Log("[Supabase/WebGL] OTP verified"); var data = JsonConvert.DeserializeObject(json); PlayerPrefs.SetString("sb_access_token", data.access_token); PlayerPrefs.SetString("sb_refresh_token", data.refresh_token); PlayerPrefs.SetString("sb_email", data.email); PlayerPrefs.Save(); OnOtpVerified?.Invoke(); } public void WebGL_OtpVerifyFailed(string error) { Debug.LogError("[Supabase/WebGL] OTP verify failed: " + error); OnOtpVerifyFailed?.Invoke(); } public void WebGL_SessionRestored(string json) { Debug.Log("[Supabase/WebGL] Session restored"); var data = JsonConvert.DeserializeObject(json); PlayerPrefs.SetString("sb_access_token", data.access_token); PlayerPrefs.SetString("sb_refresh_token", data.refresh_token); PlayerPrefs.SetString("sb_email", data.email); PlayerPrefs.Save(); OnSessionRestored?.Invoke(); } public void WebGL_NoSession() { Debug.Log("[Supabase/WebGL] Session invalid or missing."); PlayerPrefs.DeleteKey("sb_access_token"); PlayerPrefs.DeleteKey("sb_refresh_token"); PlayerPrefs.DeleteKey("sb_email"); PlayerPrefs.Save(); OnSessionInvalid?.Invoke(); OnSessionMissing?.Invoke(); } public void WebGL_LoggedOut() { PlayerPrefs.DeleteKey("sb_access_token"); PlayerPrefs.DeleteKey("sb_refresh_token"); PlayerPrefs.DeleteKey("sb_email"); PlayerPrefs.Save(); OnLoggedOut?.Invoke(); } public async void SendEmailOtp(string email, Action onSuccess = null, Action onError = null) { try { var opts = new Supabase.Gotrue.SignInWithPasswordlessEmailOptions(email) { ShouldCreateUser = true }; await Supa.Auth.SignInWithOtp(opts); onSuccess?.Invoke(); OnOtpSent?.Invoke(); } catch (Exception ex) { OnOtpSendFailed?.Invoke(); onError?.Invoke(ex); } } public async void VerifySession() { } public async void VerifyEmailOtp(string email, string code) { try { var session = await Supa.Auth.VerifyOTP( email, code, Supabase.Gotrue.Constants.EmailOtpType.Email ); await Supa.Auth.SetSession( session.AccessToken, session.RefreshToken, true ); OnOtpVerified?.Invoke(); } catch (Exception ex) { Debug.LogError(ex); OnOtpVerifyFailed?.Invoke(); } } public async void LoginWithToken() { var session = await Supa.Auth.RetrieveSessionAsync(); if (session == null) { OnSessionExpired?.Invoke(); return; } OnSessionRestored?.Invoke(); } public async void SignOut() { await Supa.Auth.SignOut(); OnLoggedOut?.Invoke(); } } [Serializable] public class WebGLSession { public string access_token; public string refresh_token; public long expires_at; public string email; }