1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Pull-mirror sync: copies a remote `indicatrix-worker`'s design library into the
//! local `indicatrix_vault` database so it's available offline.
//!
//! Named `library_mirror`, not `sync`, deliberately: this is machine-to-machine
//! mirroring of the user's own library over the already-authenticated mutual-TLS
//! connection `bridge::remote::enroll` set up -- nothing here fetches a public URL,
//! parses HTML, or runs OCR.
//!
//! # The safety rule, and it is the whole point of this module
//!
//! **This sync is additive and update-only. It never deletes a local design,
//! attachment, or custom material.** A local design's identity is its
//! `diagram_entries.url` (a `UNIQUE` column; a locally-imported `.asc` file gets a
//! synthetic `local://<file name>` URL so it can never collide with a remote page URL).
//! This module only ever touches a row whose `url` a remote [`DesignSummary`]/
//! [`DesignRecord`] actually names, so a `local://...` row is structurally unreachable
//! here. There is no "delete anything local sync didn't just see" step -- unlike a
//! naive rsync-style mirror, "make local match remote" is never attempted, only "pull
//! what remote has" is.
//!
//! # Identity and staleness
//!
//! A remote design's `url` is the same field `diagram_entries.url`'s `UNIQUE`
//! constraint uses to decide "is this design already in the database" -- no new
//! identity scheme invented (cross-source duplicate detection for different sources
//! describing the same physical design is a separate, human-reviewed concern in
//! `crate::model::dedup`, untouched here). [`crate::model::mirror::MirrorState`]
//! remembers, per `url`, the last summary hash seen; a sync enumerates the whole remote
//! catalogue's summaries first, then skips a design entirely (no `FetchDesign`, no
//! attachment fetch, no local write) when its hash hasn't moved. A no-op second sync of
//! an unchanged catalogue costs one `SearchPage` request per page plus one
//! `library_mirror_state` read per known design -- zero `FetchDesign`/`FetchAttachment`.
//!
//! # Pagination
//!
//! [`sync::run_mirror_sync`] walks a keyset cursor (`LibraryRequest::SearchPage`,
//! `id > cursor`) to exhaustion before syncing begins, rather than `OFFSET`-based
//! paging -- a keyset walk can't skip or duplicate a row when another design is
//! inserted server-side mid-walk.
//!
//! # Attachments: fetched eagerly, up to a size cap
//!
//! Unlike interactive browsing (`bridge::library::client`, lazy fetch on open), a
//! mirror's whole purpose is offline availability, so every attachment for a saved
//! design is fetched immediately except one whose advertised
//! [`AttachedFileMeta::size`] exceeds [`options::MirrorOptions::max_attachment_bytes`]
//! -- a safety net against one pathological file, not a general skip switch. A skipped
//! attachment doesn't fail the whole design; only that file is left for a future sync.
//!
//! # Cancellation leaves the database consistent
//!
//! `cancel` is checked once per design, strictly before that design's network calls or
//! local write begin, never mid-design. Once a design starts, it always runs to
//! completion (attachments fetched first, then one transactional
//! `save_diagram_entry`/`save_diagram_detail` write) before the next check.
//! **Invariant:** at any interruption point, the local database reflects some prefix of
//! fully-completed per-design syncs plus whatever was there before -- no design is ever
//! left mid-write. Enumeration itself is not cancellable mid-walk (it does no local
//! writes) and fails outright, nothing written, on any request error.
//!
//! # Module split
//!
//! [`options`] holds the tuning-knob/progress/outcome types plus the
//! [`options::LibraryTransport`] abstraction the algorithm runs generically over;
//! [`sync`] holds the algorithm, its worker-thread wrapper, and its tests.
pub use ;
pub use spawn_mirror_sync;