Build and Push Docker Image / build-and-push (push) Successful in 7m14s
Sync and data safety - Autosave flushes on leaving a study or the tab; storage-full errors are reported - Unsynced studies, deletes and ink are queued and retried when back online - Deletes propagate across devices (with a "Keep it" undo) and no longer resurrect - Server assigns study versions (no client-clock conflicts); "Combine both" merges a conflicted study chunk by chunk - Reading-plan progress made offline is merged, not overwritten; plans, ink and marks are cleared from the device on sign-out Security - Block SSRF through the ntfy reminder URL; failure-only rate limiting per IP and account; constant-time login; TOTP replay protection; input validation; SESSION_SECRET required in production; admin user delete fixed - Forgot password: one-time code sent to the account's ntfy topic Features - IQ Bible proxy (route allow-list, text-only caching per its terms): more commentaries, lexicons, study aids, daily verse and devotional, plan calendar export, narrations, podcast background - Study templates, reading-plan catch-up, account export, daily database snapshots Tests and tooling - ESLint config; App tests split into src/test; tests for sync queues, library hook, merge, templates, IQ Bible UI and reset form Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
20 lines
1.2 KiB
JavaScript
20 lines
1.2 KiB
JavaScript
// Fetches a chapter's raw text for building a study (the free Bible source). The Reader's "Save for
|
|
// offline" downloads go through the same address, so a saved book builds a study with no connection.
|
|
// Failures say what's wrong and what to do, instead of a generic error.
|
|
export async function fetchStudyChapter(translation, bookAbbrev, chapter, { signal } = {}) {
|
|
const code = translation === 'NET' ? 'eng_net' : (translation || 'BSB');
|
|
let res;
|
|
try {
|
|
res = await fetch(`https://bible.helloao.org/api/${code}/${bookAbbrev}/${chapter}.json`, { signal });
|
|
} catch (err) {
|
|
if (err?.name === 'AbortError') throw err;
|
|
const offline = typeof navigator !== 'undefined' && navigator.onLine === false;
|
|
throw new Error(offline
|
|
? "You're offline and this chapter isn't saved on this device. In the Reader, use Save for offline while connected."
|
|
: 'Could not reach the Bible text. Check your connection and try again.', { cause: err });
|
|
}
|
|
if (res.status === 503) throw new Error("You're offline and this chapter isn't saved on this device. In the Reader, use Save for offline while connected.");
|
|
if (!res.ok) throw new Error('Unable to load chapter.');
|
|
return res.json();
|
|
}
|