77 lines
1.8 KiB
TypeScript
77 lines
1.8 KiB
TypeScript
import type { AuthSessionResponse } from "./contractsAuth";
|
|
|
|
const STORAGE_KEY = "space-game.auth.session";
|
|
|
|
export interface AuthSession {
|
|
userId: string;
|
|
email: string;
|
|
roles: string[];
|
|
accessToken: string;
|
|
accessTokenExpiresAtUtc: string;
|
|
refreshToken: string;
|
|
refreshTokenExpiresAtUtc: string;
|
|
}
|
|
|
|
let currentSession: AuthSession | null = loadStoredSession();
|
|
const listeners = new Set<(session: AuthSession | null) => void>();
|
|
|
|
export function getAuthSession(): AuthSession | null {
|
|
return currentSession;
|
|
}
|
|
|
|
export function setAuthSession(session: AuthSessionResponse | null) {
|
|
currentSession = session ? { ...session } : null;
|
|
persistSession(currentSession);
|
|
notifyListeners();
|
|
}
|
|
|
|
export function clearAuthSession() {
|
|
currentSession = null;
|
|
persistSession(null);
|
|
notifyListeners();
|
|
}
|
|
|
|
export function subscribeToAuthSession(listener: (session: AuthSession | null) => void) {
|
|
listeners.add(listener);
|
|
return () => listeners.delete(listener);
|
|
}
|
|
|
|
function loadStoredSession(): AuthSession | null {
|
|
if (typeof window === "undefined") {
|
|
return null;
|
|
}
|
|
|
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const parsed = JSON.parse(raw) as AuthSession;
|
|
return parsed?.accessToken && parsed?.refreshToken
|
|
? { ...parsed, roles: Array.isArray(parsed.roles) ? parsed.roles : [] }
|
|
: null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function persistSession(session: AuthSession | null) {
|
|
if (typeof window === "undefined") {
|
|
return;
|
|
}
|
|
|
|
if (!session) {
|
|
window.localStorage.removeItem(STORAGE_KEY);
|
|
return;
|
|
}
|
|
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(session));
|
|
}
|
|
|
|
function notifyListeners() {
|
|
for (const listener of listeners) {
|
|
listener(currentSession);
|
|
}
|
|
}
|