File size: 1,376 Bytes
de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b de6cac5 45a105b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | // Session state is kept in memory only — NEVER localStorage/sessionStorage/URLs.
// It holds (a) the bearer token and (b) the active demo user. Both are lost on a
// full page refresh by design (in-memory only); this is acceptable for the trusted
// demo environment and documented in the UI ("sign in again after refresh").
// If the backend later moves to HTTP-only cookies, `credentials: 'include'` on the
// client already carries them and the token half of this module becomes a no-op.
export interface ActiveUser {
userId: string
via: 'demo' | 'passkey'
}
let token: string | null = null
let activeUser: ActiveUser | null = null
const listeners = new Set<() => void>()
function emit(): void {
listeners.forEach((fn) => fn())
}
export function setToken(t: string | null): void {
token = t
emit()
}
export function getToken(): string | null {
return token
}
export function setActiveUser(user: ActiveUser | null): void {
activeUser = user
emit()
}
export function getActiveUser(): ActiveUser | null {
return activeUser
}
export function isAuthenticated(): boolean {
return token !== null
}
/** Clears both the token and the active user. */
export function logout(): void {
token = null
activeUser = null
emit()
}
export function onSessionChange(fn: () => void): () => void {
listeners.add(fn)
return () => listeners.delete(fn)
}
|