From 649912aebb753eadaa30f4813ea8ad46f5b2bf7b Mon Sep 17 00:00:00 2001 From: Ry Racherbaumer Date: Wed, 11 Sep 2024 15:26:07 -0500 Subject: [PATCH] Update node bindings (#1053) * Add inbox_state to client * Refactor create_group to use create_group_with_members * Bump node bindings version and update CHANGELOG --- bindings_node/CHANGELOG.md | 5 ++++ bindings_node/package.json | 2 +- bindings_node/src/conversations.rs | 24 ++++++++++------- bindings_node/src/mls_client.rs | 41 +++++++++++++++++++++++++++++- bindings_node/test/Client.test.ts | 12 +++++++++ 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index c143fedf2..3bc0347e1 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,10 @@ # @xmtp/mls-client-bindings-node +## 0.0.11 + +- Added `inbox_state` to client +- Skip duplicate message processing when streaming + ## 0.0.10 - Fixed several group syncing issues diff --git a/bindings_node/package.json b/bindings_node/package.json index 429a798c7..d4d65789f 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/mls-client-bindings-node", - "version": "0.0.10", + "version": "0.0.11", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 21a5dae60..3928c36f0 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -20,6 +20,7 @@ pub struct NapiListConversationsOptions { } #[napi(object)] +#[derive(Clone)] pub struct NapiCreateGroupOptions { pub permissions: Option, pub group_name: Option, @@ -77,16 +78,21 @@ impl NapiConversations { _ => None, }; - let convo = self - .inner_client - .create_group(group_permissions, options.into_group_metadata_options()) - .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))?; - if !account_addresses.is_empty() { - convo - .add_members(&self.inner_client, account_addresses) + let metadata_options = options.clone().into_group_metadata_options(); + + let convo = if account_addresses.is_empty() { + self + .inner_client + .create_group(group_permissions, metadata_options) + .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? + } else { + self + .inner_client + .create_group_with_members(account_addresses, group_permissions, metadata_options) .await - .map_err(|e| Error::from_reason(format!("GroupError: {}", e)))?; - } + .map_err(|e| Error::from_reason(format!("ClientError: {}", e)))? + }; + let out = NapiGroup::new( self.inner_client.clone(), convo.group_id, diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index 43385b79d..236f5c494 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -6,8 +6,8 @@ use std::ops::Deref; use std::sync::Arc; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; -use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; use xmtp_id::associations::unverified::UnverifiedSignature; +use xmtp_id::associations::{generate_inbox_id as xmtp_id_generate_inbox_id, AssociationState}; use xmtp_id::associations::{AccountId, MemberIdentifier}; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; @@ -18,6 +18,29 @@ use xmtp_mls::Client as MlsClient; pub type RustXmtpClient = MlsClient; +#[napi(object)] +pub struct NapiInboxState { + pub inbox_id: String, + pub recovery_address: String, + pub installation_ids: Vec, + pub account_addresses: Vec, +} + +impl From for NapiInboxState { + fn from(state: AssociationState) -> Self { + Self { + inbox_id: state.inbox_id().to_string(), + recovery_address: state.recovery_address().to_string(), + installation_ids: state + .installation_ids() + .into_iter() + .map(|id| ed25519_public_key_to_address(id.as_slice())) + .collect(), + account_addresses: state.account_addresses(), + } + } +} + #[napi] pub struct NapiClient { inner_client: Arc, @@ -273,4 +296,20 @@ impl NapiClient { Ok(inbox_id) } + + /** + * Get the client's inbox state. + * + * If `refresh_from_network` is true, the client will go to the network first to refresh the state. + * Otherwise, the state will be read from the local database. + */ + #[napi] + pub async fn inbox_state(&self, refresh_from_network: bool) -> Result { + let state = self + .inner_client + .inbox_state(refresh_from_network) + .await + .map_err(|e| Error::from_reason(format!("{}", e)))?; + Ok(state.into()) + } } diff --git a/bindings_node/test/Client.test.ts b/bindings_node/test/Client.test.ts index 6b97f8c80..350753292 100644 --- a/bindings_node/test/Client.test.ts +++ b/bindings_node/test/Client.test.ts @@ -31,4 +31,16 @@ describe('Client', () => { const inboxId = await client.findInboxIdByAddress(user.account.address) expect(inboxId).toBe(client.inboxId()) }) + + it('should return the correct inbox state', async () => { + const user = createUser() + const client = await createRegisteredClient(user) + const inboxState = await client.inboxState(false) + expect(inboxState.inboxId).toBe(client.inboxId()) + expect(inboxState.installationIds).toEqual([client.installationId()]) + expect(inboxState.accountAddresses).toEqual([ + user.account.address.toLowerCase(), + ]) + expect(inboxState.recoveryAddress).toBe(user.account.address.toLowerCase()) + }) })