Skip to content

Commit 75cab8c

Browse files
committed
Merge remote-tracking branch 'origin/main' into coda/passkeys
2 parents 3ccec12 + ea26c14 commit 75cab8c

18 files changed

+732
-47
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings_ffi/src/mls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ impl FfiConversation {
17831783
let direction = opts.direction.map(|dir| dir.into());
17841784
let kind = match self.conversation_type().await? {
17851785
FfiConversationType::Group => None,
1786-
FfiConversationType::Dm => Some(GroupMessageKind::Application),
1786+
FfiConversationType::Dm => None,
17871787
FfiConversationType::Sync => None,
17881788
};
17891789

bindings_node/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ tracing-subscriber = { workspace = true, features = [
3030
xmtp_api.workspace = true
3131
xmtp_api_grpc.workspace = true
3232
xmtp_common.workspace = true
33+
xmtp_content_types.workspace = true
3334
xmtp_cryptography.workspace = true
3435
xmtp_id.workspace = true
3536
xmtp_mls.workspace = true
3637
xmtp_proto = { workspace = true, features = ["proto_full"] }
37-
3838
[build-dependencies]
3939
napi-build = "2.0.1"
4040

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use napi_derive::napi;
2+
use xmtp_mls::storage::group_message::ContentType as XmtpContentType;
3+
4+
pub mod multi_remote_attachment;
5+
pub mod reaction;
6+
7+
#[napi]
8+
pub enum ContentType {
9+
Unknown,
10+
Text,
11+
GroupMembershipChange,
12+
GroupUpdated,
13+
Reaction,
14+
ReadReceipt,
15+
Reply,
16+
Attachment,
17+
RemoteAttachment,
18+
TransactionReference,
19+
}
20+
21+
impl From<ContentType> for XmtpContentType {
22+
fn from(value: ContentType) -> Self {
23+
match value {
24+
ContentType::Unknown => XmtpContentType::Unknown,
25+
ContentType::Text => XmtpContentType::Text,
26+
ContentType::GroupMembershipChange => XmtpContentType::GroupMembershipChange,
27+
ContentType::GroupUpdated => XmtpContentType::GroupUpdated,
28+
ContentType::Reaction => XmtpContentType::Reaction,
29+
ContentType::ReadReceipt => XmtpContentType::ReadReceipt,
30+
ContentType::Reply => XmtpContentType::Reply,
31+
ContentType::Attachment => XmtpContentType::Attachment,
32+
ContentType::RemoteAttachment => XmtpContentType::RemoteAttachment,
33+
ContentType::TransactionReference => XmtpContentType::TransactionReference,
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use napi::bindgen_prelude::{Result, Uint8Array};
2+
use napi_derive::napi;
3+
use prost::Message;
4+
use xmtp_content_types::multi_remote_attachment::MultiRemoteAttachmentCodec;
5+
use xmtp_content_types::ContentCodec;
6+
use xmtp_proto::xmtp::mls::message_contents::content_types::{
7+
MultiRemoteAttachment as XmtpMultiRemoteAttachment,
8+
RemoteAttachmentInfo as XmtpRemoteAttachmentInfo,
9+
};
10+
use xmtp_proto::xmtp::mls::message_contents::EncodedContent;
11+
12+
use crate::ErrorWrapper;
13+
14+
#[napi(object)]
15+
pub struct RemoteAttachmentInfo {
16+
pub secret: Uint8Array,
17+
pub content_digest: String,
18+
pub nonce: Uint8Array,
19+
pub scheme: String,
20+
pub url: String,
21+
pub salt: Uint8Array,
22+
pub content_length: Option<u32>,
23+
pub filename: Option<String>,
24+
}
25+
26+
impl From<RemoteAttachmentInfo> for XmtpRemoteAttachmentInfo {
27+
fn from(remote_attachment_info: RemoteAttachmentInfo) -> Self {
28+
XmtpRemoteAttachmentInfo {
29+
content_digest: remote_attachment_info.content_digest,
30+
secret: remote_attachment_info.secret.to_vec(),
31+
nonce: remote_attachment_info.nonce.to_vec(),
32+
salt: remote_attachment_info.salt.to_vec(),
33+
scheme: remote_attachment_info.scheme,
34+
url: remote_attachment_info.url,
35+
content_length: remote_attachment_info.content_length,
36+
filename: remote_attachment_info.filename,
37+
}
38+
}
39+
}
40+
41+
impl From<XmtpRemoteAttachmentInfo> for RemoteAttachmentInfo {
42+
fn from(remote_attachment_info: XmtpRemoteAttachmentInfo) -> Self {
43+
RemoteAttachmentInfo {
44+
secret: Uint8Array::from(remote_attachment_info.secret),
45+
content_digest: remote_attachment_info.content_digest,
46+
nonce: Uint8Array::from(remote_attachment_info.nonce),
47+
scheme: remote_attachment_info.scheme,
48+
url: remote_attachment_info.url,
49+
salt: Uint8Array::from(remote_attachment_info.salt),
50+
content_length: remote_attachment_info.content_length,
51+
filename: remote_attachment_info.filename,
52+
}
53+
}
54+
}
55+
56+
#[napi(object)]
57+
pub struct MultiRemoteAttachment {
58+
pub attachments: Vec<RemoteAttachmentInfo>,
59+
}
60+
61+
impl From<MultiRemoteAttachment> for XmtpMultiRemoteAttachment {
62+
fn from(multi_remote_attachment: MultiRemoteAttachment) -> Self {
63+
XmtpMultiRemoteAttachment {
64+
attachments: multi_remote_attachment
65+
.attachments
66+
.into_iter()
67+
.map(Into::into)
68+
.collect(),
69+
}
70+
}
71+
}
72+
73+
impl From<XmtpMultiRemoteAttachment> for MultiRemoteAttachment {
74+
fn from(multi_remote_attachment: XmtpMultiRemoteAttachment) -> Self {
75+
MultiRemoteAttachment {
76+
attachments: multi_remote_attachment
77+
.attachments
78+
.into_iter()
79+
.map(Into::into)
80+
.collect(),
81+
}
82+
}
83+
}
84+
85+
#[napi]
86+
pub fn encode_multi_remote_attachment(
87+
multi_remote_attachment: MultiRemoteAttachment,
88+
) -> Result<Uint8Array> {
89+
// Convert MultiRemoteAttachment to MultiRemoteAttachment
90+
let multi_remote_attachment: XmtpMultiRemoteAttachment = multi_remote_attachment.into();
91+
92+
// Use MultiRemoteAttachmentCodec to encode the attachments
93+
let encoded =
94+
MultiRemoteAttachmentCodec::encode(multi_remote_attachment).map_err(ErrorWrapper::from)?;
95+
96+
// Encode the EncodedContent to bytes
97+
let mut buf = Vec::new();
98+
encoded.encode(&mut buf).map_err(ErrorWrapper::from)?;
99+
100+
Ok(Uint8Array::from(buf))
101+
}
102+
103+
#[napi]
104+
pub fn decode_multi_remote_attachment(bytes: Uint8Array) -> Result<MultiRemoteAttachment> {
105+
// Decode bytes into EncodedContent
106+
let encoded_content =
107+
EncodedContent::decode(bytes.to_vec().as_slice()).map_err(ErrorWrapper::from)?;
108+
109+
// Use MultiRemoteAttachmentCodec to decode into MultiRemoteAttachment and convert to MultiRemoteAttachment
110+
MultiRemoteAttachmentCodec::decode(encoded_content)
111+
.map(Into::into)
112+
.map_err(|e| napi::Error::from_reason(e.to_string()))
113+
}
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use napi::bindgen_prelude::{Result, Uint8Array};
2+
use napi_derive::napi;
3+
use prost::Message;
4+
use xmtp_content_types::reaction::ReactionCodec;
5+
use xmtp_content_types::ContentCodec;
6+
use xmtp_proto::xmtp::mls::message_contents::content_types::ReactionV2;
7+
use xmtp_proto::xmtp::mls::message_contents::EncodedContent;
8+
9+
use crate::ErrorWrapper;
10+
11+
#[napi(object)]
12+
pub struct Reaction {
13+
pub reference: String,
14+
pub reference_inbox_id: String,
15+
pub action: ReactionAction,
16+
pub content: String,
17+
pub schema: ReactionSchema,
18+
}
19+
20+
impl From<Reaction> for ReactionV2 {
21+
fn from(reaction: Reaction) -> Self {
22+
ReactionV2 {
23+
reference: reaction.reference,
24+
reference_inbox_id: reaction.reference_inbox_id,
25+
action: reaction.action.into(),
26+
content: reaction.content,
27+
schema: reaction.schema.into(),
28+
}
29+
}
30+
}
31+
32+
impl From<ReactionV2> for Reaction {
33+
fn from(reaction: ReactionV2) -> Self {
34+
Reaction {
35+
reference: reaction.reference,
36+
reference_inbox_id: reaction.reference_inbox_id,
37+
action: match reaction.action {
38+
1 => ReactionAction::Added,
39+
2 => ReactionAction::Removed,
40+
_ => ReactionAction::Unknown,
41+
},
42+
content: reaction.content,
43+
schema: match reaction.schema {
44+
1 => ReactionSchema::Unicode,
45+
2 => ReactionSchema::Shortcode,
46+
3 => ReactionSchema::Custom,
47+
_ => ReactionSchema::Unknown,
48+
},
49+
}
50+
}
51+
}
52+
53+
#[napi]
54+
pub fn encode_reaction(reaction: Reaction) -> Result<Uint8Array> {
55+
// Convert Reaction to Reaction
56+
let reaction: ReactionV2 = reaction.into();
57+
58+
// Use ReactionCodec to encode the reaction
59+
let encoded = ReactionCodec::encode(reaction).map_err(ErrorWrapper::from)?;
60+
61+
// Encode the EncodedContent to bytes
62+
let mut buf = Vec::new();
63+
encoded.encode(&mut buf).map_err(ErrorWrapper::from)?;
64+
65+
Ok(Uint8Array::from(buf.as_slice()))
66+
}
67+
68+
#[napi]
69+
pub fn decode_reaction(bytes: Uint8Array) -> Result<Reaction> {
70+
// Decode bytes into EncodedContent
71+
let encoded_content =
72+
EncodedContent::decode(bytes.to_vec().as_slice()).map_err(ErrorWrapper::from)?;
73+
74+
// Use ReactionCodec to decode into Reaction and convert to Reaction
75+
ReactionCodec::decode(encoded_content)
76+
.map(Into::into)
77+
.map_err(|e| napi::Error::from_reason(e.to_string()))
78+
}
79+
80+
#[napi]
81+
#[derive(Default, PartialEq, Debug)]
82+
pub enum ReactionAction {
83+
Unknown,
84+
#[default]
85+
Added,
86+
Removed,
87+
}
88+
89+
impl From<ReactionAction> for i32 {
90+
fn from(action: ReactionAction) -> Self {
91+
match action {
92+
ReactionAction::Unknown => 0,
93+
ReactionAction::Added => 1,
94+
ReactionAction::Removed => 2,
95+
}
96+
}
97+
}
98+
99+
#[napi]
100+
#[derive(Default, PartialEq)]
101+
pub enum ReactionSchema {
102+
Unknown,
103+
#[default]
104+
Unicode,
105+
Shortcode,
106+
Custom,
107+
}
108+
109+
impl From<ReactionSchema> for i32 {
110+
fn from(schema: ReactionSchema) -> Self {
111+
match schema {
112+
ReactionSchema::Unknown => 0,
113+
ReactionSchema::Unicode => 1,
114+
ReactionSchema::Shortcode => 2,
115+
ReactionSchema::Custom => 3,
116+
}
117+
}
118+
}

bindings_node/src/conversation.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
conversations::{HmacKey, MessageDisappearingSettings},
2323
encoded_content::EncodedContent,
2424
identity::{Identifier, IdentityExt},
25-
message::{ListMessagesOptions, Message},
25+
message::{ListMessagesOptions, Message, MessageWithReactions},
2626
permissions::{GroupPermissions, MetadataField, PermissionPolicy, PermissionUpdateType},
2727
streams::StreamCloser,
2828
ErrorWrapper,
@@ -190,6 +190,42 @@ impl Conversation {
190190
Ok(messages)
191191
}
192192

193+
#[napi]
194+
pub async fn find_messages_with_reactions(
195+
&self,
196+
opts: Option<ListMessagesOptions>,
197+
) -> Result<Vec<MessageWithReactions>> {
198+
let opts = opts.unwrap_or_default();
199+
let group = MlsGroup::new(
200+
self.inner_client.clone(),
201+
self.group_id.clone(),
202+
self.created_at_ns,
203+
);
204+
let provider = group.mls_provider().map_err(ErrorWrapper::from)?;
205+
let conversation_type = group
206+
.conversation_type(&provider)
207+
.await
208+
.map_err(ErrorWrapper::from)?;
209+
let kind = match conversation_type {
210+
ConversationType::Group => None,
211+
ConversationType::Dm => None,
212+
ConversationType::Sync => None,
213+
};
214+
let opts = MsgQueryArgs {
215+
kind,
216+
..opts.into()
217+
};
218+
219+
let messages: Vec<MessageWithReactions> = group
220+
.find_messages_with_reactions(&opts)
221+
.map_err(ErrorWrapper::from)?
222+
.into_iter()
223+
.map(Into::into)
224+
.collect();
225+
226+
Ok(messages)
227+
}
228+
193229
#[napi]
194230
pub async fn process_streamed_group_message(
195231
&self,

bindings_node/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
pub mod client;
55
mod consent_state;
6+
pub mod content_types;
67
mod conversation;
78
mod conversations;
89
mod encoded_content;

0 commit comments

Comments
 (0)