Commit Graph
5 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 17076d6a79 DRY pass #2, batch 7, F21: the desktop's main window, clock and launcher dir (#5372)
- lib.rs MAIN_WINDOW: the "main" window label that the reminder worker,
  the capture window and the shell each wrote, 5 sites in all.
- lib.rs now_ms(): the epoch-milliseconds clock that the reminder worker
  and autosync's cycle stamp each computed. LastCycle.at_ms becomes i64,
  the same number on the wire.
- integration.rs applications_dir(): the XDG launcher directory that the
  entry path and the desktop-database refresh each built.

rustfmt --check is clean in the CI image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:00:03 -04:00
bvandeusenandClaude Opus 5.5 70274347af One read of a device's link: state::credentials, with the client's seal
Five places read the server address and token straight from sync_state:
sharing, autosync, sync_unlink, update's download token, and the ffi. Reading it
raw is how Android came to send its sealed token to the share routes (#5381).
state::credentials(conn, seal) now holds that read. With a seal it opens the token
(open_token), and without one (the desktop keeps it plain) it returns it as stored.
Every site calls it.

DRY pass #2, batch 1, F1 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:14:18 -04:00
bvandeusenandClaude Opus 5.5 05c82c2362 core, desktop: Db::conn everywhere, Change::default, notes_where, and shared row mappings
Android / Kotlin + Rust (APK) (push) Canceled after 12m20s
Android / Build, or is the channel already serving this? (push) Successful in 4s
CI & Build / Build now, or wait for Android? (push) Successful in 4s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Python tests (push) Successful in 15s
CI & Build / Web typecheck and unit tests (push) Successful in 16s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / integration (push) Successful in 1m22s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 4m6s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 4m20s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 5m21s
Desktop (Tauri) / Update manifest (push) Successful in 5s
From the audit (#5179, core and desktop half).

- Every `db.0.lock().map_err(|e| e.to_string())?` (about 50 sites in core and
  the desktop) is now `db.conn()?`. The few sites that deliberately handle
  a poisoned lock differently, and the tests, keep their own spelling.
- push::Change derives Default, so its four constructors name only the
  fields they set.
- store: list_notes, reminders, titles and search share notes_where (ids
  from a query, each loaded through load_note). Labels share
  LABEL_SELECT/label_row, and saved filters share
  SAVED_FILTER_SELECT/saved_filter_row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:57:24 -04:00
bvandeusenandClaude Opus 5.5 2b2ceaa82e attachments sync: attach offline, upload when linked, removals stick (#5168)
CI & Build / Build now, or wait for Android? (push) Successful in 4s
CI & Build / Python lint (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 4s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 35s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / Web typecheck and unit tests (push) Successful in 9s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 2m23s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Android / Kotlin + Rust (APK) (push) Successful in 7m17s
Desktop could not create an attachment at all, and a removed attachment or
dismissed preview came back on the next pull. Now:

- core: add_attachment keeps the bytes in the blob store and queues the row
  (schema v10: attachments.uploaded / upload_error). Push uploads it once its
  note has landed. A refusal that retrying won't fix (too large, id clash, hash
  mismatch) is recorded on the file and not re-sent every cycle; the editor
  shows it.
- core: removing a synced attachment or dismissing a preview leaves a tombstone
  in pending_deletes; push sends it as an `attachment`/`preview` delete, and a
  pull while it waits doesn't put the row back. A pull also keeps files still
  waiting to upload instead of replacing them wholesale.
- server: PUT /api/sync/attachments/<id> (raw body, sha256-checked, idempotent,
  size-capped) and child deletes in push, which apply regardless of LWW and
  answer noop for rows the caller can't see. One store_attachment helper for
  the upload route, the importer and sync. Protocol 5, feature attachment_sync;
  the client sends neither to a server without it.
- server: migration 0031 makes a link preview's insert/delete bump its note, so
  background-fetched previews and web dismissals reach linked devices.
- desktop: Attach and paste-image work offline (raw-bytes IPC command).
- SVG is served as a download by the desktop blob scheme too (as #1981 did for
  the web), and drawn as a file chip on both.
- autosync: drop the catch_unwind; release builds abort on panic, so it only
  ever worked in debug builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:07:52 -04:00
bvandeusenandClaude Opus 5.5 efb141e555 desktop: syncs on its own — at launch, soon after an edit, every few minutes and on focus
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m53s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m47s
Desktop (Tauri) / Update manifest (push) Successful in 6s
Android / Kotlin + Rust (APK) (push) Successful in 11m34s
Android / Build, or is the channel already serving this? (push) Successful in 5s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 13s
CI & Build / Python tests (push) Successful in 14s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / integration (push) Successful in 47s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 3m8s
Until now the only caller of the sync engine was the "Sync now" button. A worker
thread now owns every cycle (the button's included, so two never overlap):

- launch: one cycle as the app opens;
- edit: every 10s it reads a fingerprint of the pending set and sends when that
  moved. A fingerprint rather than "anything pending", because a rejected change
  stays pending and would otherwise be resent every tick forever;
- timer: a pull every 5 minutes with nothing to send;
- focus: at most once per 30s.

Failed automatic cycles back off (doubling from 10s to 5 minutes). A panicking
cycle counts as a failed one rather than ending the thread. Every cycle is
emitted as inkwell://synced: the board reloads when the pull changed something,
and the Sync screen shows the last automatic failure. No final push on quit;
the launch cycle sends whatever was left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 23:40:27 -04:00