Files
confidence-engine/lib/storage/providers/local-storage.js
T

118 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ── canonical identifiers ────────────────────────────────────────────
const CANONICAL_KEY = "confidence-engine-investigation";
const LEGACY_KEY = "confidence-engine-session";
const SCHEMA_VERSION = 1;
// ── helpers ──────────────────────────────────────────────────────────
function safeGet(storage, key) {
if (!storage || typeof storage.getItem !== "function") return null;
try { return storage.getItem(key); } catch (_) { return null; }
}
function isPlainObject(value) {
return (
value !== null &&
typeof value === "object" &&
!Array.isArray(value) &&
Object.prototype.toString.call(value) === "[object Object]"
);
}
// ── loadInvestigation ────────────────────────────────────────────────
/**
* Returns the persisted investigation snapshot (normalised to current schema)
* or null when no usable state exists.
*/
export function loadInvestigation() {
const storage = _getTargetStorage();
if (!storage) return null;
// 1 canonical key first
let raw = safeGet(storage, CANONICAL_KEY);
if (raw !== null) {
try {
const parsed = JSON.parse(raw);
if (isPlainObject(parsed)) {
if (!("schemaVersion" in parsed)) parsed.schemaVersion = SCHEMA_VERSION;
return parsed;
}
} catch (_) { /* malformed — fall through to legacy */ }
}
// 2 legacy fallback
const legacyStorage = _getLegacyStorage();
if (!legacyStorage) return null;
raw = safeGet(legacyStorage, LEGACY_KEY);
if (raw === null) return null;
let parsed;
try {
parsed = JSON.parse(raw);
} catch (_) { return null; }
if (!isPlainObject(parsed)) return null;
// Normalise schemaVersion for legacy data
if (!("schemaVersion" in parsed)) parsed.schemaVersion = SCHEMA_VERSION;
// Migrate into canonical key
_persist(storage, CANONICAL_KEY, JSON.stringify(parsed));
return parsed;
}
// ── saveInvestigation ────────────────────────────────────────────────
/**
* Persists the supplied snapshot to the canonical localStorage key.
* The caller's object is never mutated.
*/
export function saveInvestigation(snapshot) {
const storage = _getTargetStorage();
if (!storage) return; // silently no-op in non-browser
try {
const record = JSON.parse(JSON.stringify(snapshot));
record.schemaVersion = SCHEMA_VERSION;
_persist(storage, CANONICAL_KEY, JSON.stringify(record));
} catch (_) { /* storage errors must not crash caller */ }
}
// ── clearInvestigation ───────────────────────────────────────────────
/** Removes the canonical investigation key and the legacy session key. */
export function clearInvestigation() {
const storage = _getTargetStorage();
if (!storage) return;
try { storage.removeItem(CANONICAL_KEY); } catch (_) {}
// Also remove the legacy sessionStorage key so it cannot resurrect stale
// state after loadInvestigation falls through from missing canonical key.
const legacyStorage = _getLegacyStorage();
if (!legacyStorage) return;
try { legacyStorage.removeItem(LEGACY_KEY); } catch (_) {}
}
// ── internals ────────────────────────────────────────────────────────
function _persist(storage, key, value) {
try { storage.setItem(key, value); } catch (_) {}
}
function _getTargetStorage() {
if (typeof globalThis.window === "undefined") return null;
const s = globalThis.window.localStorage;
if (!s || typeof s.getItem !== "function") return null;
return s;
}
function _getLegacyStorage() {
if (typeof globalThis.window === "undefined") return null;
const s = globalThis.window.sessionStorage;
if (!s || typeof s.getItem !== "function") return null;
return s;
}