Skip to main content

syncular_client/
lib.rs

1//! # syncular-client — Syncular v2 Rust client core (POC stage 2)
2//!
3//! A clean-room client implementation of the SPEC.md client-behavior
4//! contract on rusqlite local storage, consuming the committed `ssp2`
5//! codec as its wire layer. Built without reading the v1 Rust tree or the
6//! v2 TypeScript client — the conformance catalog (packages/conformance)
7//! is the proof that both cores implement one written protocol.
8//!
9//! Blocking hosts drive `sync()` / `sync_until_idle()`. Mailbox hosts prepare
10//! a round on the owner, run `PreparedSyncRound::exchange` on an I/O executor,
11//! and apply the result on the owner. A host without a blocking executor drives
12//! the same round through `PreparedSyncRound::next_operation` /
13//! `PreparedSyncRound::submit` / `PreparedSyncRound::finish`, performing every
14//! request with its own async I/O. An upload continuation repeats that
15//! exchange/apply cycle before the captured metadata request. The owner can
16//! serve local commands throughout; it queues inbound realtime traffic until
17//! the round completes. Scheduling is host policy (§8.4).
18
19pub mod api;
20#[cfg(feature = "bench-internals")]
21mod bench;
22pub mod client;
23/// §5.10.5 native CRDT helpers (the `crdt-yjs` feature) — the Rust face of the
24/// Yjs binding, mirroring `@syncular/crdt-yjs`. Off by default (dependency-lean).
25#[cfg(feature = "crdt-yjs")]
26pub mod crdt;
27/// Shared blocking HTTP/WebSocket host transport for Rust-backed bindings.
28/// The network stack is feature-gated; its no-network shape remains available
29/// in dependency-lean builds so host code needs only one transport type.
30pub mod native_transport;
31mod progress;
32mod round;
33pub use progress::{
34    ProgressObserver, ProgressPhase, ProgressState, ProgressSubscription, SyncProgress,
35    SyncProgressListener,
36};
37pub use round::{
38    AppliedSyncRound, CompletedSyncRound, PreparedSyncRound, RoundOperation, RoundReply,
39};
40/// RFC 0005 previous-version context: the persisted schema descriptor, the
41/// bounded capture, and the sibling container FILE beside the replica.
42pub mod previous_version;
43pub mod query_guard;
44pub mod realtime_round;
45pub mod remote;
46pub mod schema;
47pub mod transport;
48pub mod values;
49
50/// Browser-worker crash recovery for the installed OPFS VFS.
51#[cfg(any(test, all(target_arch = "wasm32", target_os = "unknown")))]
52mod wasm_vfs;
53
54/// Wall-clock milliseconds since the Unix epoch, the one clock this crate
55/// reads for every timestamp it records. `wasm32-unknown-unknown` runs in a JS
56/// host where `SystemTime::now()` panics, so that target reads the host clock.
57#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
58pub(crate) fn wall_clock_ms() -> i64 {
59    js_sys::Date::now() as i64
60}
61
62/// Wall-clock milliseconds since the Unix epoch, the one clock this crate
63/// reads for every timestamp it records. A host clock set before 1970 is a
64/// broken host, not a value to clamp.
65#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
66pub(crate) fn wall_clock_ms() -> i64 {
67    std::time::SystemTime::now()
68        .duration_since(std::time::UNIX_EPOCH)
69        .expect("system clock predates Unix epoch")
70        .as_millis() as i64
71}
72
73pub use api::{
74    creation_time_bucket, last, AuthorityReadDeclaration, ClientChangeBatch, ClientDiagnosticsHost,
75    ClientDiagnosticsLease, ClientDiagnosticsReplica, ClientDiagnosticsRequest,
76    ClientDiagnosticsSchema, ClientDiagnosticsSnapshot, ClientDiagnosticsStorage, ClientError,
77    ClientLimits, CommandEffects, CommitDelivery, CommitOperation, CommitOperationOutcome,
78    CommitOutcome, CommitOutcomeQuery, CommitOutcomeResolution, CommitOutcomeStatus,
79    ConflictRecord, CoverageSnapshot, CurrentBaseProof, CurrentBaseProofReason,
80    DiagnosticLastChange, DiagnosticLastRound, DiagnosticQueryFailure, DiagnosticRoundCounters,
81    DiagnosticSubscription, ExpectedDiagnosticSubscription, FetchedBlob, LocalDataPurgeInput,
82    LocalDataPurgeResult, LocalDataPurgeTarget, LocalDataRebootstrapInput,
83    LocalDataRebootstrapResult, Mutation, PresencePeer, QueryOwner, QueryReadFailure, QueryRow,
84    QuerySnapshot, QueryValue, RealtimePolicy, RealtimeState, RejectionRecord,
85    ResolveCommitOutcomeInput, RetainedCommitRow, RetainedUniqueConflict, RowState, SchemaFloor,
86    SnapshotRead, SubscriptionCatchup, SubscriptionRequest, SubscriptionStateView, SyncIntent,
87    SyncOutcome, SyncReport, SyncStatusSnapshot, TableChange, TimeBucketUnit, TransportCauseKind,
88    WindowBase, WindowChange, WindowCoverage, WindowState, WindowUnitRef,
89    CLIENT_DIAGNOSTICS_VERSION, LOCAL_AUTHORITY_UNCONFIGURED_CODE,
90    MAX_DIAGNOSTIC_EXPECTED_SUBSCRIPTIONS, MAX_DIAGNOSTIC_QUERY_FAILURES, REALTIME_LOST_CODE,
91    REALTIME_UNAVAILABLE_CODE,
92};
93pub use client::{
94    CurrentBasePreparation, FileQuerySnapshotReader, SnapshotReadRequest, SnapshotStatement,
95    SyncClient, SECURITY_PREFLIGHT_REQUIRED_CODE,
96};
97pub use schema::{compile_schema, parse_schema_json, ClientSchema};
98pub use transport::{
99    BlobDownload, BlobUploadGrant, SegmentFetch, SegmentRequest, Transport, TransportError,
100};
101
102// Re-export the SSP2 stream scanner (§8.7 round-response reassembly) so the
103// native transports (FFI + Tauri plugin) reach it through their existing
104// `syncular-client` dependency, without each adding a direct `ssp2` path dep.
105pub use realtime_round::{RealtimeRound, RoundInbound, REALTIME_TAG_DELTA, REALTIME_TAG_ROUND};
106pub use remote::{
107    PreparedRemoteCommit, RemoteBytes, RemoteClientError, RemoteCommandResult, RemoteCommitInput,
108    RemoteCommitResult, RemoteQueryResult, SyncRemoteClient,
109};
110pub use ssp2::{MessageStreamScanner, ScannedMessage};