Harden sync and security; add IQ Bible, templates, password reset, backups
Build and Push Docker Image / build-and-push (push) Successful in 7m14s
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>
This commit is contained in:
1 parent
6bb392933a
commit
f274bc9c8a
67 files changed
+4734
-1569
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// The Outline stage: choose a chapter, then cut it into chunks by clicking between
|
||||
// verses (or let the section headings suggest them). Each chunk becomes one unit of
|
||||
// study in the next stage.
|
||||
import { STUDY_TEMPLATES, getTemplate } from '../utils/studyTemplates.js';
|
||||
import { useApp } from '../context/AppContext.js';
|
||||
import { useChunkBuilder } from '../hooks/useChunkBuilder.js';
|
||||
import StudioShell from '../components/study/StudioShell.jsx';
|
||||
@@ -30,6 +31,14 @@ function PassageForm({ setup, onField, onTitleChange, onLoad, loading, error, wi
|
||||
<input type="text" value={setup.title} onChange={(e) => onTitleChange(e.target.value)} className={inputCls} />
|
||||
</label>
|
||||
)}
|
||||
{withTitle && (
|
||||
<label className="block text-sm sm:col-span-2">Start from
|
||||
<select value={setup.template ?? 'blank'} onChange={(e) => onField('template', e.target.value)} className={inputCls}>
|
||||
{STUDY_TEMPLATES.map((t) => <option key={t.id} value={t.id}>{t.name}</option>)}
|
||||
</select>
|
||||
<span className="mt-1 block text-xs text-[var(--r-sub)]">{getTemplate(setup.template).description}</span>
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<p className="text-xs text-[var(--r-sub)]">{error ? <span className="text-[var(--r-danger,#b42318)]">{error}</span> : 'Text: Berean Standard Bible (BSB).'}</p>
|
||||
|
||||
Reference in new issue
Block a user