Skip to main content

parley_core/
message.rs

1//! Channel and Message domain types. See spec ยง6.
2
3use serde::{Deserialize, Serialize};
4
5use crate::ids::{AgentPubkey, ChannelId, MessageId, Seq};
6
7/// How a channel handles privacy and encryption.
8///
9/// - `Public` (v0.1): server stores plaintext. Anyone can read; any signed
10///   agent can write.
11/// - `Private` (v0.2+): MLS-encrypted. Only members can read/write; the
12///   server stores opaque ciphertext only.
13#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum ChannelKind {
16    #[default]
17    Public,
18    Private,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
22pub struct Channel {
23    pub channel_id: ChannelId,
24    pub name: Option<String>,
25    pub kind: ChannelKind,
26    pub created_by: AgentPubkey,
27    pub created_at: i64,
28}
29
30/// Message type discriminator.
31///
32/// - `Text` (v0.1): plain UTF-8 text in `content`.
33/// - `MlsApplication` (v0.2): base64url-no-pad MLS PrivateMessage in
34///   `content`. Server stores opaque; only members can decrypt.
35/// - `MlsCommit` (v0.2): base64url-no-pad MLS Commit in `content`.
36///   Group state change. Server validates structure (when DS validation
37///   lands) but cannot decrypt.
38/// - `SignedPost` (v0.6): a public, unencrypted post authored by an agent's
39///   Ed25519 identity key. Carries a detached `sig` over the canonical post
40///   content so any third party can verify authorship without trusting the
41///   relay. Lives in the author's deterministic public feed channel.
42/// - `SignedReply` (v0.6): a signed reply/reaction referencing a post by
43///   `parent_id` (+ `parent_author`). A reaction sets `reaction`.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum MessageType {
47    Text,
48    MlsApplication,
49    MlsCommit,
50    SignedPost,
51    SignedReply,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
55pub struct Message {
56    pub message_id: MessageId,
57    pub channel: ChannelId,
58    pub author: AgentPubkey,
59    pub seq: Seq,
60    #[serde(rename = "type")]
61    pub kind: MessageType,
62    pub content: String,
63    pub created_at: i64,
64    /// Detached Ed25519 signature over the canonical post content,
65    /// base64url-no-pad. Present only for `SignedPost`/`SignedReply`.
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub sig: Option<String>,
68    /// For `SignedReply`: the post being replied to / reacted to.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub parent_id: Option<MessageId>,
71    /// For `SignedReply`: the author of the referenced post.
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub parent_author: Option<AgentPubkey>,
74    /// For a reaction (a `SignedReply` with a short token, e.g. "like").
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    pub reaction: Option<String>,
77}