Skip to main content

fluxer/model/
mod.rs

1//! Typed structs for everything the Fluxer API returns -- users, guilds,
2//! channels, messages, embeds, and all the gateway event payloads.
3//!
4//! Most fields are `Option<T>` because the API doesn't always include
5//! everything depending on the endpoint.
6
7pub mod voice;
8use serde::{Deserialize, Serialize};
9
10/// All entity IDs in the Fluxer API are snowflake strings.
11pub type Snowflake = String;
12
13/// A Fluxer user account. Both bot and human accounts share this struct.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct User {
16    pub id: Snowflake,
17    #[serde(default)]
18    pub username: String,
19    pub discriminator: Option<String>,
20    pub avatar: Option<String>,
21    pub banner: Option<String>,
22    #[serde(default)]
23    pub bot: Option<bool>,
24    #[serde(default)]
25    pub system: Option<bool>,
26    pub public_flags: Option<u64>,
27    pub premium: Option<u64>,
28}
29
30/// A guild (server). Full data arrives via `GUILD_CREATE`; [`UnavailableGuild`] is used before then.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Guild {
33    pub id: Snowflake,
34    pub name: Option<String>,
35    pub icon: Option<String>,
36    pub banner: Option<String>,
37    pub splash: Option<String>,
38    pub owner_id: Option<Snowflake>,
39    pub afk_channel_id: Option<Snowflake>,
40    /// AFK timeout in seconds.
41    pub afk_timeout: Option<u64>,
42    pub verification_level: Option<u64>,
43    /// 0 = all messages, 1 = only mentions.
44    pub default_message_notifications: Option<u64>,
45    pub explicit_content_filter: Option<u64>,
46    pub roles: Option<Vec<Role>>,
47    pub emojis: Option<Vec<Emoji>>,
48    pub features: Option<Vec<String>>,
49    pub member_count: Option<u64>,
50    pub max_members: Option<u64>,
51    pub description: Option<String>,
52    pub preferred_locale: Option<String>,
53    pub vanity_url_code: Option<String>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct WellKnownFluxerEndpoints {
58    pub api: String,
59    pub api_client: String,
60    pub api_public: String,
61    pub gateway: String,
62    pub media: String,
63    pub static_cdn: String,
64    pub marketing: String,
65    pub admin: String,
66    pub invite: String,
67    pub gift: String,
68    pub webapp: String,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct WellKnownFluxerCaptcha {
73    pub provider: String,
74    pub hcaptcha_site_key: Option<String>,
75    pub turnstile_site_key: Option<String>,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct WellKnownFluxerFeatures {
80    pub voice_enabled: bool,
81    pub stripe_enabled: bool,
82    pub self_hosted: bool,
83    pub presigned_attachment_uploads: bool,
84    pub emails_enabled: bool,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct WellKnownFluxerGif {
89    pub provider: String,
90    pub display_name: String,
91    pub attribution_required: bool,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct WellKnownFluxerSso {
96    pub enabled: bool,
97    pub enforced: bool,
98    pub display_name: Option<String>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct WellKnownFluxerResponse {
103    pub api_code_version: u64,
104    pub endpoints: WellKnownFluxerEndpoints,
105    pub captcha: WellKnownFluxerCaptcha,
106    pub features: WellKnownFluxerFeatures,
107    pub gif: WellKnownFluxerGif,
108    pub sso: WellKnownFluxerSso,
109}
110
111/// A guild member. Wraps a [`User`] with guild-specific info like nickname and roles.
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct Member {
114    pub user: Option<User>,
115    pub nick: Option<String>,
116    pub avatar: Option<String>,
117    pub roles: Vec<Snowflake>,
118    pub joined_at: String,
119    pub deaf: Option<bool>,
120    pub mute: Option<bool>,
121    pub pending: Option<bool>,
122    pub permissions: Option<String>,
123    /// ISO 8601 timestamp. If set, the member is timed out until then.
124    pub communication_disabled_until: Option<String>,
125}
126
127impl Member {
128    /// Returns the member's nickname if they have one, otherwise their username.
129    pub fn display_name(&self) -> &str {
130        if let Some(nick) = &self.nick {
131            return nick.as_str();
132        }
133        self.user
134            .as_ref()
135            .map(|u| u.username.as_str())
136            .unwrap_or("")
137    }
138}
139
140/// A guild role.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct Role {
143    pub id: Snowflake,
144    pub name: String,
145    /// Integer color value. 0 means no color.
146    pub color: Option<u64>,
147    /// Whether this role shows up separately in the member list.
148    pub hoist: Option<bool>,
149    pub icon: Option<String>,
150    pub position: Option<i64>,
151    /// Permission bitfield.
152    pub permissions: Option<String>,
153    /// Managed roles are created by integrations (bot roles, booster role, etc).
154    pub managed: Option<bool>,
155    pub mentionable: Option<bool>,
156}
157
158/// Custom or standard emoji. Custom emojis have both `name` and `id`,
159/// standard unicode emojis only have `name`.
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct Emoji {
162    pub id: Option<Snowflake>,
163    pub name: Option<String>,
164    pub roles: Option<Vec<Snowflake>>,
165    pub user: Option<User>,
166    pub require_colons: Option<bool>,
167    pub managed: Option<bool>,
168    pub animated: Option<bool>,
169    pub available: Option<bool>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct GuildEmojiMetadata {
174    pub id: Snowflake,
175    pub guild_id: Snowflake,
176    pub name: String,
177    pub animated: bool,
178    pub allow_cloning: bool,
179}
180
181impl Emoji {
182    /// Formats the emoji for use in reaction endpoints. Returns `"name:id"` for
183    /// custom emojis or just the name for unicode ones.
184    pub fn to_reaction_string(&self) -> String {
185        match (&self.name, &self.id) {
186            (Some(name), Some(id)) => format!("{}:{}", name, id),
187            (Some(name), None) => name.clone(),
188            _ => String::new(),
189        }
190    }
191}
192
193/// A channel — text, voice, DM, category, etc. Check `kind` to tell them apart.
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct Channel {
196    pub id: Snowflake,
197    /// Channel type, see [`ChannelType`] for values.
198    #[serde(rename = "type")]
199    pub kind: Option<u64>,
200    pub guild_id: Option<Snowflake>,
201    pub position: Option<i64>,
202    pub permission_overwrites: Option<Vec<PermissionOverwrite>>,
203    pub name: Option<String>,
204    pub topic: Option<String>,
205    pub nsfw: Option<bool>,
206    pub last_message_id: Option<Snowflake>,
207    /// Bits per second, for voice channels.
208    pub bitrate: Option<u64>,
209    /// 0 = unlimited.
210    pub user_limit: Option<u64>,
211    /// Slowmode, in seconds.
212    pub rate_limit_per_user: Option<u64>,
213    /// Recipients for DM/group DM channels.
214    pub recipients: Option<Vec<User>>,
215    pub icon: Option<String>,
216    pub owner_id: Option<Snowflake>,
217    pub parent_id: Option<Snowflake>,
218    pub last_pin_timestamp: Option<String>,
219}
220
221/// Numeric channel type values that map to [`Channel::kind`].
222#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
223#[repr(u8)]
224pub enum ChannelType {
225    Text = 0,
226    Dm = 1,
227    Voice = 2,
228    GroupDm = 3,
229    Category = 4,
230    Announcement = 5,
231    Stage = 13,
232}
233
234/// Permission overwrite for a channel. `kind` is 0 for role, 1 for member.
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct PermissionOverwrite {
237    pub id: Snowflake,
238    #[serde(rename = "type")]
239    pub kind: u8,
240    pub allow: Option<String>,
241    pub deny: Option<String>,
242}
243
244/// A message sent in a channel.
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Message {
247    pub id: Snowflake,
248    pub channel_id: Option<Snowflake>,
249    pub guild_id: Option<Snowflake>,
250    pub author: User,
251    /// Only present in guild messages.
252    pub member: Option<Member>,
253    pub content: Option<String>,
254    pub timestamp: Option<String>,
255    pub edited_timestamp: Option<String>,
256    pub tts: Option<bool>,
257    pub mention_everyone: Option<bool>,
258    pub mentions: Option<Vec<User>>,
259    pub mention_roles: Option<Vec<Snowflake>>,
260    pub attachments: Option<Vec<Attachment>>,
261    pub embeds: Option<Vec<Embed>>,
262    pub reactions: Option<Vec<Reaction>>,
263    pub pinned: Option<bool>,
264    pub webhook_id: Option<Snowflake>,
265    /// 0 = default, 19 = reply, etc.
266    #[serde(rename = "type")]
267    pub kind: Option<u8>,
268    /// Full message object for the message being replied to, if the server includes it.
269    pub referenced_message: Option<Box<Message>>,
270    /// Reference metadata (message/channel/guild IDs) always present on reply messages.
271    pub message_reference: Option<MessageReference>,
272    pub flags: Option<u64>,
273    pub stickers: Option<Vec<serde_json::Value>>,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct PinnedMessage {
278    pub message: Message,
279    pub pinned_at: Option<String>,
280}
281
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct PinsResponse {
284    pub items: Vec<PinnedMessage>,
285    pub has_more: Option<bool>,
286}
287
288/// A file attached to a message.
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct Attachment {
291    pub id: Snowflake,
292    pub filename: Option<String>,
293    pub description: Option<String>,
294    pub content_type: Option<String>,
295    pub size: Option<u64>,
296    pub url: Option<String>,
297    pub proxy_url: Option<String>,
298    pub height: Option<u64>,
299    pub width: Option<u64>,
300    pub ephemeral: Option<bool>,
301}
302
303/// A file to attach when sending a message. Pass one or more of these to
304/// [`Http::send_files`] or [`Http::send_message_with_files`].
305pub struct AttachmentFile {
306    /// Filename shown in the client, e.g. `"image.png"`.
307    pub filename: String,
308    pub data: Vec<u8>,
309    /// MIME type, e.g. `"image/png"`. If `None`, defaults to `"application/octet-stream"`.
310    pub content_type: Option<String>,
311}
312
313/// Rich embed. Use [`EmbedBuilder`] to construct these.
314#[derive(Debug, Clone, Serialize, Deserialize, Default)]
315pub struct Embed {
316    pub title: Option<String>,
317    #[serde(rename = "type")]
318    pub kind: Option<String>,
319    pub description: Option<String>,
320    pub url: Option<String>,
321    pub timestamp: Option<String>,
322    /// Sidebar color as an integer, e.g. `0xFF0000` for red.
323    pub color: Option<u64>,
324    pub footer: Option<EmbedFooter>,
325    pub image: Option<EmbedMedia>,
326    pub thumbnail: Option<EmbedMedia>,
327    pub video: Option<EmbedMedia>,
328    pub author: Option<EmbedAuthor>,
329    pub fields: Option<Vec<EmbedField>>,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct EmbedFooter {
334    pub text: String,
335    pub icon_url: Option<String>,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct EmbedMedia {
340    pub url: String,
341    pub height: Option<u64>,
342    pub width: Option<u64>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct EmbedAuthor {
347    pub name: String,
348    pub url: Option<String>,
349    pub icon_url: Option<String>,
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct EmbedField {
354    pub name: String,
355    pub value: String,
356    /// If true, fields can sit side-by-side.
357    #[serde(default)]
358    pub inline: bool,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct Reaction {
363    pub count: u64,
364    pub me: bool,
365    pub emoji: Emoji,
366}
367
368/// Builder for [`Embed`]. Chain methods and call `.build()` at the end.
369///
370/// ```rust
371/// use fluxer::prelude::*;
372///
373/// let embed = EmbedBuilder::new()
374///     .title("Hello")
375///     .description("World")
376///     .color(0x00FF00)
377///     .build();
378/// ```
379#[derive(Debug, Default)]
380pub struct EmbedBuilder(Embed);
381
382impl EmbedBuilder {
383    pub fn new() -> Self {
384        Self::default()
385    }
386
387    pub fn title(mut self, title: impl Into<String>) -> Self {
388        self.0.title = Some(title.into());
389        self
390    }
391    pub fn description(mut self, desc: impl Into<String>) -> Self {
392        self.0.description = Some(desc.into());
393        self
394    }
395    pub fn url(mut self, url: impl Into<String>) -> Self {
396        self.0.url = Some(url.into());
397        self
398    }
399    pub fn color(mut self, color: u64) -> Self {
400        self.0.color = Some(color);
401        self
402    }
403    pub fn timestamp(mut self, ts: impl Into<String>) -> Self {
404        self.0.timestamp = Some(ts.into());
405        self
406    }
407    pub fn footer(mut self, text: impl Into<String>, icon_url: Option<String>) -> Self {
408        self.0.footer = Some(EmbedFooter {
409            text: text.into(),
410            icon_url,
411        });
412        self
413    }
414    pub fn image(mut self, url: impl Into<String>) -> Self {
415        self.0.image = Some(EmbedMedia {
416            url: url.into(),
417            height: None,
418            width: None,
419        });
420        self
421    }
422    pub fn thumbnail(mut self, url: impl Into<String>) -> Self {
423        self.0.thumbnail = Some(EmbedMedia {
424            url: url.into(),
425            height: None,
426            width: None,
427        });
428        self
429    }
430    pub fn author(
431        mut self,
432        name: impl Into<String>,
433        url: Option<String>,
434        icon_url: Option<String>,
435    ) -> Self {
436        self.0.author = Some(EmbedAuthor {
437            name: name.into(),
438            url,
439            icon_url,
440        });
441        self
442    }
443    pub fn field(
444        mut self,
445        name: impl Into<String>,
446        value: impl Into<String>,
447        inline: bool,
448    ) -> Self {
449        let fields = self.0.fields.get_or_insert_with(Vec::new);
450        fields.push(EmbedField {
451            name: name.into(),
452            value: value.into(),
453            inline,
454        });
455        self
456    }
457    pub fn build(self) -> Embed {
458        self.0
459    }
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize)]
463pub struct Invite {
464    pub code: String,
465    pub guild: Option<PartialGuild>,
466    pub channel: Option<PartialChannel>,
467    pub inviter: Option<User>,
468    pub target_user: Option<User>,
469    pub approximate_member_count: Option<u64>,
470    pub expires_at: Option<String>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct RtcRegion {
475    pub id: String,
476    pub name: String,
477    pub emoji: String,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct ChannelSlowmodeState {
482    pub rate_limit_per_user: u64,
483    pub retry_after_ms: u64,
484    pub next_send_allowed_at: Option<String>,
485    pub can_bypass: bool,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
489pub struct GuildVanityUrl {
490    pub code: Option<String>,
491    pub uses: u64,
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct GuildVanityUrlUpdateResponse {
496    pub code: Option<String>,
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize)]
500pub struct PartialGuild {
501    pub id: Snowflake,
502    pub name: String,
503    pub icon: Option<String>,
504    pub splash: Option<String>,
505    pub banner: Option<String>,
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize)]
509pub struct PartialChannel {
510    pub id: Snowflake,
511    pub name: Option<String>,
512    #[serde(rename = "type")]
513    pub kind: Option<u8>,
514}
515
516/// A webhook. Use [`Http::execute_webhook`](crate::http::Http::execute_webhook) to post through one.
517#[derive(Debug, Clone, Serialize, Deserialize)]
518pub struct Webhook {
519    pub id: Snowflake,
520    #[serde(rename = "type")]
521    pub kind: Option<u8>,
522    pub guild_id: Option<Snowflake>,
523    pub channel_id: Option<Snowflake>,
524    pub user: Option<User>,
525    pub name: Option<String>,
526    pub avatar: Option<String>,
527    pub token: Option<String>,
528    pub url: Option<String>,
529}
530
531// --- Gateway event payloads ---
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct TypingStart {
535    pub channel_id: Option<Snowflake>,
536    pub guild_id: Option<Snowflake>,
537    pub user_id: Snowflake,
538    /// Unix timestamp in seconds.
539    pub timestamp: u64,
540    pub member: Option<Member>,
541}
542
543#[derive(Debug, Clone, Serialize, Deserialize)]
544pub struct ReactionAdd {
545    pub user_id: Snowflake,
546    pub channel_id: Option<Snowflake>,
547    pub message_id: Snowflake,
548    pub guild_id: Option<Snowflake>,
549    pub member: Option<Member>,
550    pub emoji: Emoji,
551}
552
553#[derive(Debug, Clone, Serialize, Deserialize)]
554pub struct ReactionRemove {
555    pub user_id: Snowflake,
556    pub channel_id: Option<Snowflake>,
557    pub message_id: Snowflake,
558    pub guild_id: Option<Snowflake>,
559    pub emoji: Emoji,
560}
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct ReactionRemoveAll {
564    pub channel_id: Option<Snowflake>,
565    pub message_id: Snowflake,
566    pub guild_id: Option<Snowflake>,
567}
568
569#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct ReactionRemoveEmoji {
571    pub channel_id: Option<Snowflake>,
572    pub guild_id: Option<Snowflake>,
573    pub message_id: Snowflake,
574    pub emoji: Emoji,
575}
576
577/// Partial message data from an edit. Only changed fields are populated.
578#[derive(Debug, Clone, Serialize, Deserialize)]
579pub struct MessageUpdate {
580    pub id: Snowflake,
581    pub channel_id: Option<Snowflake>,
582    pub guild_id: Option<Snowflake>,
583    pub author: Option<User>,
584    pub content: Option<String>,
585    pub edited_timestamp: Option<String>,
586    pub embeds: Option<Vec<Embed>>,
587    pub attachments: Option<Vec<Attachment>>,
588    pub pinned: Option<bool>,
589    pub flags: Option<u64>,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
593pub struct MessageDelete {
594    pub id: Snowflake,
595    pub channel_id: Option<Snowflake>,
596    pub guild_id: Option<Snowflake>,
597}
598
599#[derive(Debug, Clone, Serialize, Deserialize)]
600pub struct MessageDeleteBulk {
601    pub ids: Vec<Snowflake>,
602    pub channel_id: Option<Snowflake>,
603    pub guild_id: Option<Snowflake>,
604}
605
606#[derive(Debug, Clone, Serialize, Deserialize)]
607pub struct GuildMemberAdd {
608    pub guild_id: Snowflake,
609    #[serde(flatten)]
610    pub member: Member,
611}
612
613#[derive(Debug, Clone, Serialize, Deserialize)]
614pub struct GuildMemberRemove {
615    pub guild_id: Snowflake,
616    pub user: User,
617}
618
619#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct GuildMemberUpdate {
621    pub guild_id: Snowflake,
622    pub roles: Vec<Snowflake>,
623    pub user: User,
624    pub nick: Option<String>,
625    pub joined_at: Option<String>,
626    pub pending: Option<bool>,
627    pub communication_disabled_until: Option<String>,
628}
629
630#[derive(Debug, Clone, Serialize, Deserialize)]
631pub struct Ban {
632    pub reason: Option<String>,
633    pub user: User,
634}
635
636#[derive(Debug, Clone, Serialize, Deserialize)]
637pub struct GuildBanAdd {
638    pub guild_id: Snowflake,
639    pub user: User,
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct GuildBanRemove {
644    pub guild_id: Snowflake,
645    pub user: User,
646}
647
648#[derive(Debug, Clone, Serialize, Deserialize)]
649pub struct GuildRoleCreate {
650    pub guild_id: Snowflake,
651    pub role: Role,
652}
653
654#[derive(Debug, Clone, Serialize, Deserialize)]
655pub struct GuildRoleUpdate {
656    pub guild_id: Snowflake,
657    pub role: Role,
658}
659
660#[derive(Debug, Clone, Serialize, Deserialize)]
661pub struct GuildRoleDelete {
662    pub guild_id: Snowflake,
663    pub role_id: Snowflake,
664}
665
666#[derive(Debug, Clone, Serialize, Deserialize)]
667pub struct ChannelDelete {
668    pub id: Snowflake,
669    #[serde(rename = "type")]
670    pub kind: Option<u8>,
671    pub guild_id: Option<Snowflake>,
672}
673
674#[derive(Debug, Clone, Serialize, Deserialize)]
675pub struct ChannelPinsUpdate {
676    pub guild_id: Option<Snowflake>,
677    pub channel_id: Option<Snowflake>,
678    pub last_pin_timestamp: Option<String>,
679}
680
681/// Received once after connecting. Contains the bot user, session info for
682/// resuming, and the initial guild list.
683#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct Ready {
685    pub v: Option<u64>,
686    pub session_id: String,
687    pub resume_gateway_url: Option<String>,
688    pub user: User,
689    /// Guilds come in as unavailable first; full data arrives via GUILD_CREATE events.
690    pub guilds: Option<Vec<UnavailableGuild>>,
691    /// `[shard_id, num_shards]`
692    pub shard: Option<[u64; 2]>,
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
696pub struct UnavailableGuild {
697    pub id: Snowflake,
698    /// `true` = temporary outage, `false`/absent = bot was removed.
699    pub unavailable: Option<bool>,
700}
701
702#[derive(Debug, Deserialize)]
703pub struct GatewayBotResponse {
704    pub url: String,
705}
706
707#[derive(Debug, Clone, Serialize, Deserialize)]
708pub struct GuildEmojisUpdate {
709    pub guild_id: Snowflake,
710    pub emojis: Vec<serde_json::Value>,
711}
712
713#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct GuildStickersUpdate {
715    pub guild_id: Snowflake,
716    pub stickers: Vec<serde_json::Value>,
717}
718
719#[derive(Debug, Clone, Serialize, Deserialize)]
720pub struct GuildRoleUpdateBulk {
721    pub guild_id: Snowflake,
722    pub roles: Vec<serde_json::Value>,
723}
724
725#[derive(Debug, Clone, Serialize, Deserialize)]
726pub struct ChannelUpdateBulk {
727    pub guild_id: Option<Snowflake>,
728    pub channels: Vec<serde_json::Value>,
729}
730
731#[derive(Debug, Clone, Serialize, Deserialize)]
732pub struct InviteCreate {
733    pub channel_id: Option<Snowflake>,
734    pub guild_id: Option<Snowflake>,
735    pub code: Option<String>,
736}
737
738#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct InviteDelete {
740    pub channel_id: Option<Snowflake>,
741    pub guild_id: Option<Snowflake>,
742    pub code: String,
743}
744
745#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct WebhooksUpdate {
747    pub channel_id: Snowflake,
748    pub guild_id: Option<Snowflake>,
749}
750
751/// Full guild state sync, sent in response to an op 14 subscription request.
752/// Contains the same data as GUILD_CREATE but for already-known guilds.
753#[derive(Debug, Clone, Serialize, Deserialize)]
754pub struct GuildSync {
755    pub id: Snowflake,
756    pub roles: Option<Vec<Role>>,
757    pub channels: Option<Vec<Channel>>,
758    pub emojis: Option<Vec<Emoji>>,
759    pub stickers: Option<Vec<serde_json::Value>>,
760    pub members: Option<Vec<Member>>,
761    pub member_count: Option<u64>,
762    pub online_count: Option<u64>,
763    pub presences: Option<Vec<serde_json::Value>>,
764    pub voice_states: Option<Vec<serde_json::Value>>,
765    pub joined_at: Option<String>,
766    pub unavailable: Option<bool>,
767}
768
769/// Custom status set by a user (the emoji + text shown under their name).
770#[derive(Debug, Clone, Serialize, Deserialize)]
771pub struct CustomStatus {
772    pub text: Option<String>,
773    pub emoji_id: Option<Snowflake>,
774    pub emoji_name: Option<String>,
775    pub expires_at: Option<String>,
776}
777
778/// Fired when a user's presence (status/activity) changes in a guild.
779#[derive(Debug, Clone, Serialize, Deserialize)]
780pub struct PresenceUpdate {
781    pub user: User,
782    pub guild_id: Option<Snowflake>,
783    /// `"online"`, `"idle"`, `"dnd"`, or `"offline"`.
784    pub status: Option<String>,
785    pub mobile: Option<bool>,
786    pub afk: Option<bool>,
787    pub custom_status: Option<CustomStatus>,
788    pub activities: Option<Vec<serde_json::Value>>,
789    pub client_status: Option<serde_json::Value>,
790}
791
792/// Multiple presence updates batched together. `guild_id` is set when the
793/// presences all belong to the same guild.
794#[derive(Debug, Clone, Serialize, Deserialize)]
795pub struct PresenceUpdateBulk {
796    pub presences: Vec<PresenceUpdate>,
797    pub guild_id: Option<Snowflake>,
798}
799
800/// Fired when the current user's settings change. Structure varies; use
801/// the raw `data` field to access specific setting keys.
802#[derive(Debug, Clone, Serialize, Deserialize)]
803pub struct UserSettingsUpdate {
804    #[serde(flatten)]
805    pub data: serde_json::Value,
806}
807
808/// Partial user fields sent with USER_UPDATE.
809#[derive(Debug, Clone, Serialize, Deserialize)]
810pub struct UserUpdate {
811    pub id: Snowflake,
812    pub username: String,
813    pub discriminator: Option<String>,
814    pub avatar: Option<String>,
815    pub flags: Option<u64>,
816}
817
818/// Fired when a channel is marked as read from another session.
819#[derive(Debug, Clone, Serialize, Deserialize)]
820pub struct MessageAck {
821    pub channel_id: Option<Snowflake>,
822    pub message_id: Option<Snowflake>,
823}
824
825/// A single session entry inside [`SessionsReplace`].
826#[derive(Debug, Clone, Serialize, Deserialize)]
827pub struct SessionEntry {
828    pub session_id: String,
829    /// `"online"`, `"idle"`, `"dnd"`, `"invisible"`, or `"offline"`.
830    pub status: Option<String>,
831    pub mobile: Option<bool>,
832    pub afk: Option<bool>,
833}
834
835/// Replaces all active sessions for the current user. Sent when another
836/// device connects or changes presence.
837#[derive(Debug, Clone, Serialize, Deserialize)]
838pub struct SessionsReplace(pub Vec<SessionEntry>);
839
840/// Relationship types from the Fluxer source (`RelationshipTypes` enum).
841#[repr(u8)]
842#[derive(Debug, Clone, Copy, PartialEq, Eq)]
843pub enum RelationshipType {
844    Friend = 1,
845    Blocked = 2,
846    IncomingRequest = 3,
847    OutgoingRequest = 4,
848}
849
850/// Fired when a relationship is added (friend accepted, request sent, block added, etc).
851#[derive(Debug, Clone, Serialize, Deserialize)]
852pub struct RelationshipAdd {
853    /// The other user's ID.
854    pub id: Snowflake,
855    /// See [`RelationshipType`] for values.
856    #[serde(rename = "type")]
857    pub kind: u8,
858}
859
860/// Fired when an existing relationship changes type (e.g. pending → friend).
861#[derive(Debug, Clone, Serialize, Deserialize)]
862pub struct RelationshipUpdate {
863    pub id: Snowflake,
864    #[serde(rename = "type")]
865    pub kind: u8,
866}
867
868/// Fired when a relationship is removed (unfriend, unblock, request cancelled).
869#[derive(Debug, Clone, Serialize, Deserialize)]
870pub struct RelationshipRemove {
871    pub id: Snowflake,
872}
873
874/// Voice state for a participant inside a DM/group call.
875#[derive(Debug, Clone, Serialize, Deserialize)]
876pub struct CallVoiceState {
877    pub user_id: Snowflake,
878    pub channel_id: Option<Snowflake>,
879    pub session_id: Option<String>,
880    pub self_mute: Option<bool>,
881    pub self_deaf: Option<bool>,
882    pub self_video: Option<bool>,
883    pub self_stream: Option<bool>,
884}
885
886/// A VC was started in a DM or group DM.
887#[derive(Debug, Clone, Serialize, Deserialize)]
888pub struct CallCreate {
889    pub channel_id: Snowflake,
890    pub message_id: Option<Snowflake>,
891    pub region: Option<String>,
892    pub voice_states: Option<Vec<CallVoiceState>>,
893    /// User IDs of people currently being rung.
894    pub ringing: Option<Vec<Snowflake>>,
895}
896
897/// A call's state changed (someone joined/left, region changed, etc).
898#[derive(Debug, Clone, Serialize, Deserialize)]
899pub struct CallUpdate {
900    pub channel_id: Snowflake,
901    pub message_id: Option<Snowflake>,
902    pub region: Option<String>,
903    pub voice_states: Option<Vec<CallVoiceState>>,
904    pub ringing: Option<Vec<Snowflake>>,
905}
906
907/// A VC ended or was declined.
908#[derive(Debug, Clone, Serialize, Deserialize)]
909pub struct CallDelete {
910    pub channel_id: Snowflake,
911}
912
913/// A user was added to a group DM channel.
914#[derive(Debug, Clone, Serialize, Deserialize)]
915pub struct ChannelRecipientAdd {
916    pub channel_id: Snowflake,
917    pub user: User,
918}
919
920/// A user was removed from a group DM channel.
921#[derive(Debug, Clone, Serialize, Deserialize)]
922pub struct ChannelRecipientRemove {
923    pub channel_id: Snowflake,
924    pub user: User,
925}
926
927/// A batch of reactions added to a single message (server side debounce).
928#[derive(Debug, Clone, Serialize, Deserialize)]
929pub struct MessageReactionAddMany {
930    pub channel_id: Option<Snowflake>,
931    pub message_id: Snowflake,
932    pub guild_id: Option<Snowflake>,
933    /// Each entry has `user_id`, `emoji` (`id`/`name`), and optionally `member`.
934    pub reactions: Vec<serde_json::Value>,
935}
936
937/// Lazy passive guild update: channel last-message IDs, voice states, and
938/// channel create/update/delete diffs. Sent for large guilds.
939#[derive(Debug, Clone, Serialize, Deserialize)]
940pub struct PassiveUpdates {
941    pub guild_id: Snowflake,
942    /// Map of `channel_id → last_message_id`.
943    pub channels: Option<serde_json::Value>,
944    pub voice_states: Option<Vec<serde_json::Value>>,
945    pub created_channels: Option<Vec<Channel>>,
946    pub updated_channels: Option<Vec<Channel>>,
947    pub deleted_channel_ids: Option<Vec<Snowflake>>,
948}
949
950/// An op inside a [`GuildMemberListUpdate`].
951#[derive(Debug, Clone, Serialize, Deserialize)]
952pub struct MemberListOp {
953    /// `"SYNC"`, `"INSERT"`, `"UPDATE"`, `"DELETE"`, or `"INVALIDATE"`.
954    pub op: String,
955    /// `[start, end]` range, present for SYNC and INVALIDATE.
956    pub range: Option<[u64; 2]>,
957    /// Item index, present for INSERT / UPDATE / DELETE.
958    pub index: Option<u64>,
959    /// Batch of items for SYNC.
960    pub items: Option<Vec<serde_json::Value>>,
961    /// Single item for INSERT / UPDATE / DELETE.
962    pub item: Option<serde_json::Value>,
963}
964
965/// Incremental member list update for a guild channel
966#[derive(Debug, Clone, Serialize, Deserialize)]
967pub struct GuildMemberListUpdate {
968    pub guild_id: Snowflake,
969    /// List identifier (usually matches `channel_id`).
970    pub id: String,
971    pub channel_id: Option<Snowflake>,
972    pub member_count: Option<u64>,
973    pub online_count: Option<u64>,
974    pub groups: Option<Vec<serde_json::Value>>,
975    pub ops: Vec<MemberListOp>,
976}
977
978/// Response to REQUEST_GUILD_MEMBERS (op 8). Contains a chunk of guild members.
979#[derive(Debug, Clone, Serialize, Deserialize)]
980pub struct GuildMembersChunk {
981    pub guild_id: Snowflake,
982    pub members: Vec<Member>,
983    pub chunk_index: u32,
984    pub chunk_count: u32,
985    pub not_found: Option<Vec<Snowflake>>,
986    pub presences: Option<Vec<serde_json::Value>>,
987    pub nonce: Option<String>,
988}
989
990/// A user's voice state changed (joined/left/muted/deafened in a guild voice channel).
991#[derive(Debug, Clone, Serialize, Deserialize)]
992pub struct VoiceStateUpdate {
993    pub user_id: Snowflake,
994    pub guild_id: Option<Snowflake>,
995    pub channel_id: Option<Snowflake>,
996    pub session_id: Option<String>,
997    pub connection_id: Option<String>,
998    pub self_mute: Option<bool>,
999    pub self_deaf: Option<bool>,
1000    pub self_video: Option<bool>,
1001    pub self_stream: Option<bool>,
1002    /// Server-side mute (set by a moderator).
1003    pub mute: Option<bool>,
1004    /// Server-side deafen (set by a moderator).
1005    pub deaf: Option<bool>,
1006    pub is_mobile: Option<bool>,
1007    pub member: Option<Member>,
1008    pub viewer_stream_keys: Option<Vec<String>>,
1009    pub version: Option<u64>,
1010}
1011
1012#[derive(Debug, Clone, Serialize, Deserialize)]
1013pub struct VoiceServerUpdate {
1014    pub token: String,
1015    pub guild_id: Option<Snowflake>,
1016    pub endpoint: Option<String>,
1017}
1018
1019#[derive(Debug, Clone, Serialize, Deserialize)]
1020pub struct Resumed {
1021    #[serde(flatten)]
1022    pub data: serde_json::Value,
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1026pub struct ChannelPinsAck {
1027    pub channel_id: Snowflake,
1028    pub timestamp: Option<String>,
1029}
1030
1031#[derive(Debug, Clone, Serialize, Deserialize)]
1032pub struct UserPinnedDmsUpdate {
1033    pub pinned: Vec<Snowflake>,
1034}
1035
1036#[derive(Debug, Clone, Serialize, Deserialize)]
1037pub struct UserNoteUpdate {
1038    pub id: Snowflake,
1039    pub note: String,
1040}
1041
1042#[derive(Debug, Clone, Serialize, Deserialize)]
1043pub struct UserConnectionsUpdate {
1044    #[serde(flatten)]
1045    pub data: serde_json::Value,
1046}
1047
1048#[derive(Debug, Clone, Serialize, Deserialize)]
1049pub struct UserGuildSettingsUpdate {
1050    pub guild_id: Option<Snowflake>,
1051    #[serde(flatten)]
1052    pub settings: serde_json::Value,
1053}
1054
1055#[derive(Debug, Clone, Serialize, Deserialize)]
1056pub struct AuthSessionChange {
1057    #[serde(flatten)]
1058    pub data: serde_json::Value,
1059}
1060
1061#[derive(Debug, Clone, Serialize, Deserialize)]
1062pub struct SavedMessageCreate {
1063    pub message: Message,
1064}
1065
1066#[derive(Debug, Clone, Serialize, Deserialize)]
1067pub struct SavedMessageDelete {
1068    pub message_id: Snowflake,
1069}
1070
1071#[derive(Debug, Clone, Serialize, Deserialize)]
1072pub struct RecentMentionDelete {
1073    pub message_id: Snowflake,
1074}
1075
1076// --- Request payloads ---
1077
1078/// Attachment metadata entry for the `attachments` field of [`MessageCreatePayload`].
1079/// `id` must match the index used in the corresponding `files[N]` multipart part.
1080#[derive(Debug, Clone, Serialize)]
1081pub struct AttachmentMetadata {
1082    pub id: u64,
1083    pub filename: String,
1084    #[serde(skip_serializing_if = "Option::is_none")]
1085    pub description: Option<String>,
1086}
1087
1088/// Payload for sending/editing messages. All fields optional; only set what you need.
1089#[derive(Debug, Clone, Serialize, Default)]
1090pub struct MessageCreatePayload {
1091    #[serde(skip_serializing_if = "Option::is_none")]
1092    pub content: Option<String>,
1093    #[serde(skip_serializing_if = "Option::is_none")]
1094    pub tts: Option<bool>,
1095    #[serde(skip_serializing_if = "Option::is_none")]
1096    pub embeds: Option<Vec<Embed>>,
1097    #[serde(skip_serializing_if = "Option::is_none")]
1098    pub flags: Option<u64>,
1099    #[serde(skip_serializing_if = "Option::is_none")]
1100    pub message_reference: Option<MessageReference>,
1101    #[serde(skip_serializing_if = "Option::is_none")]
1102    pub referenced_message_id: Option<Snowflake>,
1103    /// Required when uploading files. Populated automatically by
1104    /// [`Http::send_message_with_files`]; you don't need to set this manually.
1105    #[serde(skip_serializing_if = "Option::is_none")]
1106    pub attachments: Option<Vec<AttachmentMetadata>>,
1107}
1108
1109#[derive(Debug, Clone, Serialize, Deserialize)]
1110pub struct MessageReference {
1111    pub message_id: Snowflake,
1112    pub channel_id: Option<Snowflake>,
1113    pub guild_id: Option<Snowflake>,
1114    #[serde(skip_serializing_if = "Option::is_none")]
1115    pub fail_if_not_exists: Option<bool>,
1116}
1117
1118#[derive(Debug, Clone, Serialize, Default)]
1119pub struct ChannelCreatePayload {
1120    pub name: String,
1121    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
1122    pub kind: Option<u8>,
1123    #[serde(skip_serializing_if = "Option::is_none")]
1124    pub topic: Option<String>,
1125    #[serde(skip_serializing_if = "Option::is_none")]
1126    pub bitrate: Option<u64>,
1127    #[serde(skip_serializing_if = "Option::is_none")]
1128    pub user_limit: Option<u64>,
1129    #[serde(skip_serializing_if = "Option::is_none")]
1130    pub rate_limit_per_user: Option<u64>,
1131    #[serde(skip_serializing_if = "Option::is_none")]
1132    pub position: Option<i64>,
1133    #[serde(skip_serializing_if = "Option::is_none")]
1134    pub parent_id: Option<Snowflake>,
1135    #[serde(skip_serializing_if = "Option::is_none")]
1136    pub nsfw: Option<bool>,
1137}
1138
1139/// For nullable fields like `nick`, use `Some(None)` to clear them.
1140#[derive(Debug, Clone, Serialize, Default)]
1141pub struct EditMemberPayload {
1142    #[serde(skip_serializing_if = "Option::is_none")]
1143    pub nick: Option<Option<String>>,
1144    #[serde(skip_serializing_if = "Option::is_none")]
1145    pub roles: Option<Vec<Snowflake>>,
1146    #[serde(skip_serializing_if = "Option::is_none")]
1147    pub mute: Option<bool>,
1148    #[serde(skip_serializing_if = "Option::is_none")]
1149    pub deaf: Option<bool>,
1150    #[serde(skip_serializing_if = "Option::is_none")]
1151    pub channel_id: Option<Option<Snowflake>>,
1152    #[serde(skip_serializing_if = "Option::is_none")]
1153    pub communication_disabled_until: Option<Option<String>>,
1154}
1155
1156#[derive(Debug, Clone, Serialize, Default)]
1157pub struct CreateRolePayload {
1158    pub name: String,
1159    #[serde(skip_serializing_if = "Option::is_none")]
1160    pub permissions: Option<String>,
1161    #[serde(skip_serializing_if = "Option::is_none")]
1162    pub color: Option<u64>,
1163    #[serde(skip_serializing_if = "Option::is_none")]
1164    pub hoist: Option<bool>,
1165    #[serde(skip_serializing_if = "Option::is_none")]
1166    pub mentionable: Option<bool>,
1167}
1168
1169#[derive(Debug, Clone, Serialize, Default)]
1170pub struct EditRolePayload {
1171    #[serde(skip_serializing_if = "Option::is_none")]
1172    pub name: Option<String>,
1173    #[serde(skip_serializing_if = "Option::is_none")]
1174    pub permissions: Option<String>,
1175    #[serde(skip_serializing_if = "Option::is_none")]
1176    pub color: Option<u64>,
1177    #[serde(skip_serializing_if = "Option::is_none")]
1178    pub hoist: Option<bool>,
1179    #[serde(skip_serializing_if = "Option::is_none")]
1180    pub mentionable: Option<bool>,
1181}
1182
1183#[derive(Debug, Clone, Serialize, Default)]
1184pub struct CreateInvitePayload {
1185    /// Seconds. 0 = never expires.
1186    #[serde(skip_serializing_if = "Option::is_none")]
1187    pub max_age: Option<u64>,
1188    /// 0 = unlimited.
1189    #[serde(skip_serializing_if = "Option::is_none")]
1190    pub max_uses: Option<u64>,
1191    /// If true, members joined via this invite get kicked when they disconnect
1192    /// (unless they've been given a role).
1193    #[serde(skip_serializing_if = "Option::is_none")]
1194    pub temporary: Option<bool>,
1195    #[serde(skip_serializing_if = "Option::is_none")]
1196    pub unique: Option<bool>,
1197}
1198
1199/// Query params for fetching messages. Only set one of `before`/`after`/`around`.
1200#[derive(Debug, Clone, Default)]
1201pub struct GetMessagesQuery {
1202    /// 1-100.
1203    pub limit: Option<u8>,
1204    pub before: Option<Snowflake>,
1205    pub after: Option<Snowflake>,
1206    pub around: Option<Snowflake>,
1207}
1208
1209impl GetMessagesQuery {
1210    pub fn to_query_string(&self) -> String {
1211        let mut parts = Vec::new();
1212        if let Some(l) = self.limit {
1213            parts.push(format!("limit={}", l.min(100)));
1214        }
1215        if let Some(ref b) = self.before {
1216            parts.push(format!("before={}", b));
1217        }
1218        if let Some(ref a) = self.after {
1219            parts.push(format!("after={}", a));
1220        }
1221        if let Some(ref ar) = self.around {
1222            parts.push(format!("around={}", ar));
1223        }
1224        if parts.is_empty() {
1225            String::new()
1226        } else {
1227            format!("?{}", parts.join("&"))
1228        }
1229    }
1230}
1231
1232#[derive(Debug, Clone, Serialize, Default)]
1233pub struct EditGuildPayload {
1234    #[serde(skip_serializing_if = "Option::is_none")]
1235    pub name: Option<String>,
1236    #[serde(skip_serializing_if = "Option::is_none")]
1237    pub description: Option<String>,
1238    #[serde(skip_serializing_if = "Option::is_none")]
1239    pub preferred_locale: Option<String>,
1240    #[serde(skip_serializing_if = "Option::is_none")]
1241    pub afk_channel_id: Option<Option<Snowflake>>,
1242    #[serde(skip_serializing_if = "Option::is_none")]
1243    pub afk_timeout: Option<u64>,
1244    #[serde(skip_serializing_if = "Option::is_none")]
1245    pub verification_level: Option<u64>,
1246    #[serde(skip_serializing_if = "Option::is_none")]
1247    pub default_message_notifications: Option<u64>,
1248    #[serde(skip_serializing_if = "Option::is_none")]
1249    pub explicit_content_filter: Option<u64>,
1250}
1251
1252/// Query payload for [`Http::search_messages`]. All fields are optional — set
1253/// only the filters you need. `scope` defaults to `"current"` server side.
1254#[derive(Debug, Clone, Serialize, Default)]
1255pub struct SearchMessagesQuery {
1256    /// Results per page, 1–25.
1257    #[serde(skip_serializing_if = "Option::is_none")]
1258    pub hits_per_page: Option<u8>,
1259    #[serde(skip_serializing_if = "Option::is_none")]
1260    pub page: Option<u32>,
1261    /// Full-text content search.
1262    #[serde(skip_serializing_if = "Option::is_none")]
1263    pub content: Option<String>,
1264    /// Restrict to these channel IDs.
1265    #[serde(skip_serializing_if = "Option::is_none")]
1266    pub channel_id: Option<Vec<Snowflake>>,
1267    /// Restrict to messages by these author IDs.
1268    #[serde(skip_serializing_if = "Option::is_none")]
1269    pub author_id: Option<Vec<Snowflake>>,
1270    /// Filter by attachment/embed type: `"image"`, `"video"`, `"file"`,
1271    /// `"sticker"`, `"embed"`, `"link"`, `"poll"`.
1272    #[serde(skip_serializing_if = "Option::is_none")]
1273    pub has: Option<Vec<String>>,
1274    #[serde(skip_serializing_if = "Option::is_none")]
1275    pub pinned: Option<bool>,
1276    /// `"timestamp"` or `"relevance"`.
1277    #[serde(skip_serializing_if = "Option::is_none")]
1278    pub sort_by: Option<String>,
1279    /// `"asc"` or `"desc"`.
1280    #[serde(skip_serializing_if = "Option::is_none")]
1281    pub sort_order: Option<String>,
1282    /// `"current"`, `"open_dms"`, `"all_dms"`, `"all_guilds"`, or `"all"`.
1283    #[serde(skip_serializing_if = "Option::is_none")]
1284    pub scope: Option<String>,
1285}
1286
1287/// Returned by [`Http::search_messages`].
1288#[derive(Debug, Clone, Deserialize)]
1289pub struct SearchMessagesResponse {
1290    pub messages: Vec<Message>,
1291    pub total: u64,
1292    pub hits_per_page: u8,
1293    pub page: u32,
1294}
1295
1296/// Audit log entry from the gateway.
1297#[derive(Debug, Clone, Serialize, Deserialize)]
1298pub struct GuildAuditLogEntryCreate {
1299    pub id: Snowflake,
1300    pub guild_id: Option<Snowflake>,
1301    pub action_type: Option<u64>,
1302    pub user_id: Option<Snowflake>,
1303    pub target_id: Option<Snowflake>,
1304    pub reason: Option<String>,
1305    pub changes: Option<Vec<AuditLogChange>>,
1306    /// Extra context depending on the action e.g. channel name/type for channel creates.
1307    pub options: Option<serde_json::Value>,
1308}
1309
1310#[derive(Debug, Clone, Serialize, Deserialize)]
1311pub struct AuditLogUser {
1312    pub id: Snowflake,
1313    pub username: String,
1314    pub discriminator: String,
1315    pub global_name: Option<String>,
1316    pub avatar: Option<String>,
1317    pub avatar_color: Option<u64>,
1318    pub bot: Option<bool>,
1319    pub system: Option<bool>,
1320    pub flags: u64,
1321    pub mention_flags: Option<u64>,
1322}
1323
1324#[derive(Debug, Clone, Serialize, Deserialize)]
1325pub struct AuditLogWebhook {
1326    pub id: Snowflake,
1327    #[serde(rename = "type")]
1328    pub kind: Option<u8>,
1329    pub guild_id: Option<Snowflake>,
1330    pub channel_id: Option<Snowflake>,
1331    pub name: String,
1332    pub avatar_hash: Option<String>,
1333}
1334
1335#[derive(Debug, Clone, Serialize, Deserialize)]
1336pub struct GuildAuditLogList {
1337    pub audit_log_entries: Vec<GuildAuditLogEntryCreate>,
1338    pub users: Vec<AuditLogUser>,
1339    pub webhooks: Vec<AuditLogWebhook>,
1340}
1341
1342/// A single changed field inside an audit log entry.
1343#[derive(Debug, Clone, Serialize, Deserialize)]
1344pub struct AuditLogChange {
1345    pub key: String,
1346    pub new_value: Option<serde_json::Value>,
1347    pub old_value: Option<serde_json::Value>,
1348}
1349
1350/// A single entry for [`Http::ack_bulk`]. Marks `message_id` as the last-read
1351/// message in `channel_id`.
1352#[derive(Debug, Clone, Serialize)]
1353pub struct ReadStateAck {
1354    pub channel_id: Snowflake,
1355    pub message_id: Snowflake,
1356}
1357
1358#[derive(Debug, Clone, Serialize, Default)]
1359pub struct GuildCreatePayload {
1360    pub name: String,
1361    #[serde(skip_serializing_if = "Option::is_none")]
1362    pub icon: Option<String>,
1363    #[serde(skip_serializing_if = "Option::is_none")]
1364    pub empty_features: Option<bool>,
1365    #[serde(skip_serializing_if = "Option::is_none")]
1366    pub template: Option<serde_json::Value>,
1367}
1368
1369#[derive(Debug, Clone, Serialize, Default)]
1370pub struct GuildVanityUrlUpdatePayload {
1371    #[serde(skip_serializing_if = "Option::is_none")]
1372    pub code: Option<String>,
1373}
1374
1375#[derive(Debug, Clone, Serialize, Default)]
1376pub struct WebhookExecutePayload {
1377    #[serde(skip_serializing_if = "Option::is_none")]
1378    pub content: Option<String>,
1379    /// Override the webhook's name for this message.
1380    #[serde(skip_serializing_if = "Option::is_none")]
1381    pub username: Option<String>,
1382    /// Override the webhook's avatar for this message.
1383    #[serde(skip_serializing_if = "Option::is_none")]
1384    pub avatar_url: Option<String>,
1385    #[serde(skip_serializing_if = "Option::is_none")]
1386    pub tts: Option<bool>,
1387    #[serde(skip_serializing_if = "Option::is_none")]
1388    pub embeds: Option<Vec<Embed>>,
1389    /// Reply to a message in the same channel. Only `message_id` is needed.
1390    #[serde(skip_serializing_if = "Option::is_none")]
1391    pub message_reference: Option<WebhookMessageReference>,
1392}
1393
1394/// Message to reply to when executing a webhook.
1395#[derive(Debug, Clone, Serialize, Default)]
1396pub struct WebhookMessageReference {
1397    pub message_id: Snowflake,
1398}
1399
1400#[derive(Debug, Clone, Serialize, Default)]
1401pub struct WebhookEditPayload {
1402    #[serde(skip_serializing_if = "Option::is_none")]
1403    pub content: Option<String>,
1404    #[serde(skip_serializing_if = "Option::is_none")]
1405    pub embeds: Option<Vec<Embed>>,
1406}