Files
geo/apps/ops-web/src/lib/storage.ts
T

122 lines
3.2 KiB
TypeScript
Raw Normal View History

const SESSION_KEY = "geo.ops-web.session";
const PREFERENCE_KEY = "geo.ops-web.login-preference";
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;
}
export interface LoginPreference {
remember: boolean;
lastUsername: string;
}
export interface StoredSession {
session: OpsSession;
persistent: boolean;
}
function emptySession(): OpsSession {
return { accessToken: null, expiresAt: null, operator: null };
}
function emptyPreference(): LoginPreference {
return { remember: false, lastUsername: "" };
}
function hasWindow(): boolean {
return typeof window !== "undefined";
}
function readFrom(storage: Storage): OpsSession | null {
try {
const raw = storage.getItem(SESSION_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw) as Partial<OpsSession>;
if (typeof parsed.accessToken !== "string" || !parsed.accessToken) return null;
return {
accessToken: parsed.accessToken,
expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : null,
operator:
parsed.operator && typeof parsed.operator === "object"
? (parsed.operator as OperatorView)
: null,
};
} catch {
return null;
}
}
export function readStoredSession(): StoredSession {
if (!hasWindow()) return { session: emptySession(), persistent: false };
const persistent = readFrom(window.localStorage);
if (persistent) return { session: persistent, persistent: true };
const ephemeral = readFrom(window.sessionStorage);
if (ephemeral) return { session: ephemeral, persistent: false };
return { session: emptySession(), persistent: false };
}
export function writeStoredSession(session: OpsSession, persistent: boolean): void {
if (!hasWindow()) return;
const target = persistent ? window.localStorage : window.sessionStorage;
const other = persistent ? window.sessionStorage : window.localStorage;
try {
target.setItem(SESSION_KEY, JSON.stringify(session));
} catch {
// ignore quota / serialization errors
}
try {
other.removeItem(SESSION_KEY);
} catch {
// noop
}
}
export function clearStoredSession(): void {
if (!hasWindow()) return;
try {
window.localStorage.removeItem(SESSION_KEY);
} catch {
// noop
}
try {
window.sessionStorage.removeItem(SESSION_KEY);
} catch {
// noop
}
}
export function readLoginPreference(): LoginPreference {
if (!hasWindow()) return emptyPreference();
try {
const raw = window.localStorage.getItem(PREFERENCE_KEY);
if (!raw) return emptyPreference();
const parsed = JSON.parse(raw) as Partial<LoginPreference>;
return {
remember: parsed.remember === true,
lastUsername: typeof parsed.lastUsername === "string" ? parsed.lastUsername : "",
};
} catch {
return emptyPreference();
}
}
export function writeLoginPreference(pref: LoginPreference): void {
if (!hasWindow()) return;
try {
window.localStorage.setItem(PREFERENCE_KEY, JSON.stringify(pref));
} catch {
// noop
}
}