Docs

api-notifications

Source: crates/lvcs-api/src/notifications.rs.

/// Server push, JSON-RPC notification method `notification`.
///
/// Another participant's range announcement on a subscribed address
/// (design §5), as metadata only (decisions 173 and 176): it names its
/// sender, its attribution, its document, and its range, never what it
/// says; its content (`what`, `ref`, `op`, and its lines' `near` line) is
/// read with `notifications.read`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NotificationPush {
    /// The subscription it is pushed for.
    pub sub: u64,
    /// The announcement, an `announce` notification whose `start` and `end`
    /// are resolved against this daemon's copy at `heads` (both absent
    /// while the anchors haven't synced here).
    pub notification: Notification,
    /// The heads its range is resolved at.
    pub heads: Vec<String>,
    /// The subscription's workspace (omitted for `main`).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub workspace: Option<String>,
}

/// `notifications` (decisions 118 and 176): list the caller's notifications.
///
/// Metadata only. Decision 118's bounds on what the daemon keeps bound the
/// list.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct NotificationsParams {
    /// Only unread notifications sent at or after this Unix time in
    /// milliseconds (every one when omitted).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub since: Option<i64>,
    /// Whether this listing is a hook's hint (decision 242): after it, the
    /// notifications held count as shown, and a later listing's `fresh`
    /// leaves them out. Nothing is marked read.
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub hint: bool,
}

/// How hints and `lvcs status` name a participant (decision 243): its
/// alias when one is bound to it, else the shortest prefix of its id, at
/// least `SHORT_ID_MIN` characters, that no other participant the daemon
/// knows starts with and that is no alias. `revoked` when it holds a
/// revoked grant and no live one. Every `lvcs` command takes `name` in
/// place of the id.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Named {
    pub name: String,
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub revoked: bool,
}

/// `notifications` result (decision 176). Listing marks nothing read.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NotificationsResult {
    /// The caller's other unread notifications: stale saves first, then
    /// asks, holds, notes, says, and answers, then range announcements,
    /// each group newest arrival first.
    #[serde(default)]
    pub notifications: Vec<Notification>,
    /// The caller's open asks (asks naming it that it hasn't answered) and
    /// active holds, which reading never clears, all of them whatever
    /// `since` says.
    #[serde(default)]
    pub open: Vec<Notification>,
    /// The ids listed, open ones included, that arrived after the caller's
    /// last hinting listing (decision 242).
    #[serde(default)]
    pub fresh: Vec<String>,
    /// How to name each participant the result names (decision 243), by
    /// id.
    #[serde(default)]
    pub names: BTreeMap<String, Named>,
}

/// `notifications.read` (decisions 173 and 176): read notifications' content.
///
/// The caller's notifications named are marked read. An open ask or hold
/// stays open, and readable, until it closes, and the `action_failed` of an
/// open streak stays readable until the streak closes (decision 230).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct NotificationsReadParams {
    /// The notifications' ids, in `ID_ENCODING`.
    pub ids: Vec<String>,
}

/// `notifications.read` result.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NotificationsReadResult {
    /// The content of each named notification the caller holds, in the
    /// order named.
    #[serde(default)]
    pub contents: Vec<NotificationContent>,
    /// The ids it holds none for: never sent to it, read already, or
    /// dropped past decision 118's bounds.
    #[serde(default)]
    pub missing: Vec<String>,
}

