branchjam / src /persistence.js
abhid1234's picture
Upload folder using huggingface_hub
2fe29a7 verified
Raw
History Blame Contribute Delete
2.92 kB
import { createSession, validateSession } from "./domain.js";
export const STORAGE_KEY = "branchjam:session:v1";
const canonicalValue = (value) => {
if (Array.isArray(value)) return value.map(canonicalValue);
if (!value || typeof value !== "object") return value;
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalValue(value[key])]));
};
export function serializeSession(state) {
const ordered = {
schemaVersion: state.schemaVersion,
catalogVersion: state.catalogVersion,
phase: state.phase,
seedNodeId: state.seedNodeId,
activeNodeId: state.activeNodeId,
inspectedNodeId: state.inspectedNodeId,
selectedConstraintId: state.selectedConstraintId,
currentRoundId: state.currentRoundId,
compareSelection: state.compareSelection,
nodesById: canonicalValue(state.nodesById),
roundsById: canonicalValue(state.roundsById)
};
return JSON.stringify(ordered);
}
export function createPersistence(storage, source) {
let memory = null;
let available = true;
const save = (state) => {
const serialized = serializeSession(state);
memory = serialized;
try {
storage.setItem(STORAGE_KEY, serialized);
return { ok: true, available, notice: "Local session saved." };
} catch {
available = false;
return { ok: false, available, notice: "Storage could not save this session; play continues in memory only." };
}
};
const load = () => {
let raw = memory;
try { raw = storage.getItem(STORAGE_KEY) ?? raw; }
catch { available = false; }
if (!raw) return { state: createSession(source), recovered: false, available, notice: available ? null : "Storage is unavailable; this session continues in memory only." };
try {
const state = JSON.parse(raw);
if (!validateSession(state, source)) throw new Error("invalid");
return { state, recovered: false, available, notice: available ? null : "Storage is unavailable; the in-memory session was restored for this page only." };
} catch {
memory = null;
try { storage.removeItem(STORAGE_KEY); }
catch { available = false; }
return {
state: createSession(source), recovered: true, available,
notice: available
? "Saved session was invalid or incompatible and was removed. A fresh local session is ready."
: "Saved session was invalid or incompatible. A fresh in-memory session is ready; storage cleanup was unavailable."
};
}
};
const reset = () => {
memory = null;
try { storage.removeItem(STORAGE_KEY); }
catch { available = false; }
return {
state: createSession(source), available,
notice: available
? "Local session reset to the seed."
: "Session reset to the seed in memory; storage cleanup was unavailable."
};
};
return { save, load, reset, get available() { return available; } };
}