feat(web): add rune-based auth store with bootstrap/login/logout

Central synchronous source of truth for 'who is signed in'. bootstrap()
runs once in +layout.ts load(); login/logout mutate _user and the
TanStack query cache. The silent option on logout is used by the 401
interceptor (next commit) to avoid POSTing /logout against an already-
invalid session.
This commit is contained in:
2026-04-22 17:28:10 -04:00
parent 12bf873f39
commit 07b5912fae
2 changed files with 113 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
import { api, type User, type LoginResponse } from '$lib/api/client';
import { queryClient } from '$lib/query/client';
let _user = $state<User | null>(null);
export const user = {
get value(): User | null {
return _user;
}
};
export async function bootstrap(): Promise<void> {
try {
_user = await api.get<User>('/api/me');
} catch {
_user = null;
}
}
export async function login(username: string, password: string): Promise<void> {
const res = await api.post<LoginResponse>('/api/auth/login', { username, password });
_user = res.user;
}
export async function logout(opts: { silent?: boolean } = {}): Promise<void> {
if (!opts.silent) {
try {
await api.post('/api/auth/logout', {});
} catch {
// best effort — server-side session may already be gone
}
}
_user = null;
queryClient.clear();
}