Skip to main content

simploxide_api_types/
client_api.rs

1use crate::{commands::*, responses::*, utils::CommandSyntax, *};
2use std::future::Future;
3use std::sync::Arc;
4
5/// A helper trait to handle different response wrappers
6pub trait ExtractResponse<'de, T>: Deserialize<'de> {
7    fn extract_response(self) -> Result<T, BadResponseError>;
8}
9
10pub trait ClientApiError: From<BadResponseError> + std::error::Error {
11    /// If current error is a bad response error return a reference to it
12    fn bad_response(&self) -> Option<&BadResponseError>;
13
14    /// If current error is a bad response error return a mut reference to it
15    fn bad_response_mut(&mut self) -> Option<&mut BadResponseError>;
16}
17
18pub trait ClientApi: Sync {
19    type ResponseShape<'de, T>: ExtractResponse<'de, T>
20    where
21        T: 'de + Deserialize<'de>;
22    type Error: ClientApiError;
23
24    fn send_raw(&self, command: String)
25    -> impl Future<Output = Result<String, Self::Error>> + Send;
26
27    fn send<C, R>(&self, cmd: C) -> impl Future<Output = Result<R, Self::Error>> + Send
28    where
29        C: Send + CommandSyntax,
30        R: for<'de> Deserialize<'de>,
31    {
32        async move {
33            let raw = self.send_raw(cmd.to_command_string()).await?;
34            let response_shape: Self::ResponseShape<'_, R> =
35                serde_json::from_str(&raw).map_err(BadResponseError::InvalidJson)?;
36            let response = response_shape.extract_response()?;
37            Ok(response)
38        }
39    }
40
41    /// ### Address commands
42    ///
43    /// Bots can use these commands to automatically check and create address when initialized
44    ///
45    /// ----
46    ///
47    /// Create bot address.
48    ///
49    /// *Network usage*: interactive.
50    ///
51    /// *Syntax:*
52    ///
53    /// ```
54    /// /_address <userId>
55    /// ```
56    fn api_create_my_address(
57        &self,
58        user_id: i64,
59    ) -> impl Future<Output = Result<Arc<UserContactLinkCreatedResponse>, Self::Error>> + Send {
60        async move {
61            let command = ApiCreateMyAddress { user_id };
62            let response: ApiCreateMyAddressResponse = self.send(command).await?;
63            Ok(response.into_inner())
64        }
65    }
66
67    /// ### Address commands
68    ///
69    /// Bots can use these commands to automatically check and create address when initialized
70    ///
71    /// ----
72    ///
73    /// Delete bot address.
74    ///
75    /// *Network usage*: background.
76    ///
77    /// *Syntax:*
78    ///
79    /// ```
80    /// /_delete_address <userId>
81    /// ```
82    fn api_delete_my_address(
83        &self,
84        user_id: i64,
85    ) -> impl Future<Output = Result<Arc<UserContactLinkDeletedResponse>, Self::Error>> + Send {
86        async move {
87            let command = ApiDeleteMyAddress { user_id };
88            let response: ApiDeleteMyAddressResponse = self.send(command).await?;
89            Ok(response.into_inner())
90        }
91    }
92
93    /// ### Address commands
94    ///
95    /// Bots can use these commands to automatically check and create address when initialized
96    ///
97    /// ----
98    ///
99    /// Get bot address and settings.
100    ///
101    /// *Network usage*: no.
102    ///
103    /// *Syntax:*
104    ///
105    /// ```
106    /// /_show_address <userId>
107    /// ```
108    fn api_show_my_address(
109        &self,
110        user_id: i64,
111    ) -> impl Future<Output = Result<Arc<UserContactLinkResponse>, Self::Error>> + Send {
112        async move {
113            let command = ApiShowMyAddress { user_id };
114            let response: ApiShowMyAddressResponse = self.send(command).await?;
115            Ok(response.into_inner())
116        }
117    }
118
119    /// ### Address commands
120    ///
121    /// Bots can use these commands to automatically check and create address when initialized
122    ///
123    /// ----
124    ///
125    /// Add address to bot profile.
126    ///
127    /// *Network usage*: interactive.
128    ///
129    /// *Syntax:*
130    ///
131    /// ```
132    /// /_profile_address <userId> on|off
133    /// ```
134    fn api_set_profile_address(
135        &self,
136        command: ApiSetProfileAddress,
137    ) -> impl Future<Output = Result<Arc<UserProfileUpdatedResponse>, Self::Error>> + Send {
138        async move {
139            let response: ApiSetProfileAddressResponse = self.send(command).await?;
140            Ok(response.into_inner())
141        }
142    }
143
144    /// ### Address commands
145    ///
146    /// Bots can use these commands to automatically check and create address when initialized
147    ///
148    /// ----
149    ///
150    /// Set bot address settings.
151    ///
152    /// *Network usage*: interactive.
153    ///
154    /// *Syntax:*
155    ///
156    /// ```
157    /// /_address_settings <userId> <json(settings)>
158    /// ```
159    fn api_set_address_settings(
160        &self,
161        user_id: i64,
162        settings: AddressSettings,
163    ) -> impl Future<Output = Result<Arc<UserContactLinkUpdatedResponse>, Self::Error>> + Send {
164        async move {
165            let command = ApiSetAddressSettings { user_id, settings };
166            let response: ApiSetAddressSettingsResponse = self.send(command).await?;
167            Ok(response.into_inner())
168        }
169    }
170
171    /// ### Message commands
172    ///
173    /// Commands to send, update, delete, moderate messages and set message reactions
174    ///
175    /// ----
176    ///
177    /// Send messages.
178    ///
179    /// *Network usage*: background.
180    ///
181    /// *Syntax:*
182    ///
183    /// ```
184    /// /_send <str(sendRef)>[ live=on][ ttl=<ttl>] json <json(composedMessages)>
185    /// ```
186    fn api_send_messages(
187        &self,
188        command: ApiSendMessages,
189    ) -> impl Future<Output = Result<Arc<NewChatItemsResponse>, Self::Error>> + Send {
190        async move {
191            let response: ApiSendMessagesResponse = self.send(command).await?;
192            Ok(response.into_inner())
193        }
194    }
195
196    /// ### Message commands
197    ///
198    /// Commands to send, update, delete, moderate messages and set message reactions
199    ///
200    /// ----
201    ///
202    /// Update message.
203    ///
204    /// *Network usage*: background.
205    ///
206    /// *Syntax:*
207    ///
208    /// ```
209    /// /_update item <str(chatRef)> <chatItemId>[ live=on] json <json(updatedMessage)>
210    /// ```
211    fn api_update_chat_item(
212        &self,
213        command: ApiUpdateChatItem,
214    ) -> impl Future<Output = Result<ApiUpdateChatItemResponse, Self::Error>> + Send {
215        async move {
216            let response: ApiUpdateChatItemResponse = self.send(command).await?;
217            Ok(response)
218        }
219    }
220
221    /// ### Message commands
222    ///
223    /// Commands to send, update, delete, moderate messages and set message reactions
224    ///
225    /// ----
226    ///
227    /// Delete message.
228    ///
229    /// *Network usage*: background.
230    ///
231    /// *Syntax:*
232    ///
233    /// ```
234    /// /_delete item <str(chatRef)> <chatItemIds[0]>[,<chatItemIds[1]>...] broadcast|internal|internalMark|history
235    /// ```
236    fn api_delete_chat_item(
237        &self,
238        chat_ref: ChatRef,
239        chat_item_ids: Vec<i64>,
240        delete_mode: CIDeleteMode,
241    ) -> impl Future<Output = Result<Arc<ChatItemsDeletedResponse>, Self::Error>> + Send {
242        async move {
243            let command = ApiDeleteChatItem {
244                chat_ref,
245                chat_item_ids,
246                delete_mode,
247            };
248            let response: ApiDeleteChatItemResponse = self.send(command).await?;
249            Ok(response.into_inner())
250        }
251    }
252
253    /// ### Message commands
254    ///
255    /// Commands to send, update, delete, moderate messages and set message reactions
256    ///
257    /// ----
258    ///
259    /// Moderate message. Requires Moderator role (and higher than message author's).
260    ///
261    /// *Network usage*: background.
262    ///
263    /// *Syntax:*
264    ///
265    /// ```
266    /// /_delete member item #<groupId> <chatItemIds[0]>[,<chatItemIds[1]>...]
267    /// ```
268    fn api_delete_member_chat_item(
269        &self,
270        group_id: i64,
271        chat_item_ids: Vec<i64>,
272    ) -> impl Future<Output = Result<Arc<ChatItemsDeletedResponse>, Self::Error>> + Send {
273        async move {
274            let command = ApiDeleteMemberChatItem {
275                group_id,
276                chat_item_ids,
277            };
278            let response: ApiDeleteMemberChatItemResponse = self.send(command).await?;
279            Ok(response.into_inner())
280        }
281    }
282
283    /// ### Message commands
284    ///
285    /// Commands to send, update, delete, moderate messages and set message reactions
286    ///
287    /// ----
288    ///
289    /// Add/remove message reaction.
290    ///
291    /// *Network usage*: background.
292    ///
293    /// *Syntax:*
294    ///
295    /// ```
296    /// /_reaction <str(chatRef)> <chatItemId> on|off <json(reaction)>
297    /// ```
298    fn api_chat_item_reaction(
299        &self,
300        command: ApiChatItemReaction,
301    ) -> impl Future<Output = Result<Arc<ChatItemReactionResponse>, Self::Error>> + Send {
302        async move {
303            let response: ApiChatItemReactionResponse = self.send(command).await?;
304            Ok(response.into_inner())
305        }
306    }
307
308    /// ### File commands
309    ///
310    /// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
311    ///
312    /// ----
313    ///
314    /// Receive file.
315    ///
316    /// *Network usage*: no.
317    ///
318    /// *Syntax:*
319    ///
320    /// ```
321    /// /freceive <fileId>[ approved_relays=on][ encrypt=on|off][ inline=on|off][ <filePath>]
322    /// ```
323    fn receive_file(
324        &self,
325        command: ReceiveFile,
326    ) -> impl Future<Output = Result<ReceiveFileResponse, Self::Error>> + Send {
327        async move {
328            let response: ReceiveFileResponse = self.send(command).await?;
329            Ok(response)
330        }
331    }
332
333    /// ### File commands
334    ///
335    /// Commands to receive and to cancel files. Files are sent as part of the message, there are no separate commands to send files.
336    ///
337    /// ----
338    ///
339    /// Cancel file.
340    ///
341    /// *Network usage*: background.
342    ///
343    /// *Syntax:*
344    ///
345    /// ```
346    /// /fcancel <fileId>
347    /// ```
348    fn cancel_file(
349        &self,
350        file_id: i64,
351    ) -> impl Future<Output = Result<CancelFileResponse, Self::Error>> + Send {
352        async move {
353            let command = CancelFile { file_id };
354            let response: CancelFileResponse = self.send(command).await?;
355            Ok(response)
356        }
357    }
358
359    /// ### Group commands
360    ///
361    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
362    ///
363    /// ----
364    ///
365    /// Add contact to group. Requires bot to have Admin role.
366    ///
367    /// *Network usage*: interactive.
368    ///
369    /// *Syntax:*
370    ///
371    /// ```
372    /// /_add #<groupId> <contactId> relay|observer|author|member|moderator|admin|owner
373    /// ```
374    fn api_add_member(
375        &self,
376        group_id: i64,
377        contact_id: i64,
378        member_role: GroupMemberRole,
379    ) -> impl Future<Output = Result<Arc<SentGroupInvitationResponse>, Self::Error>> + Send {
380        async move {
381            let command = ApiAddMember {
382                group_id,
383                contact_id,
384                member_role,
385            };
386            let response: ApiAddMemberResponse = self.send(command).await?;
387            Ok(response.into_inner())
388        }
389    }
390
391    /// ### Group commands
392    ///
393    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
394    ///
395    /// ----
396    ///
397    /// Join group.
398    ///
399    /// *Network usage*: interactive.
400    ///
401    /// *Syntax:*
402    ///
403    /// ```
404    /// /_join #<groupId>
405    /// ```
406    fn api_join_group(
407        &self,
408        group_id: i64,
409    ) -> impl Future<Output = Result<Arc<UserAcceptedGroupSentResponse>, Self::Error>> + Send {
410        async move {
411            let command = ApiJoinGroup { group_id };
412            let response: ApiJoinGroupResponse = self.send(command).await?;
413            Ok(response.into_inner())
414        }
415    }
416
417    /// ### Group commands
418    ///
419    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
420    ///
421    /// ----
422    ///
423    /// Accept group member. Requires Admin role.
424    ///
425    /// *Network usage*: background.
426    ///
427    /// *Syntax:*
428    ///
429    /// ```
430    /// /_accept member #<groupId> <groupMemberId> relay|observer|author|member|moderator|admin|owner
431    /// ```
432    fn api_accept_member(
433        &self,
434        group_id: i64,
435        group_member_id: i64,
436        member_role: GroupMemberRole,
437    ) -> impl Future<Output = Result<Arc<MemberAcceptedResponse>, Self::Error>> + Send {
438        async move {
439            let command = ApiAcceptMember {
440                group_id,
441                group_member_id,
442                member_role,
443            };
444            let response: ApiAcceptMemberResponse = self.send(command).await?;
445            Ok(response.into_inner())
446        }
447    }
448
449    /// ### Group commands
450    ///
451    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
452    ///
453    /// ----
454    ///
455    /// Set members role. Requires Admin role.
456    ///
457    /// *Network usage*: background.
458    ///
459    /// *Syntax:*
460    ///
461    /// ```
462    /// /_member role #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] relay|observer|author|member|moderator|admin|owner
463    /// ```
464    fn api_members_role(
465        &self,
466        group_id: i64,
467        group_member_ids: Vec<i64>,
468        member_role: GroupMemberRole,
469    ) -> impl Future<Output = Result<Arc<MembersRoleUserResponse>, Self::Error>> + Send {
470        async move {
471            let command = ApiMembersRole {
472                group_id,
473                group_member_ids,
474                member_role,
475            };
476            let response: ApiMembersRoleResponse = self.send(command).await?;
477            Ok(response.into_inner())
478        }
479    }
480
481    /// ### Group commands
482    ///
483    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
484    ///
485    /// ----
486    ///
487    /// Block members. Requires Moderator role.
488    ///
489    /// *Network usage*: background.
490    ///
491    /// *Syntax:*
492    ///
493    /// ```
494    /// /_block #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...] blocked=on|off
495    /// ```
496    fn api_block_members_for_all(
497        &self,
498        command: ApiBlockMembersForAll,
499    ) -> impl Future<Output = Result<Arc<MembersBlockedForAllUserResponse>, Self::Error>> + Send
500    {
501        async move {
502            let response: ApiBlockMembersForAllResponse = self.send(command).await?;
503            Ok(response.into_inner())
504        }
505    }
506
507    /// ### Group commands
508    ///
509    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
510    ///
511    /// ----
512    ///
513    /// Remove members. Requires Admin role.
514    ///
515    /// *Network usage*: background.
516    ///
517    /// *Syntax:*
518    ///
519    /// ```
520    /// /_remove #<groupId> <groupMemberIds[0]>[,<groupMemberIds[1]>...][ messages=on]
521    /// ```
522    fn api_remove_members(
523        &self,
524        command: ApiRemoveMembers,
525    ) -> impl Future<Output = Result<Arc<UserDeletedMembersResponse>, Self::Error>> + Send {
526        async move {
527            let response: ApiRemoveMembersResponse = self.send(command).await?;
528            Ok(response.into_inner())
529        }
530    }
531
532    /// ### Group commands
533    ///
534    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
535    ///
536    /// ----
537    ///
538    /// Leave group.
539    ///
540    /// *Network usage*: background.
541    ///
542    /// *Syntax:*
543    ///
544    /// ```
545    /// /_leave #<groupId>
546    /// ```
547    fn api_leave_group(
548        &self,
549        group_id: i64,
550    ) -> impl Future<Output = Result<Arc<LeftMemberUserResponse>, Self::Error>> + Send {
551        async move {
552            let command = ApiLeaveGroup { group_id };
553            let response: ApiLeaveGroupResponse = self.send(command).await?;
554            Ok(response.into_inner())
555        }
556    }
557
558    /// ### Group commands
559    ///
560    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
561    ///
562    /// ----
563    ///
564    /// Get group members.
565    ///
566    /// *Network usage*: no.
567    ///
568    /// *Syntax:*
569    ///
570    /// ```
571    /// /_members #<groupId>
572    /// ```
573    fn api_list_members(
574        &self,
575        group_id: i64,
576    ) -> impl Future<Output = Result<Arc<GroupMembersResponse>, Self::Error>> + Send {
577        async move {
578            let command = ApiListMembers { group_id };
579            let response: ApiListMembersResponse = self.send(command).await?;
580            Ok(response.into_inner())
581        }
582    }
583
584    /// ### Group commands
585    ///
586    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
587    ///
588    /// ----
589    ///
590    /// Create group.
591    ///
592    /// *Network usage*: no.
593    ///
594    /// *Syntax:*
595    ///
596    /// ```
597    /// /_group <userId>[ incognito=on] <json(groupProfile)>
598    /// ```
599    fn api_new_group(
600        &self,
601        command: ApiNewGroup,
602    ) -> impl Future<Output = Result<Arc<GroupCreatedResponse>, Self::Error>> + Send {
603        async move {
604            let response: ApiNewGroupResponse = self.send(command).await?;
605            Ok(response.into_inner())
606        }
607    }
608
609    /// ### Group commands
610    ///
611    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
612    ///
613    /// ----
614    ///
615    /// Create public group.
616    ///
617    /// *Network usage*: interactive.
618    ///
619    /// *Syntax:*
620    ///
621    /// ```
622    /// /_public group <userId>[ incognito=on] <relayIds[0]>[,<relayIds[1]>...] <json(groupProfile)>
623    /// ```
624    fn api_new_public_group(
625        &self,
626        command: ApiNewPublicGroup,
627    ) -> impl Future<Output = Result<ApiNewPublicGroupResponse, Self::Error>> + Send {
628        async move {
629            let response: ApiNewPublicGroupResponse = self.send(command).await?;
630            Ok(response)
631        }
632    }
633
634    /// ### Group commands
635    ///
636    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
637    ///
638    /// ----
639    ///
640    /// Get group relays.
641    ///
642    /// *Network usage*: no.
643    ///
644    /// *Syntax:*
645    ///
646    /// ```
647    /// /_get relays #<groupId>
648    /// ```
649    fn api_get_group_relays(
650        &self,
651        group_id: i64,
652    ) -> impl Future<Output = Result<Arc<GroupRelaysResponse>, Self::Error>> + Send {
653        async move {
654            let command = ApiGetGroupRelays { group_id };
655            let response: ApiGetGroupRelaysResponse = self.send(command).await?;
656            Ok(response.into_inner())
657        }
658    }
659
660    /// ### Group commands
661    ///
662    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
663    ///
664    /// ----
665    ///
666    /// Add relays to group.
667    ///
668    /// *Network usage*: interactive.
669    ///
670    /// *Syntax:*
671    ///
672    /// ```
673    /// /_add relays #<groupId> <relayIds[0]>[,<relayIds[1]>...]
674    /// ```
675    fn api_add_group_relays(
676        &self,
677        group_id: i64,
678        relay_ids: Vec<i64>,
679    ) -> impl Future<Output = Result<ApiAddGroupRelaysResponse, Self::Error>> + Send {
680        async move {
681            let command = ApiAddGroupRelays {
682                group_id,
683                relay_ids,
684            };
685            let response: ApiAddGroupRelaysResponse = self.send(command).await?;
686            Ok(response)
687        }
688    }
689
690    /// ### Group commands
691    ///
692    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
693    ///
694    /// ----
695    ///
696    /// Clear relay rejection for a channel (relay operator).
697    ///
698    /// *Network usage*: background.
699    ///
700    /// *Syntax:*
701    ///
702    /// ```
703    /// /_relay allow #<groupId>
704    /// ```
705    fn api_allow_relay_group(
706        &self,
707        group_id: i64,
708    ) -> impl Future<Output = Result<Arc<RelayGroupAllowedResponse>, Self::Error>> + Send {
709        async move {
710            let command = ApiAllowRelayGroup { group_id };
711            let response: ApiAllowRelayGroupResponse = self.send(command).await?;
712            Ok(response.into_inner())
713        }
714    }
715
716    /// ### Group commands
717    ///
718    /// Commands to manage and moderate groups. These commands can be used with business chats as well - they are groups. E.g., a common scenario would be to add human agents to business chat with the customer who connected via business address.
719    ///
720    /// ----
721    ///
722    /// Update group profile.
723    ///
724    /// *Network usage*: background.
725    ///
726    /// *Syntax:*
727    ///
728    /// ```
729    /// /_group_profile #<groupId> <json(groupProfile)>
730    /// ```
731    fn api_update_group_profile(
732        &self,
733        group_id: i64,
734        group_profile: GroupProfile,
735    ) -> impl Future<Output = Result<Arc<GroupUpdatedResponse>, Self::Error>> + Send {
736        async move {
737            let command = ApiUpdateGroupProfile {
738                group_id,
739                group_profile,
740            };
741            let response: ApiUpdateGroupProfileResponse = self.send(command).await?;
742            Ok(response.into_inner())
743        }
744    }
745
746    /// ### Group link commands
747    ///
748    /// These commands can be used by bots that manage multiple public groups
749    ///
750    /// ----
751    ///
752    /// Create group link.
753    ///
754    /// *Network usage*: interactive.
755    ///
756    /// *Syntax:*
757    ///
758    /// ```
759    /// /_create link #<groupId> relay|observer|author|member|moderator|admin|owner
760    /// ```
761    fn api_create_group_link(
762        &self,
763        group_id: i64,
764        member_role: GroupMemberRole,
765    ) -> impl Future<Output = Result<Arc<GroupLinkCreatedResponse>, Self::Error>> + Send {
766        async move {
767            let command = ApiCreateGroupLink {
768                group_id,
769                member_role,
770            };
771            let response: ApiCreateGroupLinkResponse = self.send(command).await?;
772            Ok(response.into_inner())
773        }
774    }
775
776    /// ### Group link commands
777    ///
778    /// These commands can be used by bots that manage multiple public groups
779    ///
780    /// ----
781    ///
782    /// Set member role for group link.
783    ///
784    /// *Network usage*: no.
785    ///
786    /// *Syntax:*
787    ///
788    /// ```
789    /// /_set link role #<groupId> relay|observer|author|member|moderator|admin|owner
790    /// ```
791    fn api_group_link_member_role(
792        &self,
793        group_id: i64,
794        member_role: GroupMemberRole,
795    ) -> impl Future<Output = Result<Arc<GroupLinkResponse>, Self::Error>> + Send {
796        async move {
797            let command = ApiGroupLinkMemberRole {
798                group_id,
799                member_role,
800            };
801            let response: ApiGroupLinkMemberRoleResponse = self.send(command).await?;
802            Ok(response.into_inner())
803        }
804    }
805
806    /// ### Group link commands
807    ///
808    /// These commands can be used by bots that manage multiple public groups
809    ///
810    /// ----
811    ///
812    /// Delete group link.
813    ///
814    /// *Network usage*: background.
815    ///
816    /// *Syntax:*
817    ///
818    /// ```
819    /// /_delete link #<groupId>
820    /// ```
821    fn api_delete_group_link(
822        &self,
823        group_id: i64,
824    ) -> impl Future<Output = Result<Arc<GroupLinkDeletedResponse>, Self::Error>> + Send {
825        async move {
826            let command = ApiDeleteGroupLink { group_id };
827            let response: ApiDeleteGroupLinkResponse = self.send(command).await?;
828            Ok(response.into_inner())
829        }
830    }
831
832    /// ### Group link commands
833    ///
834    /// These commands can be used by bots that manage multiple public groups
835    ///
836    /// ----
837    ///
838    /// Get group link.
839    ///
840    /// *Network usage*: no.
841    ///
842    /// *Syntax:*
843    ///
844    /// ```
845    /// /_get link #<groupId>
846    /// ```
847    fn api_get_group_link(
848        &self,
849        group_id: i64,
850    ) -> impl Future<Output = Result<Arc<GroupLinkResponse>, Self::Error>> + Send {
851        async move {
852            let command = ApiGetGroupLink { group_id };
853            let response: ApiGetGroupLinkResponse = self.send(command).await?;
854            Ok(response.into_inner())
855        }
856    }
857
858    /// ### Connection commands
859    ///
860    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
861    ///
862    /// ----
863    ///
864    /// Create 1-time invitation link.
865    ///
866    /// *Network usage*: interactive.
867    ///
868    /// *Syntax:*
869    ///
870    /// ```
871    /// /_connect <userId>[ incognito=on]
872    /// ```
873    fn api_add_contact(
874        &self,
875        command: ApiAddContact,
876    ) -> impl Future<Output = Result<Arc<InvitationResponse>, Self::Error>> + Send {
877        async move {
878            let response: ApiAddContactResponse = self.send(command).await?;
879            Ok(response.into_inner())
880        }
881    }
882
883    /// ### Connection commands
884    ///
885    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
886    ///
887    /// ----
888    ///
889    /// Determine SimpleX link type and if the bot is already connected via this link.
890    ///
891    /// *Network usage*: interactive.
892    ///
893    /// *Syntax:*
894    ///
895    /// ```
896    /// /_connect plan <userId> <connectionLink>
897    /// ```
898    fn api_connect_plan(
899        &self,
900        command: ApiConnectPlan,
901    ) -> impl Future<Output = Result<Arc<ConnectionPlanResponse>, Self::Error>> + Send {
902        async move {
903            let response: ApiConnectPlanResponse = self.send(command).await?;
904            Ok(response.into_inner())
905        }
906    }
907
908    /// ### Connection commands
909    ///
910    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
911    ///
912    /// ----
913    ///
914    /// Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link.
915    ///
916    /// *Network usage*: interactive.
917    ///
918    /// *Syntax:*
919    ///
920    /// ```
921    /// /_connect <userId>[ <str(preparedLink_)>]
922    /// ```
923    fn api_connect(
924        &self,
925        command: ApiConnect,
926    ) -> impl Future<Output = Result<ApiConnectResponse, Self::Error>> + Send {
927        async move {
928            let response: ApiConnectResponse = self.send(command).await?;
929            Ok(response)
930        }
931    }
932
933    /// ### Connection commands
934    ///
935    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
936    ///
937    /// ----
938    ///
939    /// Connect via SimpleX link as string in the active user profile.
940    ///
941    /// *Network usage*: interactive.
942    ///
943    /// *Syntax:*
944    ///
945    /// ```
946    /// /connect[ <connLink_>]
947    /// ```
948    fn connect(
949        &self,
950        command: Connect,
951    ) -> impl Future<Output = Result<ConnectResponse, Self::Error>> + Send {
952        async move {
953            let response: ConnectResponse = self.send(command).await?;
954            Ok(response)
955        }
956    }
957
958    /// ### Connection commands
959    ///
960    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
961    ///
962    /// ----
963    ///
964    /// Accept contact request.
965    ///
966    /// *Network usage*: interactive.
967    ///
968    /// *Syntax:*
969    ///
970    /// ```
971    /// /_accept <contactReqId>
972    /// ```
973    fn api_accept_contact(
974        &self,
975        contact_req_id: i64,
976    ) -> impl Future<Output = Result<Arc<AcceptingContactRequestResponse>, Self::Error>> + Send
977    {
978        async move {
979            let command = ApiAcceptContact { contact_req_id };
980            let response: ApiAcceptContactResponse = self.send(command).await?;
981            Ok(response.into_inner())
982        }
983    }
984
985    /// ### Connection commands
986    ///
987    /// These commands may be used to create connections. Most bots do not need to use them - bot users will connect via bot address with auto-accept enabled.
988    ///
989    /// ----
990    ///
991    /// Reject contact request. The user who sent the request is **not notified**.
992    ///
993    /// *Network usage*: no.
994    ///
995    /// *Syntax:*
996    ///
997    /// ```
998    /// /_reject <contactReqId>
999    /// ```
1000    fn api_reject_contact(
1001        &self,
1002        contact_req_id: i64,
1003    ) -> impl Future<Output = Result<Arc<ContactRequestRejectedResponse>, Self::Error>> + Send {
1004        async move {
1005            let command = ApiRejectContact { contact_req_id };
1006            let response: ApiRejectContactResponse = self.send(command).await?;
1007            Ok(response.into_inner())
1008        }
1009    }
1010
1011    /// ### Chat commands
1012    ///
1013    /// Commands to list and delete conversations.
1014    ///
1015    /// ----
1016    ///
1017    /// Get contacts.
1018    ///
1019    /// *Network usage*: no.
1020    ///
1021    /// *Syntax:*
1022    ///
1023    /// ```
1024    /// /_contacts <userId>
1025    /// ```
1026    fn api_list_contacts(
1027        &self,
1028        user_id: i64,
1029    ) -> impl Future<Output = Result<Arc<ContactsListResponse>, Self::Error>> + Send {
1030        async move {
1031            let command = ApiListContacts { user_id };
1032            let response: ApiListContactsResponse = self.send(command).await?;
1033            Ok(response.into_inner())
1034        }
1035    }
1036
1037    /// ### Chat commands
1038    ///
1039    /// Commands to list and delete conversations.
1040    ///
1041    /// ----
1042    ///
1043    /// Get groups.
1044    ///
1045    /// *Network usage*: no.
1046    ///
1047    /// *Syntax:*
1048    ///
1049    /// ```
1050    /// /_groups <userId>[ @<contactId_>][ <search>]
1051    /// ```
1052    fn api_list_groups(
1053        &self,
1054        command: ApiListGroups,
1055    ) -> impl Future<Output = Result<Arc<GroupsListResponse>, Self::Error>> + Send {
1056        async move {
1057            let response: ApiListGroupsResponse = self.send(command).await?;
1058            Ok(response.into_inner())
1059        }
1060    }
1061
1062    /// ### Chat commands
1063    ///
1064    /// Commands to list and delete conversations.
1065    ///
1066    /// ----
1067    ///
1068    /// Get chat previews. Supports time-based pagination — use this instead of APIListContacts / APIListGroups when scanning at scale (those load every record into memory and fail on large databases).
1069    ///
1070    /// *Network usage*: no.
1071    ///
1072    /// *Syntax:*
1073    ///
1074    /// ```
1075    /// /_get chats <userId>[ pcc=on] <str(pagination)> <json(query)>
1076    /// ```
1077    fn api_get_chats(
1078        &self,
1079        command: ApiGetChats,
1080    ) -> impl Future<Output = Result<Arc<ApiChatsResponse>, Self::Error>> + Send {
1081        async move {
1082            let response: ApiGetChatsResponse = self.send(command).await?;
1083            Ok(response.into_inner())
1084        }
1085    }
1086
1087    /// ### Chat commands
1088    ///
1089    /// Commands to list and delete conversations.
1090    ///
1091    /// ----
1092    ///
1093    /// Delete chat.
1094    ///
1095    /// *Network usage*: background.
1096    ///
1097    /// *Syntax:*
1098    ///
1099    /// ```
1100    /// /_delete <str(chatRef)> <str(chatDeleteMode)>
1101    /// ```
1102    fn api_delete_chat(
1103        &self,
1104        chat_ref: ChatRef,
1105        chat_delete_mode: ChatDeleteMode,
1106    ) -> impl Future<Output = Result<ApiDeleteChatResponse, Self::Error>> + Send {
1107        async move {
1108            let command = ApiDeleteChat {
1109                chat_ref,
1110                chat_delete_mode,
1111            };
1112            let response: ApiDeleteChatResponse = self.send(command).await?;
1113            Ok(response)
1114        }
1115    }
1116
1117    /// ### Chat commands
1118    ///
1119    /// Commands to list and delete conversations.
1120    ///
1121    /// ----
1122    ///
1123    /// Set group custom data.
1124    ///
1125    /// *Network usage*: no.
1126    ///
1127    /// *Syntax:*
1128    ///
1129    /// ```
1130    /// /_set custom #<groupId>[ <json(customData)>]
1131    /// ```
1132    fn api_set_group_custom_data(
1133        &self,
1134        command: ApiSetGroupCustomData,
1135    ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1136        async move {
1137            let response: ApiSetGroupCustomDataResponse = self.send(command).await?;
1138            Ok(response.into_inner())
1139        }
1140    }
1141
1142    /// ### Chat commands
1143    ///
1144    /// Commands to list and delete conversations.
1145    ///
1146    /// ----
1147    ///
1148    /// Set contact custom data.
1149    ///
1150    /// *Network usage*: no.
1151    ///
1152    /// *Syntax:*
1153    ///
1154    /// ```
1155    /// /_set custom @<contactId>[ <json(customData)>]
1156    /// ```
1157    fn api_set_contact_custom_data(
1158        &self,
1159        command: ApiSetContactCustomData,
1160    ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1161        async move {
1162            let response: ApiSetContactCustomDataResponse = self.send(command).await?;
1163            Ok(response.into_inner())
1164        }
1165    }
1166
1167    /// ### Chat commands
1168    ///
1169    /// Commands to list and delete conversations.
1170    ///
1171    /// ----
1172    ///
1173    /// Set auto-accept member contacts.
1174    ///
1175    /// *Network usage*: no.
1176    ///
1177    /// *Syntax:*
1178    ///
1179    /// ```
1180    /// /_set accept member contacts <userId> on|off
1181    /// ```
1182    fn api_set_user_auto_accept_member_contacts(
1183        &self,
1184        command: ApiSetUserAutoAcceptMemberContacts,
1185    ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1186        async move {
1187            let response: ApiSetUserAutoAcceptMemberContactsResponse = self.send(command).await?;
1188            Ok(response.into_inner())
1189        }
1190    }
1191
1192    /// ### User profile commands
1193    ///
1194    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1195    ///
1196    /// ----
1197    ///
1198    /// Get active user profile.
1199    ///
1200    /// *Network usage*: no.
1201    ///
1202    /// *Syntax:*
1203    ///
1204    /// ```
1205    /// /user
1206    /// ```
1207    fn show_active_user(
1208        &self,
1209    ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1210        async move {
1211            let command = ShowActiveUser {};
1212            let response: ShowActiveUserResponse = self.send(command).await?;
1213            Ok(response.into_inner())
1214        }
1215    }
1216
1217    /// ### User profile commands
1218    ///
1219    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1220    ///
1221    /// ----
1222    ///
1223    /// Create new user profile.
1224    ///
1225    /// *Network usage*: no.
1226    ///
1227    /// *Syntax:*
1228    ///
1229    /// ```
1230    /// /_create user <json(newUser)>
1231    /// ```
1232    fn create_active_user(
1233        &self,
1234        new_user: NewUser,
1235    ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1236        async move {
1237            let command = CreateActiveUser { new_user };
1238            let response: CreateActiveUserResponse = self.send(command).await?;
1239            Ok(response.into_inner())
1240        }
1241    }
1242
1243    /// ### User profile commands
1244    ///
1245    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1246    ///
1247    /// ----
1248    ///
1249    /// Get all user profiles.
1250    ///
1251    /// *Network usage*: no.
1252    ///
1253    /// *Syntax:*
1254    ///
1255    /// ```
1256    /// /users
1257    /// ```
1258    fn list_users(
1259        &self,
1260    ) -> impl Future<Output = Result<Arc<UsersListResponse>, Self::Error>> + Send {
1261        async move {
1262            let command = ListUsers {};
1263            let response: ListUsersResponse = self.send(command).await?;
1264            Ok(response.into_inner())
1265        }
1266    }
1267
1268    /// ### User profile commands
1269    ///
1270    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1271    ///
1272    /// ----
1273    ///
1274    /// Set active user profile.
1275    ///
1276    /// *Network usage*: no.
1277    ///
1278    /// *Syntax:*
1279    ///
1280    /// ```
1281    /// /_user <userId>[ <json(viewPwd)>]
1282    /// ```
1283    fn api_set_active_user(
1284        &self,
1285        command: ApiSetActiveUser,
1286    ) -> impl Future<Output = Result<Arc<ActiveUserResponse>, Self::Error>> + Send {
1287        async move {
1288            let response: ApiSetActiveUserResponse = self.send(command).await?;
1289            Ok(response.into_inner())
1290        }
1291    }
1292
1293    /// ### User profile commands
1294    ///
1295    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1296    ///
1297    /// ----
1298    ///
1299    /// Delete user profile.
1300    ///
1301    /// *Network usage*: background.
1302    ///
1303    /// *Syntax:*
1304    ///
1305    /// ```
1306    /// /_delete user <userId> del_smp=on|off[ <json(viewPwd)>]
1307    /// ```
1308    fn api_delete_user(
1309        &self,
1310        command: ApiDeleteUser,
1311    ) -> impl Future<Output = Result<Arc<CmdOkResponse>, Self::Error>> + Send {
1312        async move {
1313            let response: ApiDeleteUserResponse = self.send(command).await?;
1314            Ok(response.into_inner())
1315        }
1316    }
1317
1318    /// ### User profile commands
1319    ///
1320    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1321    ///
1322    /// ----
1323    ///
1324    /// Update user profile.
1325    ///
1326    /// *Network usage*: background.
1327    ///
1328    /// *Syntax:*
1329    ///
1330    /// ```
1331    /// /_profile <userId> <json(profile)>
1332    /// ```
1333    fn api_update_profile(
1334        &self,
1335        user_id: i64,
1336        profile: Profile,
1337    ) -> impl Future<Output = Result<ApiUpdateProfileResponse, Self::Error>> + Send {
1338        async move {
1339            let command = ApiUpdateProfile { user_id, profile };
1340            let response: ApiUpdateProfileResponse = self.send(command).await?;
1341            Ok(response)
1342        }
1343    }
1344
1345    /// ### User profile commands
1346    ///
1347    /// Most bots don't need to use these commands, as bot profile can be configured manually via CLI or desktop client. These commands can be used by bots that need to manage multiple user profiles (e.g., the profiles of support agents).
1348    ///
1349    /// ----
1350    ///
1351    /// Configure chat preference overrides for the contact.
1352    ///
1353    /// *Network usage*: background.
1354    ///
1355    /// *Syntax:*
1356    ///
1357    /// ```
1358    /// /_set prefs @<contactId> <json(preferences)>
1359    /// ```
1360    fn api_set_contact_prefs(
1361        &self,
1362        contact_id: i64,
1363        preferences: Preferences,
1364    ) -> impl Future<Output = Result<Arc<ContactPrefsUpdatedResponse>, Self::Error>> + Send {
1365        async move {
1366            let command = ApiSetContactPrefs {
1367                contact_id,
1368                preferences,
1369            };
1370            let response: ApiSetContactPrefsResponse = self.send(command).await?;
1371            Ok(response.into_inner())
1372        }
1373    }
1374
1375    /// ### Chat management
1376    ///
1377    /// These commands should not be used with CLI-based bots
1378    ///
1379    /// ----
1380    ///
1381    /// Start chat controller.
1382    ///
1383    /// *Network usage*: no.
1384    ///
1385    /// *Syntax:*
1386    ///
1387    /// ```
1388    /// /_start
1389    /// ```
1390    fn start_chat(
1391        &self,
1392        command: StartChat,
1393    ) -> impl Future<Output = Result<StartChatResponse, Self::Error>> + Send {
1394        async move {
1395            let response: StartChatResponse = self.send(command).await?;
1396            Ok(response)
1397        }
1398    }
1399
1400    /// ### Chat management
1401    ///
1402    /// These commands should not be used with CLI-based bots
1403    ///
1404    /// ----
1405    ///
1406    /// Stop chat controller.
1407    ///
1408    /// *Network usage*: no.
1409    ///
1410    /// *Syntax:*
1411    ///
1412    /// ```
1413    /// /_stop
1414    /// ```
1415    fn api_stop_chat(
1416        &self,
1417    ) -> impl Future<Output = Result<Arc<ChatStoppedResponse>, Self::Error>> + Send {
1418        async move {
1419            let command = ApiStopChat {};
1420            let response: ApiStopChatResponse = self.send(command).await?;
1421            Ok(response.into_inner())
1422        }
1423    }
1424}
1425
1426/// Use this as [`ClientApi::ResponseShape`] to extract web socket responses
1427#[derive(Serialize, Deserialize)]
1428pub struct WebSocketResponseShape<T> {
1429    pub resp: WebSocketResponseShapeInner<T>,
1430}
1431
1432#[derive(Serialize, Deserialize)]
1433#[serde(untagged)]
1434pub enum WebSocketResponseShapeInner<T> {
1435    Response(T),
1436    Error(ChatCmdError),
1437    Undocumented(JsonObject),
1438}
1439
1440impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for WebSocketResponseShape<T> {
1441    fn extract_response(self) -> Result<T, BadResponseError> {
1442        self.resp.extract_response()
1443    }
1444}
1445
1446impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for WebSocketResponseShapeInner<T> {
1447    fn extract_response(self) -> Result<T, BadResponseError> {
1448        match self {
1449            Self::Response(resp) => Ok(resp),
1450            Self::Error(err) => Err(BadResponseError::ChatError(
1451                err.into_inner().chat_error.clone(),
1452            )),
1453            Self::Undocumented(json) => Err(BadResponseError::Undocumented(json)),
1454        }
1455    }
1456}
1457
1458/// Use this as [`ClientApi::ResponseShape`] to extract FFI responses
1459#[derive(Serialize, Deserialize)]
1460pub enum FfiResponseShape<T> {
1461    #[serde(rename = "result")]
1462    Result(T),
1463
1464    #[serde(rename = "error")]
1465    Error(Arc<ChatError>),
1466
1467    #[serde(untagged)]
1468    Undocumented(JsonObject),
1469}
1470
1471impl<'de, T: 'de + Deserialize<'de>> ExtractResponse<'de, T> for FfiResponseShape<T> {
1472    fn extract_response(self) -> Result<T, BadResponseError> {
1473        match self {
1474            Self::Result(resp) => Ok(resp),
1475            Self::Error(err) => Err(BadResponseError::ChatError(err)),
1476            Self::Undocumented(json) => Err(BadResponseError::Undocumented(json)),
1477        }
1478    }
1479}
1480
1481#[derive(Debug)]
1482pub enum BadResponseError {
1483    ChatError(Arc<ChatError>),
1484    InvalidJson(serde_json::Error),
1485    Undocumented(JsonObject),
1486}
1487
1488impl BadResponseError {
1489    pub fn chat_error(&self) -> Option<&ChatError> {
1490        if let Self::ChatError(error) = self {
1491            Some(error.as_ref())
1492        } else {
1493            None
1494        }
1495    }
1496
1497    pub fn invalid_json(&self) -> Option<&serde_json::Error> {
1498        if let Self::InvalidJson(error) = self {
1499            Some(error)
1500        } else {
1501            None
1502        }
1503    }
1504
1505    pub fn undocumented(&self) -> Option<&JsonObject> {
1506        if let Self::Undocumented(error) = self {
1507            Some(error)
1508        } else {
1509            None
1510        }
1511    }
1512}
1513
1514impl std::error::Error for BadResponseError {
1515    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1516        match self {
1517            Self::ChatError(error) => Some(error.as_ref()),
1518            Self::InvalidJson(error) => Some(error),
1519            Self::Undocumented(_) => None,
1520        }
1521    }
1522}
1523
1524impl std::fmt::Display for BadResponseError {
1525    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1526        match self {
1527            Self::ChatError(resp) => writeln!(f, "Bad response:\n{resp:#}"),
1528            Self::Undocumented(resp) => writeln!(f, "Unexpected response:\n{resp:#}"),
1529            Self::InvalidJson(err) => writeln!(f, "Invalid JSON:\n{err:#}"),
1530        }
1531    }
1532}
1533
1534pub enum UndocumentedResponse<T> {
1535    Documented(T),
1536    Undocumented(JsonObject),
1537}
1538
1539/// If you want to ~~suffer~~ handle undocumented responses you can use this extension trait
1540/// on client API return values which moves Undocumented from `Err` to `Ok` variant.
1541///
1542/// Example:
1543///
1544/// ```ignore
1545///     match client
1546///         .api_create_my_address(1)
1547///         .await
1548///         .allow_undocumented()?
1549///     {
1550///         UndocumentedResponse::Documented(resp) => {
1551///              // Process expected response...
1552///         }
1553///         UndocumentedResponse::Undocumented(resp) => {
1554///             // Do something with the unexpected response...
1555///         }
1556///     }
1557/// }
1558/// ```
1559pub trait AllowUndocumentedResponses<T, E> {
1560    fn allow_undocumented(self) -> Result<UndocumentedResponse<T>, E>;
1561}
1562
1563impl<T, E> AllowUndocumentedResponses<T, E> for Result<T, E>
1564where
1565    E: ClientApiError,
1566{
1567    fn allow_undocumented(self) -> Result<UndocumentedResponse<T>, E> {
1568        match self {
1569            Ok(resp) => Ok(UndocumentedResponse::Documented(resp)),
1570            Err(mut e) => match e.bad_response_mut() {
1571                Some(BadResponseError::Undocumented(btree_map)) => Ok(
1572                    UndocumentedResponse::Undocumented(std::mem::take(btree_map)),
1573                ),
1574                _ => Err(e),
1575            },
1576        }
1577    }
1578}