nodedb_types/sync/wire/delta.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! Delta push / ack / reject / collection-purged messages.
4
5use serde::{Deserialize, Serialize};
6
7use crate::sync::compensation::CompensationHint;
8use crate::sync::wire::ack_status::AckStatus;
9
10/// Delta push message (client → server, 0x10).
11#[derive(
12 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
13)]
14pub struct DeltaPushMsg {
15 /// Collection the delta applies to.
16 pub collection: String,
17 /// Document ID.
18 pub document_id: String,
19 /// Loro CRDT delta bytes.
20 pub delta: Vec<u8>,
21 /// Client's peer ID (for CRDT identity).
22 pub peer_id: u64,
23 /// Per-mutation unique ID for dedup.
24 pub mutation_id: u64,
25 /// CRC32C checksum of `delta` bytes for integrity verification.
26 /// Computed by sender, validated by receiver. 0 for legacy clients.
27 #[serde(default)]
28 pub checksum: u32,
29 /// Device-assigned valid-time for the mutation (ms since Unix epoch).
30 ///
31 /// Populated by offline-capable clients so Origin can preserve the
32 /// application's notion of "when did this fact take effect" independently
33 /// of the Origin-assigned `system_from_ms`. `None` means the client did
34 /// not supply a valid-time — Origin will use `system_from_ms` as the
35 /// default valid-from.
36 #[serde(default)]
37 pub device_valid_time_ms: Option<i64>,
38 /// Stable identity of the originating producer (Lite peer ID or Origin node ID).
39 /// 0 for legacy / pre-idempotency clients.
40 #[serde(default)]
41 pub producer_id: u64,
42 /// Monotonic epoch counter incremented on every producer restart.
43 /// 0 for legacy / pre-idempotency clients.
44 #[serde(default)]
45 pub epoch: u64,
46 /// Per-stream monotonic sequence number within the epoch.
47 /// 0 for legacy / pre-idempotency clients.
48 #[serde(default)]
49 pub seq: u64,
50}
51
52/// Delta acknowledgment (server → client, 0x11).
53#[derive(
54 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
55)]
56pub struct DeltaAckMsg {
57 /// Mutation ID being acknowledged.
58 pub mutation_id: u64,
59 /// Server-assigned LSN for this mutation.
60 pub lsn: u64,
61 /// Absolute clock-skew between `device_valid_time_ms` and the Origin
62 /// wall clock at commit, in milliseconds. `None` when the client did
63 /// not supply a device valid-time, or when skew was within tolerance
64 /// (≤ 24h). Populated so clients can surface a warning UX.
65 #[serde(default)]
66 pub clock_skew_warning_ms: Option<i64>,
67 /// Highest sequence number from this producer that has been durably applied.
68 /// 0 when the server has not yet recorded a sequence for this producer.
69 #[serde(default)]
70 pub applied_seq: u64,
71 /// Idempotency outcome of the acknowledged message.
72 #[serde(default)]
73 pub status: AckStatus,
74}
75
76/// Delta rejection (server → client, 0x12).
77#[derive(
78 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
79)]
80pub struct DeltaRejectMsg {
81 /// Mutation ID being rejected.
82 pub mutation_id: u64,
83 /// Reason for rejection.
84 pub reason: String,
85 /// Compensation hints for the client.
86 pub compensation: Option<CompensationHint>,
87}
88
89/// Collection purged notification (server → client, 0x14).
90///
91/// Emitted when Origin hard-deletes a collection (retention window
92/// expired after `DROP COLLECTION` or explicit `DROP COLLECTION ... PURGE`).
93/// The receiving Lite client must:
94///
95/// 1. Drop all local Loro CRDT state for the collection.
96/// 2. Remove the collection's redb record.
97/// 3. Terminate any active shape subscriptions or streaming consumers
98/// sourced from the collection.
99/// 4. Fire the `on_collection_purged` client-trait callback.
100///
101/// `purge_lsn` is the Origin WAL LSN at which the hard-delete committed.
102/// Clients persist it so that on reconnect they can replay any purge
103/// events that landed while they were offline by querying
104/// `_system.dropped_collections` / purge event log at LSN > last_seen.
105#[derive(
106 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
107)]
108pub struct CollectionPurgedMsg {
109 /// Numeric tenant ID the collection belonged to.
110 pub tenant_id: u64,
111 /// Collection name.
112 pub name: String,
113 /// Origin WAL LSN at which the hard-delete was committed.
114 pub purge_lsn: u64,
115}