Files
librenotes/cmd
libretechandClaude Opus 4.7 f166485012 Add background sync controller with conflict detection
cmd/librenotes/web/public/sync.js drives the offline-online
reconciliation flow against the notes REST API:

- start(): registers online/offline window listeners, runs an
  initial syncOnce() if currently online.
- syncOnce(): push() then pull(); emits "librenotes:sync-state"
  events with state in {online, offline, syncing, synced, error}.
- push(): walks notesCache.pending() (rows with dirty=1, including
  tombstones). PUTs use ?base=<synced_at> for optimistic locking
  and DELETEs use the same. The notes API returns 409 with the
  current server body on conflict; sync.js stashes the pair in
  conflictsById and dispatches "librenotes:sync-conflict" so the
  app shell can render a resolution dialog.
- pull(): GETs the summary list, refetches any row whose server
  updated_at exceeds the local synced_at (or that is missing
  locally), and stamps it as cleanly synced. Skips locally-dirty
  rows so push's conflict path stays authoritative.
- resolveConflict(id, "local"|"remote"|"merge", merged): replays
  the user's choice. "local" and "merge" PUT with the latest
  server base so the second attempt accepts; "remote" overwrites
  the local cache with the server copy.

app.html now includes a sync-state badge in the header and a
<dialog> for conflict resolution wired to the events. app.js
calls notesSync.start() on load and routes dialog clicks back to
resolveConflict. The dialog uses native <dialog>.showModal(),
which all current target browsers support.

style.css adds badge colour states (syncing/synced/offline/error)
and a two-column conflict layout that collapses on narrow widths.

Closes #23.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 22:45:25 +02:00
..