// js/accounts/auth.js import { auth } from './config.js'; export class AuthManager { constructor() { this.user = null; this.authListeners = []; this.init(); } async init() { const params = new URLSearchParams(window.location.search); const userId = params.get('userId'); const secret = params.get('secret'); const isOAuthRedirect = params.get('oauth') === '1'; if (userId && secret && userId !== 'null' && secret !== 'null') { try { await auth.createSession(userId, secret); window.history.replaceState({}, '', window.location.pathname); } catch (error) { console.warn('OAuth session handoff failed:', error.message); window.history.replaceState({}, '', window.location.pathname); } } else if (isOAuthRedirect) { await new Promise((resolve) => setTimeout(resolve, 500)); window.history.replaceState({}, '', window.location.pathname); } try { this.user = await auth.get(); this.updateUI(this.user); this.authListeners.forEach((listener) => listener(this.user)); } catch { this.user = null; this.updateUI(null); } } onAuthStateChanged(callback) { this.authListeners.push(callback); // If we already have a user state, trigger immediately if (this.user !== null) { callback(this.user); } } async signInWithGoogle() { try { auth.createOAuth2Session( 'google', window.location.origin + '/index.html?oauth=1', window.location.origin + '/login.html' ); } catch (error) { console.error('Login failed:', error); alert(`Login failed: ${error.message}`); } } async signInWithEmail(email, password) { try { await auth.createEmailPasswordSession(email, password); this.user = await auth.get(); this.updateUI(this.user); this.authListeners.forEach((listener) => listener(this.user)); return this.user; } catch (error) { console.error('Email Login failed:', error); alert(`Login failed: ${error.message}`); throw error; } } async signUpWithEmail(email, password) { try { await auth.create('unique()', email, password); await auth.createEmailPasswordSession(email, password); this.user = await auth.get(); this.updateUI(this.user); this.authListeners.forEach((listener) => listener(this.user)); return this.user; } catch (error) { console.error('Sign Up failed:', error); alert(`Sign Up failed: ${error.message}`); throw error; } } async sendPasswordReset(email) { try { await auth.createRecovery(email, window.location.origin + '/reset-password.html'); alert(`Password reset email sent to ${email}`); } catch (error) { console.error('Password reset failed:', error); alert(`Failed to send reset email: ${error.message}`); throw error; } } async signOut() { try { await auth.deleteSession('current'); this.user = null; this.updateUI(null); this.authListeners.forEach((listener) => listener(null)); if (window.__AUTH_GATE__) { window.location.href = '/login'; } else { window.location.reload(); } } catch (error) { console.error('Logout failed:', error); throw error; } } updateUI(user) { const connectBtn = document.getElementById('firebase-connect-btn'); const clearDataBtn = document.getElementById('firebase-clear-cloud-btn'); const statusText = document.getElementById('firebase-status'); const emailContainer = document.getElementById('email-auth-container'); const emailToggleBtn = document.getElementById('toggle-email-auth-btn'); if (!connectBtn) return; if (window.__AUTH_GATE__) { connectBtn.textContent = 'Sign Out'; connectBtn.classList.add('danger'); connectBtn.onclick = () => this.signOut(); if (clearDataBtn) clearDataBtn.style.display = 'none'; if (emailContainer) emailContainer.style.display = 'none'; if (emailToggleBtn) emailToggleBtn.style.display = 'none'; if (statusText) statusText.textContent = user ? `Signed in as ${user.email}` : 'Signed in'; const accountPage = document.getElementById('page-account'); if (accountPage) { const title = accountPage.querySelector('.section-title'); if (title) title.textContent = 'Account'; accountPage.querySelectorAll('.account-content > p, .account-content > div').forEach((el) => { if (el.id !== 'firebase-status' && el.id !== 'auth-buttons-container') { el.style.display = 'none'; } }); } const customDbBtn = document.getElementById('custom-db-btn'); if (customDbBtn) { const pbFromEnv = !!window.__POCKETBASE_URL__; if (pbFromEnv) { const settingItem = customDbBtn.closest('.setting-item'); if (settingItem) settingItem.style.display = 'none'; } } return; } if (user) { connectBtn.textContent = 'Sign Out'; connectBtn.classList.add('danger'); connectBtn.onclick = () => this.signOut(); if (clearDataBtn) clearDataBtn.style.display = 'block'; if (emailContainer) emailContainer.style.display = 'none'; if (emailToggleBtn) emailToggleBtn.style.display = 'none'; if (statusText) statusText.textContent = `Signed in as ${user.email}`; } else { connectBtn.textContent = 'Connect with Google'; connectBtn.classList.remove('danger'); connectBtn.onclick = () => this.signInWithGoogle(); if (clearDataBtn) clearDataBtn.style.display = 'none'; if (emailToggleBtn) emailToggleBtn.style.display = 'inline-block'; if (statusText) statusText.textContent = 'Sync your library across devices'; } } } export const authManager = new AuthManager();