Skip to main content

New features

Encrypted reactions in Community Announcement Groups Client::send_reaction now transparently detects Community Announcement Groups (CAG — the default announcement subgroup of a community) and encrypts the reaction before sending. No API change is needed; the same call works for DMs, regular groups, and CAGs:
// Works identically for DMs, regular groups, and CAGs.
client.send_reaction(&cag_jid, target_key, "🔥").await?;
For a CAG chat the library checks GroupInfo::is_community_announce (cached from group metadata). When true, the reaction emoji and timestamp are encrypted with the target post’s messageSecret under the "Enc Reaction" HKDF use-case and shipped as an enc_reaction_message envelope — matching WA Web’s WAWebReactionEncryptMsgData flow. If the parent secret was not captured (message received before session started, or msg_secret_policy disabled without a resolver) the call fails with a descriptive error rather than silently emitting a plaintext reaction the channel would reject. Incoming encrypted reactions are decrypted transparently by the receive path and dispatched in the same plaintext reaction_message shape as an ordinary group reaction. The key field is filled from the envelope’s target_message_key so event handlers require no changes.
Channel comments via client.comments() A new Comments feature handle lets you post encrypted threaded replies under a CAG post. Comments require the parent post’s messageSecret (captured during receive) and are authored under the LID identity, matching WA Web’s getMeLidUserOrThrow:
let parent_key = wa::MessageKey {
    remote_jid: Some(cag_jid.to_string()),
    from_me: Some(false),
    id: Some("3EB0POSTID".to_string()),
    // Must be the post author so receivers can derive the HKDF key.
    participant: Some(post_author_jid.to_string()),
};

// Text comment (extended_text_message body)
let result = client.comments()
    .send_text(&cag_jid, parent_key.clone(), "Great post!")
    .await?;

// Arbitrary message body
let body = wa::Message {
    extended_text_message: Some(Box::new(wa::message::ExtendedTextMessage {
        text: Some("Great post!".to_string()),
        ..Default::default()
    })),
    ..Default::default()
};
let result = client.comments()
    .send_message(&cag_jid, parent_key, body)
    .await?;
The comment carries a fresh messageSecret of its own so it can receive encrypted reactions. Both the comment body secret and the parent-post secret are persisted under the correct ids. Incoming encrypted comments are decrypted transparently. The decrypted body is dispatched as a normal Event::Message. The parent post key surfaces on the new MessageInfo::comment_target field, since the inner Message proto has no slot for the threading link:
Event::Message(msg, info) => {
    if let Some(parent_key) = &info.comment_target {
        println!("Comment on post: {:?}", parent_key.id);
        if let Some(text) = msg.text_content() {
            println!("Comment text: {}", text);
        }
    }
}
The comment’s own messageSecret (from the outer envelope) is persisted under the comment’s id and sender so that future encrypted reactions to the comment can be decrypted.

Breaking changes

Pre-1.0, additive surface. The following structs and enums gain new fields/variants. If you construct them with exhaustive struct-literal syntax (without ..Default::default()), add the new fields: MessageInfo gains comment_target: Option<wa::MessageKey>:
// Add the field or use ..Default::default():
let info = MessageInfo {
    id: "...".to_string(),
    // ...
    peer_recipient_pn: None,
    comment_target: None,   // new
    bcl_participants: vec![],
};
GroupInfo gains is_community_announce: Option<bool>. Blobs persisted before this field was added will deserialize with None (“unknown”) and trigger one metadata re-query when the value is first needed. No migration is required — existing serialized blobs remain valid. SecretEncKind gains two variants that must be covered in exhaustive match arms:
  • SecretEncKind::EncReaction — an enc_reaction_message envelope
  • SecretEncKind::EncComment — an enc_comment_message envelope