A Rust library for the Discord API.
Thanks to the following for their contributions:
In this release, the standard framework has been deprecated (#2733).
As Discord continues to endorse and evolve application commands (/...
commands, user commands, message commands, etc.), the standard framework becomes increasingly outdated. Bots are also steadily losing (and already have lost) access to contents of messages, making it difficult to build a prefix-only bot. Unless you plan on restricting your bot to only accept commands in DMs, allowing its presence in only fewer than 100 guilds, or presenting a reasonable justification to Discord for permission to continue using message contents, you should migrate to application commands. We recommend poise, which supports writing both prefix and application commands with a #[command]
macro like the standard framework.
Poise already exists and is better than the standard framework. Efforts should be directed at improving poise instead. To support application commands would require an overhaul of the standard framework, as they are special (for instance, Discord parses arguments on behalf of the bot and passes them as structured data, whereas for prefix commands, the bot must parse by itself).
RoleId::to_role_cached
- Use Guild::roles
instead.bitflags!
types, resulting in a smaller memory footprint.guildid
/guild
instead.This release turned out to be one of serenity's largest ever, with well over 300 PRs in total! It contains quite a few major breaking changes to the API. Therefore, the changelog for this release also serves as a migration guide for users upgrading from the 0.11 series.
Thanks to the following for their contributions:
The closure-based API for constructing requests using the builder pattern has been ripped out and replaced. In place of closures, users must now pass in builder types directly. For example, in serenity 0.11, code like the following was very common:
let channel = guild
.create_channel(&http, |c| c.name("my-test-channel").kind(ChannelType::Text))
.await?;
Now, users instead write the following code:
let builder = CreateChannel::new("my-test-channel").kind(ChannelType::Text);
let channel = guild.create_channel(&http, builder).await?;
Or, inline like so:
let channel = guild
.create_channel(&http, CreateChannel::new("my-test-channel").kind(ChannelType::Text))
.await?;
Note that in this particular example, the channel name is now a mandatory field that must be passed in when constructing the builder. Mutating the builder with subsequent calls to CreateChannel::name
will change the underlying value. Additionally, all methods on builders now take mut self
and return Self
, instead of taking and returning &mut self
/&mut Self
. This allows for explicit construction as in the second example above. Also, builders no longer wrap a pub HashMap<&'static str, T>
; the hashmap has been flattened into concrete private fields.
Some benefits to this new approach to builders are:
AttachmentType
enum has been replaced with a CreateAttachment
builder struct. This struct has the file
, path
, and url
constructors that eagerly evaluate the data passed to them - CreateAttachment
simply stores the resulting raw data. This is in contrast to AttachmentType
which lazily carried filepaths/urls with it, and had data
and filename
methods for resolving them. Additionally, the CreateAttachment::to_base64
method can be used to manually encode an attachment if needed.EditAttachments
builder struct has been added for use with the attachments
method on the EditMessage
, EditWebhookMessage
, and EditInteractionResponse
builders. This new builder provides finer control when editing a message's existing attachments or uploading additional ones. Also, the following methods have been renamed to more accurately reflect their behavior:serenity v0.11 | serenity v0.12 |
---|---|
EditMessage::attachment |
EditMessage::new_attachment |
EditMessage::add_existing_attachment |
EditMessage::keep_existing_attachment |
EditWebhookMessage::clear_existing_attachments |
EditWebhookMessage::clear_attachments |
EditInteractionResponse::clear_existing_attachments |
EditInteractionResponse::clear_attachments |
Collectors have been redesigned and simplified at no cost to expressibility. There is now a generic collector::collect
function which takes a closure as argument, letting you filter events as they stream in.
ComponentInteractionCollector
, ModalInteractionCollector
, MessageCollector
, and ReactionCollector
) are simply convenience structs that wrap this underlying function.EventCollector
is now deprecated, as its use usually involved anti-patterns around fallibility. However, its functionality can still be replicated using collector::collect
. See example 10 for more details.RelatedId
and RelatedIdsForEventType
types have been removed as they were only used by EventCollector
. Methods for retrieving them from events have also been removed; if users wish to extract "related" ids from an event, they should do so directly from the event's fields. The removed methods are the following:
Event::user_id
Event::guild_id
Event::channel_id
Event::message_id
EventType::related_ids
In an effort to shorten long names and make import paths less unwieldy, Serenity now uses command
instead of application_command
in all places, except for the Permissions::USE_APPLICATION_COMMANDS
constant. This includes methods on the Http
, GuildId
, Guild
, PartialGuild
, and Command
types, as well as a few other miscellaneous places:
serenity v0.11 | serenity v0.12 |
---|---|
Http::*_{global,guild}_application_command* |
Http::*_{global,guild}_command* |
{GuildId,Guild,PartialGuild}::*_application_command* |
{GuildId,Guild,PartialGuild}::*_command* |
Command::*_global_application_command* |
Command::*_global_command* |
Interaction::application_command |
Interaction::command |
EventHandler::application_command_permissions_update |
EventHandler::command_permissions_update |
Route::ApplicationCommand* |
Route::Command* |
Permissions::use_application_commands |
Permissions::use_commands |
Additionally, the following command types have been renamed:
serenity v0.11 | serenity v0.12 |
---|---|
CreateApplicationCommand |
CreateCommand |
CreateApplicationCommandOption |
CreateCommandOption |
CreateApplicationCommandPermissionData |
CreateCommandPermission |
CreateApplicationCommandPermissionsData |
EditCommandPermissions |
CommandPermission |
CommandPermissions |
CommandPermissionData |
CommandPermission |
Furthermore, the methods on CreateCommandPermission
, such as new
, kind
, etc. have been replaced with constructors for each type of permission, e.g. role
, user
, channel
, etc., to avoid a possible mismatch between kind
and the id that gets passed in.
Finally, the {GuildId,Guild,PartialGuild}::create_command_permission
method has been renamed to edit_command_permission
to more accurately reflect its behavior.
CacheRef
type that wraps a reference into the cache. Other methods that returned a map, now return a wrapper type around a reference to the map, with a limited API to prevent accidental deadlocks. This all helps reduce the number of clones when querying the cache. Those wishing to replicate the old behavior can simply call .clone()
on the return type to obtain the wrapped data.CacheSettings
has new fields time_to_live
, cache_guilds
, cache_channels
, and cache_users
, allowing cache configuration on systems with memory requirements; whereas previously, memory-constrained systems were forced to disable caching altogether.PrivateChannel
s (aka DM channels) has been removed, as they are never sent across the gateway by Discord. Therefore, the Cache::{private_channel, private_channels}
methods have been removed, and Cache::guild_channel
has been renamed to just Cache::channel
. Additionally, some uses of the Channel
enum in return types have been replaced with either GuildChannel
or PrivateChannel
as seen fit.All *Id
types have had their internal representations made private. Therefore, the API has changed as follows:
serenity v0.11 | serenity v0.12 |
---|---|
ExampleId(12345) |
ExampleId::new(12345) |
example_id.as_u64() |
example_id.get() |
Note that all *Id
types now implement Into<u64>
and Into<i64>
. Additionally, attempting to instantiate an id with a value of 0
will panic.
Also, the implementations of FromStr
for the UserId
, RoleId
, and ChannelId
types now expect an integer rather than a mention string. The following table shows the new expected input strings:
serenity v0.11 | serenity v0.12 | |
---|---|---|
ChannelId |
<#81384788765712384> |
81384788765712384 |
RoleId |
<@&136107769680887808> |
136107769680887808 |
UserId |
<@114941315417899012> or <@!114941315417899012> |
114941315417899012 |
Users wishing to parse mentions should either parse into a Mention
object, or use the utils::{parse_user_mention, parse_role_mention, parse_channel_mention}
methods.
The various interaction types have been renamed as follows:
serenity v0.11 | serenity v0.12 |
---|---|
ApplicationCommandInteraction |
CommandInteraction |
MessageComponentInteraction |
ComponentInteraction |
ModalSubmitInteraction |
ModalInteraction |
Method names on interaction types have been shortened in the following way:
serenity v0.11 | serenity v0.12 |
---|---|
create_interaction_response |
create_response |
create_followup_message |
create_followup |
delete_original_interaction_response |
delete_response |
delete_followup_message |
delete_followup |
edit_original_interaction_response |
edit_response |
edit_followup_message |
edit_followup |
get_interaction_response |
get_response |
get_followup_message |
get_followup |
AutocompleteInteraction
has been merged into CommandInteraction
, along with its corresponding methods.kind
field has been removed from each of the interaction structs.quick_modal
method has been added to CommandInteraction
and ComponentInteraction
. See the docs for more details.The standard framework is now configurable at runtime, as the configure
method now takes self
by reference. In line with the builder changes, the Configuration
and BucketBuilder
builders are no longer closure-based and must be passed in directly. Also, the Framework
trait has been reworked to accomodate more use cases than just text commands:
dispatch
method now takes a FullEvent
as argument instead of just a Message
. This enum contains all the data that is passed to the EventHandler
.init
method has been added, that allows for more complex framework initialization, which can include executing HTTP requests, or accessing cache or shard data.As a result, the trait now accomodates alternative frameworks more easily, such as poise.
WsStream
to WsClient
.ShardManagerMonitor
and ShardManagerMessage
types have been removed. Their functionality has been replicated via methods directly on ShardManager
. Any fields with type Sender<ShardManagerMessage>
, as well as the Client::shard_manager
field, have had their types changed to Arc<ShardManager>
. The new methods on ShardManager
are the following:
return_with_value
shutdown_finished
restart_shard
update_shard_latency_and_stage
ShardClientMessage
and InterMessage
enums were deemed redundant wrappers around ShardRunnerMessage
and removed - users should use ShardRunnerMessage
directly instead.ShardManagerError
type is removed in favor of GatewayError
.Shard::heartbeat_instants
. Users should instead use the last_heartbeat_{sent,ack}
methods, which now return Option<Instant>
instead of Option<&Instant>
.Shard::heartbeat_interval
to return Option<Duration>
instead of Option<u64>
.Shard::check_heartbeat
to do_heartbeat
.ShardMessenger::new
now takes &ShardRunner
as argument instead of Sender<ShardRunnerMessage>
.ShardRunnerMessage::AddCollector
variant in favor of the ShardMessenger::add_collector
method. This method adds the collectors immediately, whereas ShardRunnerMessage
is polled periodically in a loop - this could occasionally cause collectors to drop the first event they received.serenity::client::bridge::{gateway,voice}::*
have been moved into serenity::gateway
. They are now gated behind the gateway
feature instead of the client
feature, however most users use these features in conjunction, and so should not see a change in required-enabled features.Serenity now uses Rust edition 2021, with an MSRV of Rust 1.74.
thread_id
parameter to Http::{get,edit,delete}_webhook_message
, Http::execute_webhook}
, as well as Webhook::{get,delete}_message
.audit_log_reason
parameter to many Http
methods and builder structs.EventHandler::shards_ready
method.Default
for many model types.button
and select_menu
methods to the following builders:
CreateInteractionResponseMessage
CreateInteractionResponseFollowup
EditInteractionResponse
CreateMessage
EditMessage
EditWebhookMessage
ExecuteWebhook
ChannelId::create_forum_post
and GuildChannel::create_forum_post
.event_handler
and raw_event_handler
fields with pluralized event_handlers
and raw_event_handlers
in the following structs:
ShardManagerOptions
ShardQueuer
ShardRunner
ShardRunnerOptions
ClientBuilder
ReactionRemoveEmoji
and GuildAuditLogEntryCreate
.serenity::all
module, which re-exports most public items in the crate.CreateButton::custom_id
method.{GuildId, Guild, PartialGuild}::edit_mfa_level
.EditWebhookMessage
endpoint by adding a new_attachments
parameter to Http::edit_webhook_message
, as well as the following methods to the EditWebhookMessage
builder:
attachment
add_existing_attachment
remove_existing_attachment
User::global_name
field, and by making discriminators on usernames optional and non-zero. In particular, the PresenceUser::discriminator
and User::discriminator
fields are now of type Option<NonZeroU16>
.{GuildId,Guild,PartialGuild}::current_user_member
method.User::static_face
method, mirroring User::face
.VOICE_CHANNEL_STATUS_UPDATE
gateway event.GuildId::everyone_role
method.CREATE_EVENTS
and CREATE_GUILD_EXPRESSIONS
permissions, and rename MANAGE_EMOJIS_AND_STICKERS
to MANAGE_GUILD_EXPRESSIONS
(the old name is still present but deprecated).FormattedTimestamp
utility struct for representing a combination of a timestamp and a formatting style.utils::argument_convert::parse_message_url
.Hash
to Timestamp
's derive list.typesize
support.From<Into<String>>
for AutocompleteChoice
.Request::body_ref
now returns Option<&T>
instead of &Option<&T>
.Typing::stop
now returns bool
instead of Option<()>
. Also, Typing::start
and any wrapper methods are now infallible.async
:
ChannelId::name
Context::*
Guild::{members_starting_with, members_containing, members_username_containing, members_nick_containing}
Guild::default_channel
PartialGuild::greater_member_hierarchy
ShardManager::new
UserId::to_user_cached
Error::Http
variant.Guild::member
to return Cow<'_, Member>
instead of just Member
.ShardManagerOptions
to be owned (Arc
is cheap to clone).u8
.RequestBuilder::body
from Option<&[u8]>
to Option<Vec<u8>>
.MessageInteraction
non-exhaustive, and add a member
field.Permissions::USE_SLASH_COMMANDS
to USE_APPLICATION_COMMANDS
.constants::OpCode
to Opcode
, and the same for voice_model::OpCode
.ShardInfo
for tracking Shard ids, and change ids from u64
to u32
.Message::nonce
field to a custom Nonce
enum instead of a serde_json::Value
.MembershipState
, ScheduledEventStatus
, and ScheduledEventType
non-exhaustive.MessageActivityKind
variants to use CamelCase instead of ALL_CAPS.CurrentPresence
with a PresenceData
struct.ActivityData
in place of Activity
for setting the current presence.set_activity
methods to take an Option<ActivityData>
to allow for clearing the current presence by passing in None
.ClientBuilder
, and adding an optional presence
parameter to Shard::new
.Unknown
variants on enums are now changed to Unknown(u8)
. Also, the num
method for those enums is removed; users should call u8::from
instead.Member::edit
to edit in place, and return Result<()>
instead of Result<Message>
.u32
, u64
, or NonZeroU64
.{GuildId, Guild, PartialGuild}::delete
to return Result<()>
.impl From<String> for Timestamp
with impl TryFrom<&str>
.const
:
LightMethod::reqwest_method
Ratelimit::{limit, remaining, reset, reset_after}
RequestBuilder::new
Channel::{id, position, name}
Error::is_cache_err
Event::event_type
EventType::name
GatewayIntents::*
Permissions::*
CommonFilterOptions::{filter_limit, collect_limit}
fields from u32
to NonZeroU32
.GuildChannel::message_count
field from Option<u8>
to Option<u32>
.serenity::utils::colour
module into serenity::model
.CreateAllowedMentions::parse
with all_users
, all_roles
, and everyone
methods.ChannelId::name
to return Result<String>
instead of Option<String>
.EventHandler
methods if the cache
feature is disabled. Relevant cache-dependant data is now passed in using Option
.u32
.Future
for ClientBuilder
with IntoFuture
.ClientBuilder::{get_token, get_type_map, get_cache_settings}
infallible.CacheUpdate::Output
for ChannelDeleteEvent
from ()
to Vec<Message>
.Box
:
CommandInteraction::member
ComponentInteraction::message
ModalInteraction::message
Message::member
Message::interaction
CreateSelectMenuKind
and ComponentInteractionDataKind
enums to better enforce well-formation of requests.http
module by re-exporting all types found in submodules at the top level and removinng access to the submodules themselves.ErrorResponse
non-exhaustive, change the url
field from Url
to String
, and add a method
field.Http::ratelimiter
field in Option
, and remove the corresponding ratelimiter_disabled
field.reason
parameter to Http::{ban, kick}
, and remove Http::{ban,kick}_with_reason
.Route
and RouteInfo
enums, and add method
and params
fields to the Request
struct.model::application
module in the same way the http
module was flattened.ThreadMembersUpdateEvent::member_count
field from u8
to i16
.GuildUpdateEvent::guild
from PartialGuild
to Guild
Reaction::member
from Option<PartialMember>
to Member
Integration::guild_id
from GuildId
to Option<GuildId>
IncidentUpdate::status
from IncidentStatus
to String
(IncidentStatus
is also removed){Guild,PartialGuild}::premium_subscription_count
from u64
to Option<u64>
InputText::value
from String
to Option<String>
CurrentApplicationInfo::owner
from User
to Option<User>
ScheduledEventMetadata::location
from String
to Option<String>
Trigger::KeywordPreset
from a tuple variant to a struct variantIncident::short_link
to shortlink
ThreadDeleteEvent::channels_id
to channel_ids
ThreadMembersUpdateEvent::removed_members_ids
to removed_member_ids
InviteTargetType::EmmbeddedApplication
to EmbeddedApplication
Scope::RelactionshipsRead
to RelationshipsRead
CurrentUser
to be a newtype around User
, implement the Deref
trait, and remove the guilds
, invite_url
, and invite_url_with_oauth2_scopes
methods. The only method now unique to CurrentUser
is edit
. All other methods are available to call via deref coercion.model
types non-exhaustive:
model::application::{Interaction, ActionRow, Button, SelectMenu, SelectMenuOption, InputText}
model::application::{PartialCurrentApplicationInfo, Team, TeamMember, InstallParams}
model::channel::{PartialGuildChannel, ChannelMention}
model::gateway::{ActivityEmoji, ClientStatus}
model::guild::{Ban, GuildPrune, GuildInfo, UnavailableGuild, GuildWelcomeScreen}
model::guild::{ScheduledEventMetadata, ScheduledEventUser}
model::guild::automod::{Rule, TriggerMetadata, Action, ActionExecution}
model::misc::EmojiIdentifier
CacheUpdate::Output
for ChannelUpdateEvent
from ()
to Channel
. Also, make {Guild,PartialGuild}::user_permissions_in
infallible and change Error::InvalidPermissions
into a struct variant containing both the the required
permissions as well as the present
permissions.secrecy::SecretString
to prevent them being leaked through Debug
implementations, and so that they are zeroed when dropped.String
s to a dedicated ImageHash
type which saves on space by storing the hash directly as bytes.rate_limit_per_user
fields are now counted using a u16
.position
fields now hold a u16
.positition
fields now hold a u16
.auto_archive_position
fields are now an enum AutoArchivePosition
.afk_timeout
fields are now an enum AfkTimeout
.DefaultReaction
struct with a ForumEmoji
enum.Sticker::sort_value
field is now an Option<u16>
.min_values
and max_values
fields for Select Menus now hold a u8
.max_age
invite field now holds a u32
.max_uses
invite field now holds a u8
.ActivityParty
current and maximum size are now of type u32
.Ready::version
field is now a u8
.min_length
and max_length
fields for Input Text components now hold a u16
.mention_total_limit
field for automod triggers now holds a u8
.RoleSubscriptionData::total_months_subscribed
field is now a u16
.{Http,ChannelId,GuildChannel}::create_public_thread
to create_thread_from_message
, and similarly rename create_private_thread
to create_thread
, to more accurately reflect their behavior. The corresponding endpoints have also been renamed from ChannelPublicThreads
/ChannelPrivateThreads
, to ChannelMessageThreads
/ChannelThreads
, respectively.ThreadDelete
event now provides the full GuildChannel
object for the deleted thread if it is present in the cache.ThreadUpdate
event now provides the old thread's GuildChannel
object if it is present in the cache.Webhook::source_guild
and Webhook::source_channel
fields have had their types changed from Option<PartialGuild>
/Option<PartialChannel>
to their own Option<WebhookGuild>
/Option<WebhookChannel>
types in order to avoid deserialization errors. These new types contain very few fields, but have methods for converting into PartialGuild
s or Channel
s by querying the API.json::prelude
module with public wrapper functions that abstract over both serde_json
and simd-json
.GatewayIntents::GUILD_BANS
to GUILD_MODERATION
(the old name is still present but is deprecated).CreateInteractionResponseMessage::flags
to take InteractionResponseFlags
instead of MessageFlags
.ThreadMember
into PartialThreadMember
.GuildId::audit_logs
.Guild::members_with_status
to return impl Iterator<Item = &Member>
instead of Vec<Member>
.model::application::ResolvedTarget
.model::guild::GuildContainer
.EventHandler::{guild_unavailable, unknown}
.EditProfile::{email, password, new_password}
.serenity::json::from_number
. Users should call .into()
instead.Channel::Category
variant, as GuildChannel::kind
can already be ChannelType::Category
. However, the Channel::category
method is still available.Mention::Emoji
variant.serenity::token::parse
- use token::validate
instead.absolute_ratelimits
feature and replace it with a runtime configuration option.CacheAndHttp
, and inline it as separate cache
and http
fields in the following structs:
ShardManagerOptions
ShardQueuer
ShardRunner
ShardRunnerOptions
Client
VoiceServerUpdateEvent::channel_id
ResumedEvent::channel_id
Ready::{presences, private_channels, trace}
InviteGuild::{text_channel_count, voice_channel_count}
VoiceState::token
IncidentUpdate::affected_components
(and also the AffectedComponent
struct)Maintenance::{description, stop, start}
SelectMenu::values
MessageUpdateEvent::{author, timestamp, nonce, kind, stickers}
PartialGuild::{owner, permissions}
InviteTargetType::Normal
Trigger::HarmfulLink
FromStrAndCache
and StrExt
traits. Also removes model::{ChannelParseError,RoleParseError}
, which conflicted with types of the same name from utils
.model
from the model::prelude
, and don't re-export types from other libraries, like Deserialize
or HashMap
.DefaultAvatar
enum.PartialOrd
/Ord
:
EventType
enum. Instead of Event::event_type().name()
, users should just call Event::name
.PingInteraction::guild_locale
field.This is the second iteration of 0.12's Release Candidate. Notable inclusions since the prior iteration are:
Event::Unknown
wrap UnknownEvent
againtypesize
supportThis is the Release Candidate for v0.12.0. For the list of changes made (which there are a ton), see the CHANGELOG file at the root of the repository.
Thanks to the following for their contributions:
MessageComponentInteraction::edit_original_message()
for editing the original message of the message component.std::str::FromStr
for the ID types to allow converting from a string. This does not affect the pre-existing implementation on ChannelId
, RoleId
, and UserId
.set_components()
methods on EditInteractionResponse
and EditWebhookMessage
delete_reaction
and delete_reactions
methods for deleting reactions to ChannelId
, GuildChannel
, and Message
.base64
dependency to 0.21
Special thanks to @mkrasnitski for writing this changelog :heart:
Thanks to the following for their contributions:
Timestamp
usable regardless of the chrono
or time
features.BucketBuilder::await_ratelimits
to 1
upon BucketBuilder::delay_action
being set.EventHandler::ratelimit
method.MessageUpdateEvent
:
mention_channels
reactions
components
sticker_items
Shard::handle_event
publicly.User::member
, as well as Message:{thread, application_id}
fields.defer_ephemeral
helper method to many interaction types.as_*
and into_*
helper methods to the Interaction
type for converting to each of its respective variants.UserPublicFlags::ACTIVE_DEVELOPER
flag.flags
total_messages_sent
available_tags
applied_tags
default_reaction_emoji
default_thread_rate_limit_per_user
default_sort_order
owner_id
in thread and forum channels.SUPPRESS_NOTIFICATIONS
message flag.Http::get_{guild,global}_application_commands_with_localizations
Command::get_global_application_commands_with_localizations
{GuildId,Guild,PartialGuild}::get_application_commands_with_localizations
remove_all_attachments
method to EditMessage
.Thanks to the following for their contributions:
Thanks to the following for their contributions:
GuildChannel::message_count
in a non-breaking way (@GnomedDev)Auto Moderation
feature (@nickelc)app_permissions
field on interactions (@nickelc)Invite::expires_at
field (@mkrasnitski)discriminator
" serde error for presence updates (@nickelc)rustversion
dependency and backports
module (@GnomedDev)MessageType::AutoModerationAction
enum variant (@nickelc)CustomisedHelpData
(@mkrasnitski)CacheHttp
for Arc<T>
if T
also implements it (@mkrasnitski)model::application
types (@kangalioo)Webhook
to enable direct creation (@mkrasnitski)interactions
& oauth2
model types into the application
module (@nickelc)model
feature is disabled (@FallenWarrior2k)Thanks to the following for their contributions:
Ord
and PartialOrd
for Timestamp
(@tedtramonte) c:b1c3a62
audit_log::Action
to represent unknown values (@nickelc) c:b2ae872
SUPPRESS_EMBEDS
flag for interaction response messages (@nickelc) c:888c37f
Guild
to PartialGuild
(@kangalioo) c:475fc1f
clippy::pedantic
lints (@GnomedDev) c:dc22cf2
simd-json
trait imports with json::prelude::*
(@nickelc) c:3e454cc
convert_ws_message
(@MelonShooter) c:8b2326c
Cow
in utils/content_safe.rs
to save on allocations (@mkrasnitski) c:79a3cc8
dashmap
5.2.0 for the MSRV build job (@nickelc) c:2898af2
simd-json
to 0.4.14 (@nickelc) c:0ba01a7
AttachmentType::data
in EditRole::icon
(@mkrasnitski) c:c3ad0b2
.git-blame-ignore-revs
(@nickelc) c:75df53e