feat(wip): add tauri-plugin-oauth and enable Spotify oauth

This commit is contained in:
2025-10-15 12:53:51 -04:00
parent 8d773f8188
commit 7f719bec11
10 changed files with 870 additions and 3 deletions

133
src/lib/stores/spotify.ts Normal file
View File

@@ -0,0 +1,133 @@
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;
}
// 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
};
// Create a writable store for reactive UI updates
export const spotifyAuth: Writable<SpotifyAuthState> = writable(defaultState);
// Load Spotify auth state from store
export async function loadSpotifyAuth(): Promise<void> {
const clientId = await store.get<string>('clientId');
const clientSecret = await store.get<string>('clientSecret');
const accessToken = await store.get<string>('accessToken');
const refreshToken = await store.get<string>('refreshToken');
const expiresAt = await store.get<number>('expiresAt');
const user = await store.get<SpotifyUser>('user');
spotifyAuth.set({
clientId: clientId ?? null,
clientSecret: clientSecret ?? null,
accessToken: accessToken ?? null,
refreshToken: refreshToken ?? null,
expiresAt: expiresAt ?? null,
user: user ?? null,
loggedIn: !!(accessToken && user)
});
}
// Save client credentials (developer app credentials)
export async function saveClientCredentials(clientId: string, clientSecret: string): Promise<void> {
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<void> {
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<void> {
await store.set('user', user);
await store.save();
spotifyAuth.update(s => ({
...s,
user,
loggedIn: true
}));
}
// Clear auth (logout)
export async function clearSpotifyAuth(): Promise<void> {
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);
}
// Initialize on module load
loadSpotifyAuth();