// Lightweight reactive auth principal for the SPA. Since the switch to // session-cookie login (POST /api/manager/login), the SPA no longer relies on // the browser's Basic Auth: on mount we resolve GET /me — a session cookie // makes it 200 (signed in); otherwise it is 401 and the login page shows. // logout() clears the cookie server-side, so sign-out actually sticks. // // We default to read until /me resolves so a viewer never sees a flash of // admin controls. canWrite/isAdmin are memoized over the reactive level. import { computed, ref } from 'vue' import type { AccessLevel } from './types' import { api } from './api' export const authLevel = ref('read') export const authName = ref('') export const authReady = ref(false) export const isAuthed = ref(false) const RANK: Record = { read: 1, write: 2, admin: 3, superadmin: 4 } export const canWrite = computed(() => RANK[authLevel.value] >= RANK.write) // admin: full write access but cannot manage accounts (that needs superadmin). export const isAdmin = computed(() => authLevel.value === 'admin') // superadmin: the only tier that can manage accounts (users/apikeys routes). export const isSuperAdmin = computed(() => authLevel.value === 'superadmin') // login signs in via the session-cookie endpoint and mirrors the resolved // principal. Call from the login page; on success App.vue drops into the shell. export async function login(username: string, password: string): Promise { const me = await api.login(username, password) authLevel.value = me.level authName.value = me.name isAuthed.value = true authReady.value = true } // logout clears the UI session and returns to the login page. export async function logout(): Promise { try { await api.logout() } catch { // session cookie may already be gone; still reset local state } authLevel.value = 'read' authName.value = '' isAuthed.value = false } // fetchMe resolves the current principal. Called once on app mount; safe to // call again after account changes that could affect the live session. export async function fetchMe(): Promise { try { const me = await api.me() authLevel.value = me.level authName.value = me.name isAuthed.value = true } catch { // 401 (no/failed auth) — show the login page. authLevel.value = 'read' authName.value = '' isAuthed.value = false } finally { authReady.value = true } }