Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions backup.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
// scan cache — round-trips through one human-readable JSON file.

export const BACKUP_FORMAT = 'repolens-backup';
export const BACKUP_VERSION = 1;
export const BACKUP_VERSION = 2;

// Upper bounds on how much a single import may write, so a hostile or corrupt
// file can't pin the IndexedDB write lock or blow the storage quota. Anything
// past these is dropped with a surfaced warning (never silently).
export const MAX_ROWS = { repos: 5000, nodes: 20000, edges: 50000, cache: 5000, collections: 2000, decisions: 5000 };
export const MAX_ROWS = { repos: 5000, nodes: 20000, edges: 50000, cache: 5000, collections: 2000, decisions: 5000, snapshots: 5000 };

// Per-repo snapshot ring-buffer cap (mirrors SNAPSHOT_CAP in snapshots.js); each
// imported snapshots row is trimmed to its most recent SNAP_CAP entries.
const SNAP_CAP = 30;

const arr = (x) => (Array.isArray(x) ? x : []);
const rowHasRepo = (r) => !!(r && r.id != null && r.payload && r.payload.repoId);
Expand All @@ -22,10 +26,11 @@ const edgeOk = (e) => !!(e && e.id != null && e.source != null && e.target != nu
const cacheOk = (c) => !!(c && c.repoId && c.platform);
const collectionOk = (c) => !!(c && c.id != null && c.payload && typeof c.payload.name === 'string');
const decisionOk = (d) => !!(d && d.id != null && d.payload && d.payload.repoId && d.payload.decision);
const snapshotOk = (r) => !!(r && r.id != null && r.repoId && Array.isArray(r.snaps));

/** Empty normalized shape — the safe fallback when a file can't be parsed. */
function emptyValue() {
return { repos: [], nodes: [], edges: [], cache: [], collections: [], decisions: [] };
return { repos: [], nodes: [], edges: [], cache: [], collections: [], decisions: [], snapshots: [] };
}

/**
Expand All @@ -34,19 +39,14 @@ function emptyValue() {
* @param {{ repos?: object[], nodes?: object[], edges?: object[], cache?: object[], exportedAt?: string }} [parts]
* @returns {object}
*/
export function buildBackup({ repos, nodes, edges, cache, collections, decisions, exportedAt } = {}) {
const r = arr(repos), n = arr(nodes), e = arr(edges), c = arr(cache), col = arr(collections), dec = arr(decisions);
export function buildBackup({ repos, nodes, edges, cache, collections, decisions, snapshots, exportedAt } = {}) {
const r = arr(repos), n = arr(nodes), e = arr(edges), c = arr(cache), col = arr(collections), dec = arr(decisions), snap = arr(snapshots);
return {
format: BACKUP_FORMAT,
version: BACKUP_VERSION,
exportedAt: exportedAt || new Date().toISOString(),
counts: { repos: r.length, nodes: n.length, edges: e.length, cache: c.length, collections: col.length, decisions: dec.length },
repos: r,
nodes: n,
edges: e,
cache: c,
collections: col,
decisions: dec,
counts: { repos: r.length, nodes: n.length, edges: e.length, cache: c.length, collections: col.length, decisions: dec.length, snapshots: snap.length },
repos: r, nodes: n, edges: e, cache: c, collections: col, decisions: dec, snapshots: snap,
};
}

Expand Down Expand Up @@ -87,6 +87,7 @@ export function validateBackup(obj) {
cache: clamp('cache', arr(obj.cache).filter(cacheOk)),
collections: clamp('collections', arr(obj.collections).filter(collectionOk)),
decisions: clamp('decisions', arr(obj.decisions).filter(decisionOk)),
snapshots: clamp('snapshots', arr(obj.snapshots).filter(snapshotOk).map((r) => ({ ...r, snaps: arr(r.snaps).slice(-SNAP_CAP) }))),
};
return { ok: errors.length === 0, errors, warnings, value };
}
Expand All @@ -99,7 +100,7 @@ export function validateBackup(obj) {
*/
export function summarizeBackup(obj) {
const { value } = validateBackup(obj);
return { repos: value.repos.length, nodes: value.nodes.length, edges: value.edges.length, cache: value.cache.length, collections: value.collections.length, decisions: value.decisions.length };
return { repos: value.repos.length, nodes: value.nodes.length, edges: value.edges.length, cache: value.cache.length, collections: value.collections.length, decisions: value.decisions.length, snapshots: value.snapshots.length };
}

/**
Expand Down
2 changes: 1 addition & 1 deletion diff-analysis.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Pure helpers for "Diff Since I Last Looked" — compares two cached analysis snapshots.
// No DOM, no chrome APIs, unit-testable.

const FIT_ORDER = ['strong', 'solid', 'care', 'risky'];
export const FIT_ORDER = ['strong', 'solid', 'care', 'risky'];
const FIT_RANK = Object.fromEntries(FIT_ORDER.map((f, i) => [f, i]));

export function daysSince(isoTs) {
Expand Down
Loading
Loading