Build and Push Docker Image / build-and-push (push) Successful in 5m13s
- Earlier versions of a study: the server keeps compressed copies (about one per ten minutes of editing, the latest 30); Export shows what differs and puts one back (the replaced copy is kept) - Notes on highlights and bookmarks: synced, merged without loss, in exports and backups - Reader verse panel lists your studies and chunks that cover the verse, and opens them - Prayer journal: requests, who for, linked verses, days prayed, answers; synced, in backups and the account export; daily prayer reminder through ntfy - TODO.md lists the ideas not built yet Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
33 lines
1.5 KiB
JavaScript
33 lines
1.5 KiB
JavaScript
// 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 };
|
|
}
|