// Earlier versions of a study. Just before a save replaces what the server holds, that copy can be kept, so a // bad merge or an accidental delete can be undone. To stay small, a copy is kept at most once per window of // editing, it is compressed, and only the newest few are kept. import { gunzipSync, gzipSync } from 'zlib'; export const MIN_GAP_MS = 10 * 60 * 1000; // one version per ten minutes of editing history export const MAX_VERSIONS = 30; // `prevEditedAt` is when the copy about to be replaced was saved; `lastKeptAt` is when the newest kept version was. export function shouldSnapshot({ prevEditedAt, lastKeptAt, force = false, minGap = MIN_GAP_MS }) { if (!Number.isFinite(prevEditedAt)) return false; if (force) return true; return !Number.isFinite(lastKeptAt) || prevEditedAt - lastKeptAt >= minGap; } export const pack = (json) => gzipSync(Buffer.from(typeof json === 'string' ? json : JSON.stringify(json))); export const unpack = (buf) => JSON.parse(gunzipSync(buf).toString('utf8')); const words = (s) => (String(s ?? '').trim() ? String(s).trim().split(/\s+/).length : 0); // How big a study is: chunks and the words in its notes and scripts. export function summarizeProject(project) { let chunks = 0; let noteWords = 0; for (const chapter of project?.chapters ?? []) { for (const chunk of chapter.chunks ?? []) { chunks += 1; for (const f of ['observation', 'interpretation', 'application', 'generalNotes', 'finalScript']) noteWords += words(chunk[f]); } } return { chunks, words: noteWords }; }