Files
readest/apps/readest.koplugin/readest-sync-api.json
T
Huang Xin 35b02c4efc feat(statistics): KOReader-compatible reading stats with cross-device sync (#4606)
Supersedes #3156. Adds a reading-statistics system whose canonical data model
is KOReader's own (book + page_stat_data), so stats round-trip losslessly
between Readest and KOReader.

- Storage: a cross-platform Turso statistics.db in KOReader's exact schema
  (web/Workers, desktop, iOS, Android) — replacing #3156's Node-only
  better-sqlite3 + statistics.json.
- Tracking: per-page reading events (time-on-page, idle-capped) flushed on
  page-change/idle/hide/close — the KOReader model — not session aggregates.
- Sync: legacy /api/sync extended with a stats type backed by self-contained
  Supabase tables (stat_books, stat_pages); union/longer-duration-wins merge
  keyed on book_hash. apps/readest.koplugin syncs through the same endpoint.
- Scale & robustness: per-tab singleton connection (avoids OPFS lock
  conflicts) + explicit WAL checkpoint; transactional bulk apply; chunked
  resumable push; client-driven paged pull with trailing-ms completion;
  paginated/scoped server merge.

Verified: 5668 unit tests, 155 koplugin busted tests, biome+tsgo + luacheck
all green; web OPFS DB verified live.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 10:42:39 +02:00

51 lines
1.5 KiB
JSON

{
"base_url": "https://web.readest.com/api",
"name": "readest-sync-api",
"methods": {
"pullChanges": {
"path": "/sync",
"method": "GET",
"required_params": ["since", "type", "book", "meta_hash"],
"expected_status": [200, 400, 301, 401, 403]
},
"pushChanges": {
"path": "/sync",
"method": "POST",
"required_params": ["books", "notes", "configs"],
"payload": ["books", "notes", "configs", "statBooks", "statPages"],
"expected_status": [200, 201, 301, 400, 401, 403]
},
"pullBooks": {
"path": "/sync?type=books",
"method": "GET",
"required_params": ["since"],
"expected_status": [200, 400, 301, 401, 403]
},
"getDownloadUrl": {
"path": "/storage/download",
"method": "GET",
"required_params": ["fileKey"],
"expected_status": [200, 400, 301, 401, 403, 404]
},
"listFiles": {
"path": "/storage/list",
"method": "GET",
"required_params": ["bookHash"],
"expected_status": [200, 400, 301, 401, 403]
},
"deleteFile": {
"path": "/storage/delete",
"method": "DELETE",
"required_params": ["fileKey"],
"expected_status": [200, 400, 301, 401, 403, 404]
},
"getUploadUrl": {
"path": "/storage/upload",
"method": "POST",
"required_params": ["fileName", "fileSize", "bookHash"],
"payload": ["fileName", "fileSize", "bookHash"],
"expected_status": [200, 400, 301, 401, 403]
}
}
}