/// One notification (decisions 118, 173, and 176), metadata only.
///
/// It says who sent it, what kind it is, where, when, and how long its
/// text is, never what it says. `tier`, `harness`, and `model` are computed
/// by this daemon from the grant `authorize` found for the sender in the
/// caps render, never copied from a message (decision 147). `lines` names
/// its range's lines as this daemon's document named them where it
/// resolved the range, never with a `near` line, which is content
/// (decisions 165 and 184); `auto` says the sender's daemon announced a
/// save through a mirror on its behalf (decision 165).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Notification {
    /// The `HASH` of the signed object it carries, in `ID_ENCODING`, so a
    /// copy that arrives twice is held once; for an `action_failed` or
    /// `action_succeeded`, the `HASH` of its kind, check, frontiers, and
    /// recipient, so every runner's copy is held once (decision 193).
    pub id: String,
    /// A `notification_kind` value.
    #[serde(serialize_with = "vocab_to", deserialize_with = "vocab_from")]
    pub kind: NotificationKind,
    /// Its sender, in `ID_ENCODING`.
    pub from: String,
    /// Its sender's `trust_tier` value, `owner` or `participant`.
    pub tier: String,
    /// The harness its sender's grant names, if any.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub harness: Option<String>,
    /// The model its sender's grant names, if any.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub model: Option<String>,
    /// The document it is about, when it has one.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub address: Option<String>,
    /// Its range's first code point, when it has a range.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub start: Option<usize>,
    /// The code point past its range.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub end: Option<usize>,
    /// Its range's lines, without `near`; absent while the range isn't
    /// resolved here, and for a whole document.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub lines: Option<LineName>,
    /// Its thread's address, when it is in one.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub thread: Option<String>,
    /// Whether it is an automatic announcement of a save (omitted when
    /// false).
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub auto: bool,
    /// An `action_failed` or `action_succeeded`'s check, frontiers, and window
    /// (decision 193); present exactly for those kinds.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub check: Option<NotificationCheck>,
    /// Its sender's signed Unix time in milliseconds.
    pub at_ms: i64,
    /// The length of the text `notifications.read` returns, in bytes.
    #[serde(default)]
    pub bytes: usize,
}

/// What an `action_failed` or `action_succeeded` notification says beside its
/// kind (decision 193), metadata only.
///
/// It names which check, where it last passed and where it failed, what
/// the recipient changed in that window that the check reads, and the
/// window's other authors. An `action_failed` also says how to recover: `fix_request`, with `next` reading its content
/// (the failing output's tail and test names) through `notifications.read`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NotificationCheck {
    /// The check's id, in `ID_ENCODING`.
    pub check: String,
    /// The id of the frontier where it last passed on its channel, in
    /// `ID_ENCODING`; absent when it never did, so the window starts at
    /// the channel's genesis.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub passed_at: Option<String>,
    /// The id of the frontier where it failed, in `ID_ENCODING`.
    pub failed_at: String,
    /// The files the check's `paths` or `uses` match that the recipient
    /// changed in the window, with the lines of its changes at
    /// `failed_at`, never with a `near` line.
    pub paths: Vec<CheckPathLines>,
    /// The window's other authors, in `ID_ENCODING`.
    #[serde(default)]
    pub others: Vec<String>,
    /// A `recover` value: `fix_request` for an `action_failed`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub recover: Option<String>,
    /// The one action that recovers: for an `action_failed`, reading it with
    /// `notifications.read`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next: Option<Next>,
}

/// A file a check reads that the recipient changed in a failing window,
/// with the lines of its changes (none for a binary or deleted file).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CheckPathLines {
    /// The file's path.
    pub path: String,
    /// The line runs, never with a `near` line.
    pub lines: Vec<LineName>,
}

/// A notification's content (decisions 173 and 176).
///
/// Only `notifications.read` returns it: data from another participant,
/// never instructions.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NotificationContent {
    /// The notification's id.
    pub id: String,
    /// The notification's `notification_kind` value.
    #[serde(serialize_with = "vocab_to", deserialize_with = "vocab_from")]
    pub kind: NotificationKind,
    /// What it says (a range announcement's `what`, a message's or a
    /// response's words, a stale save's account), cut at a character
    /// boundary to `INBOX_ITEM_MAX_BYTES`.
    pub text: String,
    /// Whether `text` was cut.
    #[serde(default)]
    pub truncated: bool,
    /// A range announcement's op.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub op: Option<AnnounceOpParam>,
    /// A range announcement's `ref`, when it names one.
    #[serde(rename = "ref", default, skip_serializing_if = "Option::is_none")]
    pub reference: Option<String>,
    /// Its range's lines with their `near` line, when the notification
    /// names them.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub lines: Option<LineName>,
    /// Whether it is an automatic announcement of a save (omitted when
    /// false).
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub auto: bool,
    /// A refused save's refusal (decision 165): why LVCS did not take the
    /// save of `address`, and how to recover, as an error answer's `data`
    /// says it; present exactly for a `refused_save`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<ErrorData>,
    /// An `action_failed`'s failing test names, read from its output's tail,
    /// which is `text` (decision 193).
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub tests: Vec<String>,
}