Files
scan-wave/src/lib/google/auth/manager.ts
2025-09-02 18:18:58 +02:00

148 lines
3.7 KiB
TypeScript

import { authenticateWithGoogle } from '$lib/google/auth/client.js';
export interface GoogleAuthState {
isConnected: boolean;
checking: boolean;
connecting: boolean;
showCancelOption: boolean;
token: string | null;
error: string | null;
userEmail: string | null;
}
export function createGoogleAuthState(): GoogleAuthState {
return {
isConnected: false,
checking: false,
connecting: false,
showCancelOption: false,
token: null,
error: null,
userEmail: null
};
}
export class GoogleAuthManager {
private readonly state: GoogleAuthState;
private cancelTimeout: ReturnType<typeof setTimeout> | null = null;
constructor(state: GoogleAuthState) {
this.state = state;
}
async checkConnection(): Promise<void> {
this.state.checking = true;
this.state.error = null;
try {
const token = localStorage.getItem('google_refresh_token');
const email = localStorage.getItem('google_user_email');
if (!token) {
this.state.isConnected = false;
this.state.token = null;
this.state.userEmail = null;
return;
}
// Verify the token by calling our backend endpoint
const response = await fetch('/private/api/google/auth/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refreshToken: token })
});
if (response.ok) {
this.state.isConnected = true;
this.state.token = token;
this.state.userEmail = email;
} else {
// Token is invalid or expired
await this.disconnectGoogle();
if (response.status === 401) {
this.state.error = 'Google session expired. Please reconnect.';
} else {
this.state.error = 'Failed to verify connection.';
}
}
} catch (error) {
console.error('Error checking connection:', error);
this.state.error = 'Failed to verify connection status';
this.state.isConnected = false;
} finally {
this.state.checking = false;
}
}
async connectToGoogle(): Promise<void> {
if (this.state.connecting) return;
this.state.connecting = true;
this.state.error = null;
this.state.showCancelOption = false;
// Show cancel option after 5 seconds
this.cancelTimeout = setTimeout(() => {
this.state.showCancelOption = true;
}, 5000);
try {
const result = await authenticateWithGoogle();
if (result.success && result.refreshToken) {
// Store tokens
localStorage.setItem('google_refresh_token', result.refreshToken);
if (result.userEmail) {
localStorage.setItem('google_user_email', result.userEmail);
}
// Update state
this.state.isConnected = true;
this.state.token = result.refreshToken;
this.state.userEmail = result.userEmail;
} else {
throw new Error(result.error ?? 'Authentication failed');
}
} catch (error) {
this.state.error = error instanceof Error ? error.message : 'Failed to connect to Google';
} finally {
this.state.connecting = false;
this.state.showCancelOption = false;
if (this.cancelTimeout) {
clearTimeout(this.cancelTimeout);
this.cancelTimeout = null;
}
}
}
cancelGoogleAuth(): void {
this.state.connecting = false;
this.state.showCancelOption = false;
this.state.error = null;
if (this.cancelTimeout) {
clearTimeout(this.cancelTimeout);
this.cancelTimeout = null;
}
}
async disconnectGoogle(): Promise<void> {
try {
// Clear local storage
localStorage.removeItem('google_refresh_token');
localStorage.removeItem('google_user_email');
// Reset state
this.state.isConnected = false;
this.state.token = null;
this.state.userEmail = null;
this.state.error = null;
} catch (error) {
console.error('Error disconnecting:', error);
this.state.error = 'Failed to disconnect';
}
}
}