diff --git a/web/src/lib/auth/store.svelte.ts b/web/src/lib/auth/store.svelte.ts index 8ca24e02..005c6026 100644 --- a/web/src/lib/auth/store.svelte.ts +++ b/web/src/lib/auth/store.svelte.ts @@ -2,26 +2,23 @@ import { api, type User, type LoginResponse } from '$lib/api/client'; import { queryClient } from '$lib/query/client'; import { clearPersistedQueue } from '$lib/player/persisted'; import { playQueue, closeQueueDrawer } from '$lib/player/store.svelte'; +import { user, setUser } from './user.svelte'; -let _user = $state(null); - -export const user = { - get value(): User | null { - return _user; - } -}; +// Re-export so existing `import { user } from '$lib/auth/store.svelte'` +// callers keep working. New code can import directly from auth/user.svelte. +export { user }; export async function bootstrap(): Promise { try { - _user = await api.get('/api/me'); + setUser(await api.get('/api/me')); } catch { - _user = null; + setUser(null); } } export async function login(username: string, password: string): Promise { const res = await api.post('/api/auth/login', { username, password }); - _user = res.user; + setUser(res.user); } export async function register(opts: { @@ -37,7 +34,7 @@ export async function register(opts: { if (opts.inviteToken) body.invite_token = opts.inviteToken; if (opts.displayName) body.display_name = opts.displayName; const res = await api.post('/api/auth/register', body); - _user = res.user; + setUser(res.user); await bootstrap(); } @@ -50,7 +47,7 @@ export async function resetPassword(token: string, newPassword: string): Promise } export async function logout(opts: { silent?: boolean } = {}): Promise { - const userId = _user?.id; + const userId = user.value?.id; if (!opts.silent) { try { await api.post('/api/auth/logout', {}); @@ -58,7 +55,7 @@ export async function logout(opts: { silent?: boolean } = {}): Promise { // best effort — server-side session may already be gone } } - _user = null; + setUser(null); queryClient.clear(); // M7 #364: clear queue persistence + reset in-memory queue + close drawer // so a subsequent login doesn't inherit the previous user's playback state. diff --git a/web/src/lib/auth/user.svelte.ts b/web/src/lib/auth/user.svelte.ts new file mode 100644 index 00000000..6918f11b --- /dev/null +++ b/web/src/lib/auth/user.svelte.ts @@ -0,0 +1,19 @@ +// User state lives here so auth/store and player/store can share it +// without a circular import. auth/store mutates via setUser; player/store +// reads only. Both auth-flow consumers (login/register/logout) and any +// component that needs the current user can import `user` from either +// this module or auth/store — auth/store re-exports it for backward +// compatibility. +import type { User } from '$lib/api/client'; + +let _user = $state(null); + +export const user = { + get value(): User | null { + return _user; + } +}; + +export function setUser(u: User | null): void { + _user = u; +} diff --git a/web/src/lib/player/store.svelte.ts b/web/src/lib/player/store.svelte.ts index f4bf151d..9f730b20 100644 --- a/web/src/lib/player/store.svelte.ts +++ b/web/src/lib/player/store.svelte.ts @@ -1,7 +1,7 @@ import type { TrackRef, RadioResponse } from '$lib/api/types'; import { untrack } from 'svelte'; import { api } from '$lib/api/client'; -import { user } from '$lib/auth/store.svelte'; +import { user } from '$lib/auth/user.svelte'; import { readPersistedQueue, writePersistedQueue } from './persisted'; export type PlayerState = 'idle' | 'loading' | 'playing' | 'paused' | 'error'; @@ -397,10 +397,7 @@ $effect.root(() => { // queue/index changes drive it. The throttled-write effect below // covers position drift. $effect(() => { - // `user?.value` (not `user.value`) guards against module-init order during - // tests: auth/store.svelte.ts imports from this file, so when this module - // loads via that chain, `user` may not yet be assigned. See I2 follow-up. - const userId = user?.value?.id; + const userId = user.value?.id; if (!userId) return; // Reading these registers the reactive dependency; the values // themselves are unused — writePersistedQueue re-reads live state. @@ -416,7 +413,7 @@ $effect.root(() => { // Throttled write on position changes. $effect(() => { - const userId = user?.value?.id; + const userId = user.value?.id; if (!userId) return; const _p = _position; void _p;