| // Archive for ended Test Bench sessions. Persisted to the browser's | |
| // localStorage — this is single-browser, client-side retention, not a | |
| // shared server database. A "session" is every run since the last time | |
| // the user pressed End Session; nothing is written until that deliberate | |
| // action, so the record reflects a documented decision, not a side effect | |
| // of each individual run. | |
| export type ArchiveStatus = "done" | "blocked" | "expired"; | |
| export type ArchiveEntry = { | |
| id: string; | |
| timestamp: number; | |
| pipelineName: string; | |
| targetLabel: string; | |
| status: ArchiveStatus; | |
| checksum: string; | |
| byteSize: number; | |
| loc: number; | |
| nodeCount: number; | |
| runsInSession: number; | |
| performanceSummary: string; | |
| log: string[]; | |
| }; | |
| const STORAGE_KEY = "layer.testbench.archive"; | |
| const MAX_ENTRIES = 200; | |
| export function loadArchive(): ArchiveEntry[] { | |
| if (typeof window === "undefined") return []; | |
| try { | |
| const raw = window.localStorage.getItem(STORAGE_KEY); | |
| if (!raw) return []; | |
| const parsed = JSON.parse(raw); | |
| return Array.isArray(parsed) ? (parsed as ArchiveEntry[]) : []; | |
| } catch { | |
| return []; | |
| } | |
| } | |
| export function saveArchiveEntry(entry: ArchiveEntry): void { | |
| if (typeof window === "undefined") return; | |
| const next = [entry, ...loadArchive()].slice(0, MAX_ENTRIES); | |
| try { | |
| window.localStorage.setItem(STORAGE_KEY, JSON.stringify(next)); | |
| } catch { | |
| // Storage full or unavailable — the run itself already succeeded, so | |
| // fail the archive write silently rather than blocking the user. | |
| } | |
| } | |