refactor(confidence-engine): add investigation storage provider
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
// investigation-storage — generic persistence boundary
|
||||
// Exposes loadInvestigation / saveInvestigation / clearInvestigation
|
||||
// and delegates internally to the concrete localStorage provider.
|
||||
|
||||
export { loadInvestigation, saveInvestigation, clearInvestigation } from "./providers/local-storage.js";
|
||||
@@ -0,0 +1,111 @@
|
||||
// ── 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 only the canonical investigation key. */
|
||||
export function clearInvestigation() {
|
||||
const storage = _getTargetStorage();
|
||||
if (!storage) return;
|
||||
try { storage.removeItem(CANONICAL_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;
|
||||
}
|
||||
Reference in New Issue
Block a user