import { LazyStore } from '@tauri-apps/plugin-store'; import { writable, type Writable } from 'svelte/store'; // Spotify User interface export interface SpotifyUser { id: string; display_name: string; email?: string; country?: string; product?: string; // premium, free, etc. images?: Array<{ url: string }>; } // Spotify auth state export interface SpotifyAuthState { // Developer credentials clientId: string | null; clientSecret: string | null; // OAuth tokens accessToken: string | null; refreshToken: string | null; expiresAt: number | null; // Unix timestamp in milliseconds // User data user: SpotifyUser | null; loggedIn: boolean; cacheTimestamp: number | null; // Unix timestamp in seconds } // Initialize the store with spotify.json const store = new LazyStore('spotify.json'); // Default state const defaultState: SpotifyAuthState = { clientId: null, clientSecret: null, accessToken: null, refreshToken: null, expiresAt: null, user: null, loggedIn: false, cacheTimestamp: null }; // Create a writable store for reactive UI updates export const spotifyAuth: Writable = writable(defaultState); // Load Spotify auth state from store export async function loadSpotifyAuth(): Promise { const clientId = await store.get('clientId'); const clientSecret = await store.get('clientSecret'); const accessToken = await store.get('accessToken'); const refreshToken = await store.get('refreshToken'); const expiresAt = await store.get('expiresAt'); const user = await store.get('user'); const cacheTimestamp = await store.get('cacheTimestamp'); spotifyAuth.set({ clientId: clientId ?? null, clientSecret: clientSecret ?? null, accessToken: accessToken ?? null, refreshToken: refreshToken ?? null, expiresAt: expiresAt ?? null, user: user ?? null, loggedIn: !!(accessToken && user), cacheTimestamp: cacheTimestamp ?? null }); } // Save client credentials (developer app credentials) export async function saveClientCredentials(clientId: string, clientSecret: string): Promise { await store.set('clientId', clientId); await store.set('clientSecret', clientSecret); await store.save(); spotifyAuth.update(s => ({ ...s, clientId, clientSecret })); } // Save OAuth tokens export async function saveTokens(accessToken: string, refreshToken: string, expiresIn: number): Promise { const expiresAt = Date.now() + (expiresIn * 1000); await store.set('accessToken', accessToken); await store.set('refreshToken', refreshToken); await store.set('expiresAt', expiresAt); await store.save(); spotifyAuth.update(s => ({ ...s, accessToken, refreshToken, expiresAt })); } // Save user data export async function saveUser(user: SpotifyUser): Promise { await store.set('user', user); await store.save(); spotifyAuth.update(s => ({ ...s, user, loggedIn: true })); } // Clear auth (logout) export async function clearSpotifyAuth(): Promise { await store.delete('accessToken'); await store.delete('refreshToken'); await store.delete('expiresAt'); await store.delete('user'); await store.save(); spotifyAuth.update(s => ({ ...s, accessToken: null, refreshToken: null, expiresAt: null, user: null, loggedIn: false })); } // Check if token is expired or about to expire (within 5 minutes) export function isTokenExpired(expiresAt: number | null): boolean { if (!expiresAt) return true; const bufferTime = 5 * 60 * 1000; // 5 minutes in milliseconds return Date.now() >= (expiresAt - bufferTime); } // Save cache timestamp export async function saveCacheTimestamp(timestamp: number): Promise { await store.set('cacheTimestamp', timestamp); await store.save(); spotifyAuth.update(s => ({ ...s, cacheTimestamp: timestamp })); } // Initialize on module load loadSpotifyAuth();