@@ -3438,6 +3438,39 @@ async fn add_mls_member_device(
34383438 . map_err ( |e| format ! ( "Task join error: {}" , e) ) ?
34393439}
34403440
3441+ /// Invite a new member to an existing MLS group
3442+ /// Similar to create_group_chat, this refreshes the member's keypackages and adds them to the group
3443+ #[ tauri:: command]
3444+ async fn invite_member_to_group (
3445+ group_id : String ,
3446+ member_npub : String ,
3447+ ) -> Result < ( ) , String > {
3448+ // Refresh keypackages for the new member
3449+ let devices = refresh_keypackages_for_contact ( member_npub. clone ( ) ) . await . map_err ( |e| {
3450+ format ! ( "Failed to refresh device keypackage for {}: {}" , member_npub, e)
3451+ } ) ?;
3452+
3453+ // Choose the first device (same policy as group creation)
3454+ let ( device_id, _kp_ref) = devices
3455+ . into_iter ( )
3456+ . next ( )
3457+ . ok_or_else ( || format ! ( "No device keypackages found for {}" , member_npub) ) ?;
3458+
3459+ // Run non-Send MLS engine work on a blocking thread
3460+ tokio:: task:: spawn_blocking ( move || {
3461+ let handle = TAURI_APP . get ( ) . ok_or ( "App handle not initialized" ) ?. clone ( ) ;
3462+ let rt = tokio:: runtime:: Handle :: current ( ) ;
3463+ rt. block_on ( async move {
3464+ let mls = MlsService :: new_persistent ( & handle) . map_err ( |e| e. to_string ( ) ) ?;
3465+ mls. add_member_device ( & group_id, & member_npub, & device_id)
3466+ . await
3467+ . map_err ( |e| e. to_string ( ) )
3468+ } )
3469+ } )
3470+ . await
3471+ . map_err ( |e| format ! ( "Task join error: {}" , e) ) ?
3472+ }
3473+
34413474/// Remove a member device from an MLS group
34423475#[ tauri:: command]
34433476async fn remove_mls_member_device (
@@ -3643,8 +3676,8 @@ async fn accept_mls_welcome(welcome_event_id_hex: String) -> Result<bool, String
36433676 let nostr_group_id_bytes = welcome. nostr_group_id . clone ( ) ;
36443677 let group_name = welcome. group_name . clone ( ) ;
36453678 let welcomer_hex = welcome. welcomer . to_hex ( ) ;
3646- let wrapper_id_hex = welcome. wrapper_event_id . to_hex ( ) ;
3647-
3679+ let wrapper_event_id_hex = welcome. wrapper_event_id . to_hex ( ) ;
3680+
36483681 // Accept the welcome - this updates engine state internally
36493682 engine. accept_welcome ( & welcome) . map_err ( |e| e. to_string ( ) ) ?;
36503683
@@ -3689,7 +3722,7 @@ async fn accept_mls_welcome(welcome_event_id_hex: String) -> Result<bool, String
36893722 println ! ( "[MLS] - engine_group_id: {}" , engine_group_id) ;
36903723 println ! ( "[MLS] - group_name: {}" , group_name) ;
36913724
3692- ( nostr_group_id, engine_group_id, group_name, welcomer_hex, wrapper_id_hex )
3725+ ( nostr_group_id, engine_group_id, group_name, welcomer_hex, wrapper_event_id_hex )
36933726 } ; // engine dropped here
36943727
36953728 // Now persist the group metadata (awaitable section)
@@ -4279,6 +4312,7 @@ pub fn run() {
42794312 // MLS advanced helpers
42804313 process_mls_event,
42814314 add_mls_member_device,
4315+ invite_member_to_group,
42824316 remove_mls_member_device,
42834317 get_mls_group_members,
42844318 leave_mls_group,
0 commit comments