62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
|
|
const STORAGE_KEY = "geo.ops-web.session";
|
||
|
|
|
||
|
|
export interface OperatorView {
|
||
|
|
id: number;
|
||
|
|
username: string;
|
||
|
|
display_name: string;
|
||
|
|
email: string | null;
|
||
|
|
role: string;
|
||
|
|
status: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface OpsSession {
|
||
|
|
accessToken: string | null;
|
||
|
|
expiresAt: number | null;
|
||
|
|
operator: OperatorView | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function emptySession(): OpsSession {
|
||
|
|
return { accessToken: null, expiresAt: null, operator: null };
|
||
|
|
}
|
||
|
|
|
||
|
|
function hasStorage(): boolean {
|
||
|
|
return typeof window !== "undefined" && "localStorage" in window;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function readStoredSession(): OpsSession {
|
||
|
|
if (!hasStorage()) return emptySession();
|
||
|
|
try {
|
||
|
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
||
|
|
if (!raw) return emptySession();
|
||
|
|
const parsed = JSON.parse(raw) as Partial<OpsSession>;
|
||
|
|
return {
|
||
|
|
accessToken: typeof parsed.accessToken === "string" ? parsed.accessToken : null,
|
||
|
|
expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : null,
|
||
|
|
operator:
|
||
|
|
parsed.operator && typeof parsed.operator === "object"
|
||
|
|
? (parsed.operator as OperatorView)
|
||
|
|
: null,
|
||
|
|
};
|
||
|
|
} catch {
|
||
|
|
return emptySession();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function writeStoredSession(session: OpsSession): void {
|
||
|
|
if (!hasStorage()) return;
|
||
|
|
try {
|
||
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(session));
|
||
|
|
} catch {
|
||
|
|
// ignore quota / serialization errors
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function clearStoredSession(): void {
|
||
|
|
if (!hasStorage()) return;
|
||
|
|
try {
|
||
|
|
window.localStorage.removeItem(STORAGE_KEY);
|
||
|
|
} catch {
|
||
|
|
// noop
|
||
|
|
}
|
||
|
|
}
|