This commit is contained in:
2026-09-17 11:13:13 +07:00
parent fd39be0eda
commit fe2d956d40
13 changed files with 507 additions and 1391 deletions
+10 -22
View File
@@ -44,8 +44,7 @@ pub enum ChatError {
MissingTag(&'static str),
DuplicateTag(&'static str),
BadTag(&'static str),
/// A delete is a tombstone and a timer notice documents the policy, so
/// neither may be erased by the policy it carries.
/// Neither a delete nor a timer notice may be erased by the policy it carries.
ExemptExpiration,
}
@@ -73,16 +72,14 @@ impl From<StreamError> for ChatError {
}
}
/// A chat event another chat event refers to: a quote, a comment's parent, a
/// reaction's target. The author slot is a SHOULD on the wire, so it is optional.
/// A chat event another chat event refers to: a quote, a comment's parent, a reaction's target.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReplyRef {
pub id: EventId,
pub author: Option<PublicKey>,
}
/// A reference that also names the referenced event's kind, which a comment
/// (`K`/`k`) and a reaction (`k`) must commit on the wire.
/// A reference that also names the referenced event's kind, which `K`/`k` must commit on the wire.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Target {
pub reply: ReplyRef,
@@ -166,8 +163,7 @@ pub fn build_message(
build_rumor_ms(KIND_MESSAGE, author, content, tags, at_ms)
}
/// A NIP-22 comment. `parent` is the immediate parent and `root` the thread's
/// immutable root; `None` means the parent is itself the root.
/// `parent` is the immediate parent; a `None` root means the parent is the thread's root.
#[allow(clippy::too_many_arguments)]
pub fn build_comment(
author: PublicKey,
@@ -238,8 +234,7 @@ pub fn build_edit(
build_rumor_ms(KIND_EDIT, author, content, tags, at_ms)
}
/// CORD-08 §4: an informational row in the timeline, gated by the roster rather
/// than by the fold, so it is built like any other chat rumor.
/// CORD-08 §4: informational, gated by the roster rather than by the fold.
pub fn build_timer_notice(
author: PublicKey,
channel: &ChannelId,
@@ -253,8 +248,7 @@ pub fn build_timer_notice(
build_rumor_ms(KIND_TIMER_NOTICE, author, "", tags, at_ms)
}
/// The tag is derived from the rumor's own signed `created_at`, so a later
/// metadata edit can never reach back into history.
/// Derived from the signed `created_at`, so a later metadata edit never reaches back.
fn expiration_tag(at_ms: u64, timer: Option<u64>) -> Option<Tag> {
timer.map(|timer| Tag::custom(TAG_EXPIRATION, [(at_ms / 1000 + timer).to_string()]))
}
@@ -297,8 +291,7 @@ pub fn build_typing(
)
}
/// Seals a chat rumor and wraps it at the channel's address. `ephemeral` picks
/// the 21059 wrap, which relays must not store.
/// `ephemeral` picks the 21059 wrap, which relays must not store.
pub fn seal_rumor(
rumor: &UnsignedEvent,
group: &GroupKey,
@@ -318,8 +311,7 @@ pub fn seal_rumor(
KIND_WRAP
};
// CORD-08 §2: a NIP-40 expiration rides the wrap as well, so relays drop the
// stored event on schedule; the inner copy is what drives a local purge.
// The wrap's copy is for relays; the inner one drives the local purge.
let expiration: Vec<Tag> = rumor
.tags
.iter()
@@ -336,9 +328,7 @@ pub fn seal_rumor(
)?)
}
/// Opens a wrap against the plane whose key is tried. The channel and epoch the
/// rumor claims must both be the ones that opened it, so a keyholder of two
/// planes cannot re-seal a rumor elsewhere or replay it across an epoch.
/// The claimed channel and epoch must both be the ones that opened the wrap.
pub fn open(
wrap: &Event,
group: &GroupKey,
@@ -358,9 +348,7 @@ pub fn open(
Ok((opened, chat))
}
/// Every epoch's group key for one channel. `secret` is whatever feeds the
/// channel at that epoch: the `community_root` for a public one, its own key
/// for a private one.
/// `secret` is the `community_root` for a public channel, its own key for a private one.
pub fn plane_keys(
held: &[(Epoch, [u8; 32])],
channel: &ChannelId,