- Fixes a crash when messages are received in voice channels
- Fixes missing direct message channels on message events
- Bumped the internal Discord API version to 8.
- Added support for gateway intents:
- Added
gatewayIntentenumeration - Added
gatewayIntentsclient option - Added
Client:getIntentsmethod - Added
Client:setIntentsmethod - Added
Client:enableIntentsmethod - Added
Client:disableIntentsmethod - Added
Client:enableAllIntentsmethod - Added
Client:disableAllIntentsmethod
- Added
- Added support for permission precision greater than 31 bits
- Deprecated
Client:setGame, useClient:setActivity - Added support for
embedsfield inTextChannel:send - Added
channelTypeenumerations:storenewsThreadpublicThreadprivateThreadstageVoicedirectoryforum
- Added
webhookTypeenumeration:application
- Added
messageTypeenumerations:channelFollowAddguildDiscoveryDisqualifiedguildDiscoveryRequalifiedguildDiscoveryInitialWarningguildDiscoveryFinalWarningthreadCreatedreplychatInputCommandthreadStarterMessageguildInviteRemindercontextMenuCommandautoModerationActionroleSubscriptionPurchase
- Added
activityTypeenumerations:watchingcompeting
- Added
statusenumeration:offline
- Added
permissionenumerations:viewGuildInsightsuseSlashCommandsrequestToSpeakmanageEventsmanageThreadsusePublicThreadsusePrivateThreads
- Added
messageFlagenumerations:hasThreadephemeralloading
- Added
actionTypeenumerations:stageInstanceCreatestageInstanceUpdatestageInstanceDeletestickerCreatestickerUpdatestickerDeleteeventCreateeventUpdateeventDeletethreadCreatethreadUpdatethreadDeleteautoModRuleCreateautoModRuleUpdateautoModRuleDeleteautoModMessageBlockautoModMessageFlagautoModUserTimeout
- Added support for member timeouts
- Added
Member:timeoutFor - Added
Member:timeoutUntil - Added
Member:removeTimeout - Added
Member.timedOut - Added
Member.timedOutUntil
- Added
- Fixes a bug in trying to sleep where
retry_afterisnilon 429. - Fixes mention consistency in for edited reply messages
- Fixes a crash when accessing
Message.mentionedUsersfor reply messages that have no mentions
- The mentioned author of a referenced message is now in
Message.mentionedUsers - Fixed a bug where mentions were ignored in replies
- Added basic support for message replies
- Added
content.referencefield forTextChannel:send(content) - Added
Message.referencedMessageproperty
- Added
- Added
Activity:__hashmethod - Added
INVITEandINTEGRATIONevents to the internal ignore list - Added ability to set member voice channel to
nil(voice-kick) - Changed reconnection request from
warningtoinfoin logging - Fixed rare crash on receiving invalid message reaction data
- Updated the
discordappdomain name todiscordwhere necessary (CDN links remain the same)
- Fixed an issue where the gateway session would not attempt to resume after a reconnection
- Fixed issue where objects would not be cached if they were re-created after being recently deleted
- Fixed issue where ratelimit headers were ignored
- Multiple presences are now flattened into one
- Fixed typo in
Guild.splashURLresult - Fixed issue where
Banobjects generated byGuild:getBandid not have the correct parent type - Fixed crash when FFmpeg process would close before reading
- Removed FFI dependency in Date class
- Added support for custom statuses:
- Added
Activity.emojiIdproperty - Added
Activity.emojiNameproperty - Added
Activity.emojiHashproperty - Added
Activityas a valid emoji and emojiId resolvable - Added
activityType.customenumeration
- Added
- Added support for message flags and embed suppression
- Added
Message:hasFlagmethod - Added
Message:hideEmbedsmethod - Added
Message:showEmbedsmethod - Added
messageFlagenumerations:crosspostedisCrosspostsuppressEmbedssourceMessageDeletedurgent
- Added
- Added
Message:updatemethod - Added
webhookTypeenumerations:incomingchannelFollower
- Added
Webhook.typeproperty - Added
permission.streamenumeration - Added
gatewayFileclient option - Switched to millisecond precision for HTTP ratelimiting
- Reduced default
routeDelayclient option from 300 to 250 ms - Bots can now add and remove reactions more quickly
- Reduced default
- Added
actionTypeenumerations:memberMovememberDisconnectbotAddmessageBulkDeletemessagePinmessageUnpinintegrationCreateintegrationUpdateintegrationDelete
- Fixed issue where
Reaction.emojiURLused.pngfor animated emojis - Fixed issue where
Guild.featuresdid not update - Fixed issue where deleted objects would be uncached prematurely
- Fixed issue where internal session ID was removed before it was used
- Refactored
docgen.luaand improved class documentation - Other changes
- Added error message for missing
ffmpegexecutable - Removed coroutine wrappers for internal iterators
- Switched to a dynamic multi-part file boundary
- Emojis are now properly URL-encoded
- Minor
Timeclass refactor
- Added error message for missing
- Added support for status differentiation
- Added
UserPresence.webStatusproperty - Added
UserPresence.mobileStatusproperty - Added
UserPresence.desktopStatusproperty
- Added
- Added support for premium guilds
- Added
Guild.premiumTierproperty - Added
Guild.premiumSubscriptionCountproperty - Added
Member.premiumSinceproperty - Added
messageType.premiumGuildSubscriptionenumeration - Added
messageType.premiumGuildSubscriptionTier1enumeration - Added
messageType.premiumGuildSubscriptionTier2enumeration - Added
messageType.premiumGuildSubscriptionTier3enumeration
- Added
- Added support for guild banners
- Added
Guild.bannerproperty - Added
Guild.bannerURLproperty - Added
Guild:setBannermethod
- Added
- Other additions
- Added
Guild.vanityCodeproperty - Added
Guild.descriptionproperty - Added
Guild.maxMembersproperty - Added
Guild.maxPresencesproperty - Added
Iterable:pickmethod - Added
Permissions.fromManystatic method - Added
Client:getApplicationInformationmethod - Added
Message.webhookIdproperty - Added
Snowflake:getDatemethod - Added
AuditLogEntry.userIdproperty - Added
GuildChannel.privateproperty
- Added
- Other changes and bug fixes
Emitter:removeAllListenersnow does exactly that if nonameis passed- Added support for Discord's new count boolean in
Guild:pruneMembers - Added an optional format parameter to
Date:toStringthat obeys the same rules asos.daterules. - Removed parsing of
_traceproperties in gateway payloads - Added basic support for guild news channels (Discordia treats them as text channels for now)
- Fixed a bug in emoji ID resolution
- Fixed
Member:hasPermissionreturning false for administrators in some conditions - Optimized libsodium char array construction
- Fixed emoji detection for
Message.cleanContent - Fixed issue converting
Dateto a snowflake on Windows - Various documentation fixes
- Dependency updates
- Updated
luvit/secure-socketfrom1.2.0to1.2.2 - Updated
creationix/coro-httpfrom3.0.0to3.1.0
- Updated
- Added
GuildTextChannel.rateLimitandGuildTextChannel:setRateLimitfor slowmode handling - Added parsing of members in the VOICE_STATE_UPDATE event and the mentioned users array for message handling
- Added
statusenumeration for presence or activity statuses - Reverted memoization changes from 2.5.0 (fixes an unidentified bug in role caching)
- Fixed an issue where
Message.reactionswas always empty
- Fixed nil index issue in Emoji and Member methods
- Added
message.linkproperty for jump-to links - Added
Guild.lazyproperty - Added
Guild:getBanfor checking individual bans Activitynow correctly inheritsContainer- Removed global reaction ratelimit
- Memoized iterables are now weakly cached for memory optimization
- Fixed a bug in
Emitter:waitForwhen using a predicate
- Added support for sending voice/audio
- Added
VoiceConnectionclass and other internal voice classes GuildVoiceChannel:joinis now functional- Added
GuildVoiceChannel:leave - See documentation for more information
- Added
- Added support for advanced presences/activities
- Added
Activityclass - Added
Member.activityandRelationship.activityviaUserPresence.activity - Deprecated
UserPresence.gameName, useUserPresence.activity.name - Deprecated
UserPresence.gameType, useUserPresence.activity.type - Deprecated
UserPresence.gameURL, useUserPresence.activity.url
- Added
- Other additions
- Added inline documentation and a documentation generator for classes
- Added
GuildCategoryChannel:createTextChannelandGuildCategoryChannel:createVoiceChannel - Added
Client:getRoleandClientgetEmoji - Added
PermissionOverwrite:setPermissions - Added
prioritySpeakerpermission - Added
Stopwatch:__tostring - Added
class.serializefunction - Added
shardDisconnectevent - Added optional predicate to
Emitter:waitFor - Added ability to get member counts with
Client:getInvite,Invite.approximatePresenceCount, andInvite.approximateMemberCount - Added donation link to README
- Bug fixes
- Fixed overflow issue with
extensions.table.deepcount - Fixed leading-zero issue in
Date:toISO - Fixed issue when comparing two
Dateobjects - Fixed issue in
Time:toString - Fixed issue that caused a crash on guild initialization
- Fixed
Client.shardCount - Fixed cache consistency issue with
PermissionOverwrites - Fixed issue in mention matching when an unpaired
<was encountered
- Fixed overflow issue with
- Other changes
- Made
Date:__tostringmore consistent with other metamethods and addedDate:toString - Overhauled WebSocket connection logic
- Deprecated
User.fullname, useUser.taginstead - Calling an HTTP API method outside of a coroutine will now throw (instead of return) its error
- Implemented internal gateway
message.memberparsing - All offline members are now uncached when
cacheAllMembersis false (instead of just those in large guilds)
- Made
- Emoji improvements:
- Added
Emoji:hasRole - Added
Emoji:setRoles Emoji.mentionStringwill now provide the animated version<a:name:id>for animated emojisEmoji.urlwill now provide a.gifURL for animated emojis- Added
Emoji.animatedboolean property
- Added
- Message mention improvements:
- Mentions are now iterated in the order that they appear in the message content
- Replicated mentions are still ignored as before
- Added
Message.mentionedEmojis(for custom emojis only) - Known cross-guild role and emoji mentions are now resolvable
- Role mentions will now resolve even if the role is technically not mentionable
- Emojis are now parsed in
Message.cleanContent - Added
ArrayIterable.firstandArrayIterable.lastproperties (eg:message.mentionedUsers.first)
Client:setGamenow supports arbitrary game/activity types- Added
gameType.listeningenumeration - Added
GuildVoiceChannel:join(only joins the channel, no voice connection is made) - Adjusted shard counting:
Client.shardCountwas corrected to represent the number of shards that the single client instance is runningClient.totalShardCountwas added to represent the total number of shards that the bot is running across all clients- The client option
shardCountwill remain unchanged; it still represents the total number of shards across all clients
- Added
GuildVoiceChannel.connectedMembersiterable property - Added
Time:toStringto obtain a natural-language time duration with proper grammatical number - Other changes
- Some internal
Emitterclass tweaks - Added
TableIterableclass (used internally) - HTTP User-Agent is now set during initialization instead of authentication
- Fixed nil concatenation in enum module
- Default class instance
__tostringnow provides only the class type - Fixed over-caching of members
- Some internal
- Added audit log support
- Added
Guild:getAuditLogs - Added
AuditLogEntryclass - Added
actionTypeenumeration
- Added
- Added
Guild:getEmoji - Added support for
Reaction:getUsersquery - Added
TextChannel:sendfshortcut - Objects deleted via HTTP are now synchronously uncached
- Fixed
Guild:listVoiceRegions - Ratelimit route tweaks
- ID paths are now properly substituted
- Webhooks are now treated as a major route
- Reactions are now treated as a global route
- Fixed issue when setting status on manually-sharded bots
- Fixed crash on guild initialization when voice states were not present
- Added
Reaction.emojiHashandEmoji.hashproperties - Added support for emoji endpoints and methods:
Emoji:setNameEmoji:deleteGuild:createEmoji
- Date instances are now valid Snowflake ID resolvables
- Added
textChannelsandvoiceChannelsfiltered iterables toGuildCategoryChannel - Added support for system channels
Guild.systemChannelGuild.systemChannelIdGuild:setSystemChannel
- Added missing
Message.oldContent, which was intended for 2.0.0 GuildTextChannel:bulkDeletecan now handle a minimum of 1 message instead of 2Iterable:toArray(fn)is now an acceptable overload forIterable:toArray(sortBy, fn)- Switched the base64 resolver to use OpenSSL instead of a pure Lua version
- Client owner data is now cached on authentication (still named gateway.json)
- Authentication cache now expires after 1 hour instead of 24 hours
- Reactions are now properly uncached when MESSAGE_REACTIONS_REMOVE_ALL occurs
- JSON
nullis now correctly handled forInvitesandReactions
The major goals of this rewrite were to add new or missing features and to improve consistency and efficiency. A lot of changes were made to Discordia to achieve these goals; many of them are breaking. Please read the following changelog carefully and update your applications accordingly.
Note: Due to changes made by Discord, versions of Discordia prior to 2.0.0 may not be supported on or after October 16, 2017.
- Bot tokens must now be manually prefixed with
Bot - The core of the library that establishes and maintains a connection to Discord has been overhauled (see Internal Changes for more information)
- More and clearer information regarding the client's connection is now logged
- Manual sharding is now supported
- Updated to Discord gateway v6
- Updated to Discord REST API v7
- Guilds are no longer automatically synced by default (user accounts only)
- Updated coro-http from 2.1.1 to 3.0.0
- Updated coro-websocket from 1.0.0 to 3.1.0
- Updated secure-socket from 1.1.4 to 1.2.0
- Removed coro-fs
- Class methods are no longer automatically generated for class properties (eg:
User:getUsernameis not a valid alternative forUser.username)- Properties are generally used for items that are immediately available for consumption
- Methods are generally used for items that require arguments or an HTTP or WebSocket request to be procured
- Some previously generated methods may still exist (eg:
TextChannel:getFirstMessageexists;TextChannel.firstMessagedoes not exist) - Some previous property-method pairs may still exist (eg:
Role.colorexists and is a number;Role:getColorexists and returns aColorobject) - Properties are never directly mutable; all mutations are done via methods
classmodule is no longer automatically registered as a global (access the newclassfield of thediscordiamodule instead)- Added various helper functions:
isClass,isObject,isSubclass,isInstance,type,profile - Calling
classnow returns only a class and getter table (instead of a class table and property, method, and cache constructors) - Changed the "private"
class.__classestable toclass.classes
- Properties and methods that access caches have been removed and replaced by caches that can be directly accessed
- Some shortcut methods remain (eg:
client:getGuildandchannel:getMessage) - Stand-alone iterators for cached objects have been changed to iterable objects (eg:
message.mentionedUsersis now anArrayIterable) - Stand-alone iterators for HTTP-accessible objects have been removed and replaced by methods that return an iterable object (eg:
channel.inviteswas replaced bychannel:getInvites) - Iterable objects are those that implement the
Iterablemixin; all have anitermethod plus methods that rely on this - The
Iterablemixin provides methods such asget,find,forEach, etc - Classes that implement the
Iterablemixin are:Cache- for main Discord objects (eg: guilds, channels, roles)SecondaryCache- for select references to objects that are cached elsewhere (eg: pinned messages)ArrayIterable- for objects that are better represented in an ordered form, and sometimes mapped (eg: member roles, mentioned users)WeakCache- for objects that are either never directly deleted or are temporarily referenced from other locations (eg: channel messages)
Ban- represents a guild ban (provides a user object and reason)GroupChannel- represents a group DM channel (user accounts only)Relationship- represents friends and blocked users (user accounts only)
Date- used to represent a single instance in timeTime- used to represent a specific length of timeLogger- used to log messages to the console and files
- New
Loggerclass added- Available log-levels are
error,warning,info,debug, andnone - Messages use a format
timestamp | level | message - Messages are logged to the console and to a file
- Available log-levels are
- The client uses a
Loggerinstance with a default level ofinfo, default file ofdiscordia.log, and default timestamp of%F %T - Shards use the main client logger, but prefix messages with
Shard: #where#is the shard ID. - Most methods that return false or nil to indicate a failure will now return an error message as their second return value
- This generally applies to methods that make HTTP requests
- When available, more detailed error messages will be provided than those that are sent to the client logger; always check these messages when debugging issues
- Added
Resolversingleton (used internally) - Methods that previously required certain objects now accept object hashes or objects that can be similarly hashed (eg:
member:addRolenow accepts either aRoleobject or snowflake ID) - Methods that previously required raw base64 now also accept a path to a file
- Added
enumsmodule to the maindiscordiamodule - Most types and levels are now enumerated as Lua numbers
- Enumerated properties can be more easily represented using fields within the
enumsmodule (eg:channelType.voiceandverificationLevel.medium)
- Module is no longer automatically loaded into the global Lua modules (call the modules to load them instead)
- Removed
printffunction - Combined
string.splitandstring.split2into onestring.split - Combined
string.padleft,string.padright, andstring.padcenterinto onestring.pad - Renamed
table.findtotable.search - Removed
table.hash - Removed
table.transposed
- Added
pinsUpdateevent - Added
webhooksUpdateevent - Added
reactionRemoveAllevent - Added
reactionRemoveAllUncachedevent - Added
recipientAddevent - Added
recipientRemoveevent - Added
relationshipAddevent - Added
relationshipRemoveevent - Added
relationshipUpdateevent - Added
infoevent - Added
debugevent - Added group channel and category handling to
channelCreate,channelUpdate, andchannelDelete - Renamed
resumedevent toshardResumed - Removed
guildCreateUnavailableevent (checkguild.unavailableonguildCreateinstead) - Removed
typingStartUncachedevent - Removed
muteanddeafarguments from voice events (checkmember.mutedandmember.deafenedinstead) - Changed
reactionAddandreactionRemoveparameters from(reaction, user)to(reaction, userId) - Changed
reactionAddUncachedandreactionRemoveUncachedparameters from raw(data)table to(channel, messageId, hash, userId) - Changed
typingStartparameters from(user, channel, timestamp)to raw(userId, channelId, timestamp)table - Changed
heartbeatparameters from(sequence, latency, shardId)to(shardId, latency) - Changed
rawparameters from(tbl, str)to(str)wherestris a JSON string
- Added
shardCountoption - Added
firstShardoption - Added
lastShardoption - Added
syncGuildsoption - Added
logLeveloption (useenums.logLevelfor convenience) - Added
logFileoption (use an empty string''to disable) - Removed
globalDelayoption - Removed
messageLimitoption - Changed
dateTimeoption from'%c'to'%F %T' - Non-integer options are now rejected (where relevant)
- Added
infoanddebugmethods and log-levels to complementwarninganderrormethods and log-levels - Registering a callback to log events no longer prevents messages from being logged
- Messages logged to the console are now also logged to a file
- Fixed issue where
gateway.jsondid not have user-specific fields - Added
setAFKmethod - Added
setGamemethod - Added
setStatusmethod - Added
getConnectionsmethod - Added
createGroupChannelmethod - Added
groupChannelsCacheproperty - Added
relationshipsCacheproperty - Changed
runto require aBotprefix for bot tokens - Changed
runto accept an initial presence as its second argument - Changed
runto not accept email and password for logins - Changed
stopmethod to never exit the process (do this manually instead) - Changed
setAvatarto accept a base64-resolvable - Removed
setNicknamemethod (useguild.me:setNicknameinstead) - Removed
setStatusOnlineandsetStatusIdlemethods (usesetStatusinstead) - Removed
setGameNamemethod (usesetGameinstead) - Removed
acceptInvitemethod - Replaced
usersproperties and methods with directly accessibleCacheproperty - Replaced
guildsproperties and methods with directly accessibleCacheproperty - Replaced
privateChannelsproperties and methods with directly accessibleCacheproperty - Removed
rolesproperties and methods - Removed
membersproperties and methods - Removed
channelsproperties and methods - Removed
messagesproperties and methods - Removed
textChannelsproperties and methods - Removed
voiceChannelsproperties and methods - Removed
guildVoiceChannelsproperties and methods - Removed
guildTextChannelsproperties and methods - Added stand-alone
getUsermethod, which accepts only a userId-resolvable - Added stand-alone
getGuildmethod, which accepts only a guildId-resolvable - Added stand-alone
getChannelmethod, which accepts only a channelId-resolvable - Removed
mobileproperty
- New class! See documentation.
- Moved
mentionStringproperty fromGuildChanneltoChannel - Removed
isPrivateproperty (checktypeinstead) - Changed
typeproperty from string to number (useenums.channelType)
- Added
__tostringmetamethod, which uses new__hashmethod(s) - Added
__eqmetamethod, which uses new__hashmethod(s)
- Added
categoryproperty - Added
setCategorymethod - Replaced
invitesproperty withgetInvitesmethod - Replaced
permissionOverwritesproperties and methods with directly accessibleCacheproperty - Replaced
setPositionmethod withmoveUpandmoveDownmethods - Changed
createInviteparameters from(maxAge, maxUses, temporary, unique)to(payload)
- Added
__hashmethod, which returnsidproperty - Removed
__eqmethod (parent method is used instead) - Removed
__tostringmethod (parent method is used instead) - Changed
timestampproperty to correctly match Python DateTime
- Removed
loadMessagesmethod - Replaced
lastMessageproperty withgetLastMessagemethod - Replaced
firstMessageproperty withgetFirstMessagemethod - Replaced
pinnedMessagesproperty withgetPinnedMessagesmethod - Replaced
messagesproperties and methods with directly accessibleCacheproperty - Renamed
getMessageHistorytogetMessagesand changed behavior (see documentation) - Renamed
sendMessagetosendand changed behavior (see documentation) - Added stand-alone
getMessagemethod, which accepts only a messageId-resolvable
- Changed
urlproperty to use cdn URL - Renamed
stringtomentionStringto be consistent with other "mentions" - Added
rolesArrayIterablefor roles that may be required to use the emoji - Removed explicit
__tostringmethod (parent method is used instead)
- New class! See documentation.
- Added
setVerificationLevelmethod - Added
setNotificationSettingmethod - Added
setExplicitContentSettingmethod - Added
explicitContentSettingproperty - Added
ownerIdproperty - Added
afkChannelIdproperty - Added
splashproperty - Added
splashURL - Added
setSplashmethod - Added optional
reasonargument tokickUser,banUser, andunbanUsermethods - Added
syncmethod - Added
requestMembersmethod - Added
categoriesCacheproperty - Added
createCategorymethod - Renamed
iconUrltoiconURL - Renamed
setAfkTimeouttosetAFKTimeout - Renamed
setAfkChanneltosetAFKChannel - Changed
setIconto accept a base64-resolvable - Changed
setAFKChannelto accept a channelId-resolvable - Replaced
vipboolean with rawfeaturestable - Fixed
pruneMembersmethod - Changed
kickUser,banUser, andunbanUsermethods to accept userId-resolvables - Changed
banUserparameters from(days)to(reason, days) - Removed
defaultChannelproperty - Replaced
bannedUsersproperty withgetBansmethod - Replaced
invitesproperty withgetInvitesmethod - Replaced
webhooksproperty withgetWebhooksmethod - Replaced
rolesproperties and methods with directly accessibleCacheproperty - Replaced
emojisproperties and methods with directly accessibleCacheproperty - Replaced
membersproperties and methods with directly accessibleCacheproperty - Replaced
textChannelsproperties and methods with directly accessibleCacheproperty - Replaced
voiceChannelsproperties and methods with directly accessibleCacheproperty - Removed
messagesproperties and methods - Removed
channelsproperties and methods - Added stand-alone
getRolemethod, which accepts only a roleId-resolvable - Added stand-alone
getChannelmethod, which accepts only a channelId-resolvable - Added stand-alone
getMembermethod, which accepts only a userId-resolvable
- New class! See documentation.
- Changed
bulkDeletebehavior (see documentation) - Moved
mentionStringfromGuildChanneltoChannel - Replaced
webhooksproperty withgetWebhooksmethod - Added
enableNSFWanddisableNSFWmethods - Added
nsfwproperty
- Removed
joinandleavemethods until voice is re-written - Removed
connectionproperty until voice is re-written - Removed
membersproperties and methods until voice is re-written
- Added
__hashmethod, which returnscodeproperty - Added
guildSplashproperty - Added
guildIconproperty - Added
guildSplashURLproperty - Added
guildIconURLproperty - Changed
channelTypefrom string to number (useenums.channelType) - Removed
acceptmethod
- Changed base class from
SnowflaketoUserPresence - Added
__hashmethod, which returnsuser.idproperty - Replaced
rolesproperties and methods with directly accessibleArrayIterableproperty - Replaced
setMutemethod withmuteandunmutemethods - Replaced
setDeafmethod withdeafenandundeafenmethods - Renamed
muteproperty tomuted - Renamed
deafproperty todeafened - Changed
colorproperty fromColorobject to number - Added
getColormethod to accessColorobject - Removed
addRoles,removeRoles, andhasRolesmethods - Changed
addRole,removeRole, andhasRolemethods to accept a roleId-resolvable - Added optional
reasonargument tokick,ban, andunbanmethods - Changed
kick,ban, andunbanmethods to always use the member's current guild (useguild:kickUser(member), etcif a different guild is required) - Changed
banparameters from(days)to(reason, days) - Renamed
sendMessagemethod tosend(seeTextChannel:send) - Removed
Member:getMembership(guild)(useGuild:getMember(member)instead) - Added
gameTypeproperty (useenums.gameType) - Added
gameURLproperty - Changed
hasRolemethod to returntruefor@everyonerole - Added
getPermissionsmethod - Added
hasPermissionmethod - Added
membersFilteredIterableproperty
- Replaced
reactionsproperties and methods with directly accessibleCacheproperty - Replaced
mentionedUsersproperties and methods with directly accessibleArrayIterableproperty - Replaced
mentionedRolesproperties and methods with directly accessibleArrayIterableproperty - Replaced
mentionedChannelsproperties and methods with directly accessibleArrayIterableproperty - Changed
oldContentproperty from a string to a table of strings - Removed
editedTimestampproperty (useoldContentkeys instead) - Moved
Message:getReactionUsers(emoji)toReaction:getUsers() - Added
typeproperty - Added
mentionsEveryoneproperty - Changed
@everyoneand@herementions (incleanContent) to use a zero-width space instead of a null character
- Removed
nameproperty (directly check name of object instead) - Replaced
objectproperty withgetObjectmethod - Changed
allowedPermissionsproperty fromPermissionsobject to number - Changed
deniedPermissionsproperty fromPermissionsobject to number - Added
getAllowedPermissionsmethod to accessPermissionsobject - Added
getDeniedPermissionsmethod to accessPermissionsobject
- Changed
deletemethod toleave
- Added
__hashmethod, which returns the emoji ID for custom emojis or emoji name for standard emojis - Added
delete([user])method - Moved
Message:getReactionUsers(emoji)toReaction:getUsers() - Removed
emojiproperty - Added
emojiIdproperty - Added
emojiNameproperty - Added
emojiURLproperty
- New class! See documentation.
- Changed
colorproperty fromColorobject to number - Changed
permissionsproperty fromPermissionsobject to number - Added
getColormethod to accessColorobject - Added
getPermissionsmethod to accessPermissionsobject - Changed
setColorto accept a color-resolvable - Changed
setPermissionsto accept a permissions-resolvable - Replaced
setHoistmethod withhoistandunhoist - Replaced
setMentionablemethod withenableMentioninganddisableMentioning - Changed
hoistproperty tohoisted - Replaced
setPositionmethod withmoveUpandmoveDownmethods - Added
membersFilteredIterableproperty
- Removed
User:getMembership(guild)(useGuild:getMember(user)instead) - Replaced
privateChannelproperty withgetPrivateChannelmethod - Renamed
sendMessagemethod tosend(seeTextChannel:send) - Renamed
avatarUrltoavatarURL - Renamed
defaultAvatarUrltodefaultAvatarURL - Renamed
getAvatarUrltogetAvatarURL - Renamed
getDefaultAvatarUrltogetDefaultAvatarURL - Changed
defaultAvatarhashes to numbers (useenums.defaultAvatar) - Changed
setAvatarto accept a base64-resolvable - Changed
mutualGuildsiterator function to aFilteredIterableinstace - Added
fullnameproperty - Removed avatar default size of 1024 (pass an explicit size to
get[Default]AvatarURLif a size is required) - Removed
kick,ban, andunbanmethods (usedGuildmethods instead)
- New class! See documentation.
- Changed
setAvatarto accept a base64-resolvable - Renamed
avatarUrltoavatarURL - Renamed
getAvatarUrltogetAvatarURL - Added
getDefaultAvatarURL - Added
defaultAvatarURL
- New class! See documentation.
- New class! See documentation.
- New class! See documentation.
- New class! See documentation.
- New class! See documentation.
- New class! See documentation.
- Removed class until voice is re-written
- No public changes
- Changed constructor to accept only a number (use static methods for more options)
- Changed
__tostringto display hex value and RGB - Added
fromHex,fromRGB,fromHSV, andfromHSLstatic methods - Added
toHex,toRGB,toHSV, andtoHSLmember methods
- New class! See documentation.
- No public changes
- Added
onSyncandonceSyncmethod s for omitting automatic coroutine-wrapping of listener callbacks - Changed
removeListenerto remove all listeners that match the provided function instead of just the first match - Added awaitable
waitFormethod with optional timeout - Removed
propagatemethod
- New class! See documentation.
- No public changes
- Changed
enable,disable, andhasmethods to accept a string ("sendMessages") or a number (0x800orenums.permission.sendMessages)
- Added
stoppedparameter to constructor to optionally initialize a stopped stopwatch - Renamed
pausemethod tostop - Renamed
resumemethod tostart - Renamed
restartmethod toreset - Removed
hours,minutes,seconds,microseconds, andnanosecondsproperties - Added
getTimemethod
- New class! See documentation.
- Added partial handling of failed socket connections
- Added special handling for reaction ratelimits
- Implemented webhook features
- Added
Webhookclass - Added
Guild.webhooksandGuildTextChannel.webhooksiterators (both use an HTTP request) - Added
GuildTextChannel:createWebhookmethod
- Added
- Text channel and message improvements
bulkDeleteandgetMessageHistoryimprovements- Added optional predicates to filter specific messages
After|Before|Aroundmethods now optionally accept a Snowflake ID instead of aMessageobject
- Added
firstMessageandlastMessageproperties toTextChannel(both use an HTTP request) - Added support for raw data file attachments
- Added support for multiple file attachments per message
- Added
User.privatechannelproperty (uses an HTTP request) Guild:createRolenow accepts an initialnameargument- Replaced
TYPING_STARTwarnings withtypingStartUncachedevent - Disabled member object creation on
PRESENCE_UPDATE- Fixes lingering member objects after guild leave
- Fixes missing
joinedAtproperty - May provide a performance improvement
- To compensate for missing members, enable
fetchMemberson client initialization
- Other changes
- Fixed voice sequence and timestamp incrementing
- Fixed
Emitterlistener addition/removal - Fixed crash on guild creation due to rogue member presences
- Changed
os.exitinclient:stoptoprocess:exit - Changed
printcall in console logging function toprocess.stdout:write
- Fixed bug in Guild:setOwner
- Fixed nickname not being cleared from member objects
- Minor optimization in
printf
- Added token check to socket reconnection
- Fixed bug when setting client nickname via Member
- Added default JSON table for non-JSON HTTP responses
- Added checks for invalid client options
- Restored fixed creationix/coro dependency versions
- Extensions added:
string.randomfor generating random stringstring.split2for splitting strings by pattern [@FiniteReality]
- Implemented automatic gateway sharding
- Multiple shards are automatically spawned on startup according to the Discord-recommended amount
- Added a
shardReadyevent that fires as each shard finishes loading with a shard ID as its argument - Shard ID is also now an argument for the
resumedandheartbeatevents Client.shardCountandGuild.shardIdare accessible properties
- Overhauled token parsing and login handling:
- Tokens can now optionally be prefixed with
Bot - Tokens are validated before establishing a gateway connection; invalid tokens are rejected with an error
- Attempts to connect or reconnect to the gateway are no longer pcall'd
- To simplify
READYhandling, failed loading of guild chunk or sync payloads will result inreadynever firing instead of timing out - Added support for compressed gateway payloads (enabled by default)
- Replaced
gateway.cachewithgateway.json
- Tokens can now optionally be prefixed with
- Member conveniences:
- Added
User.mutualGuildsiterator - Added
Member.colorproperty - Added
Member:hasRoleandMember:hasRolesmethods - Added
Member:addRoleandMember:removeRolemethods - Added member cache accessors to
GuildVoiceChannelclass - Improved
User:getMembershipby reducing unnecessary HTTP requests
- Added
- Other changes:
- Optimized classes to be more memory efficient
- Minor optimizations in
TextChannel:sendMessage - Minor HTTP request optimizations
- Removed member check from
PRESENCE_UPDATEhandler - Fixed functions not explicitly returning
nilin some cases - Added default audio library names which can allow for automatic loading of libopus.so and libsodium.so on POSIX systems or opus.dll and sodium.dll on Windows. (Call
loadOpusorloadSodiumwithout arguments to use the defaults) - Fixed a missing parameter in the sodium decrypt function (not currently used by Discordia)
- Event handler optimizations
- If an uncached guild, channel, member, or role is encountered on their respective
UPDATEorDELETEevents, an object is now created and cached from the event payload instead of throwing a warning. - Events that parse a text channel ID are now more performant; the channel is found by using an channel map instead of by iterating over guilds.
- If an uncached guild, channel, member, or role is encountered on their respective
- Token parsing on login was improved
- Tokens are no longer prepended with
BotonREADY. Tokens are tested against a REST endpoint (/users/@me), and are prepended withBotonly if necessary. - If an invalid token is provided, the library will throw an error instead of entering a connect/disconnect loop.
- Tokens are no longer prepended with
- Opus encoder fix
- The encode method now expects an explicitly defined PCM length instead of one implicitly defined from the input table.
- This should fix a segmentation fault issue which apparently was a result of passing a size that is too small.
- Fixed an oversight where the positional return value of
string.unpackwas passed to the opus encoder for FFmpeg streams.
- Message enhancements
- Deprecated
TextChannel:sendMessage(content, mentions, tts)format TextChannel:sendMessage(content)is now the suggested format, wherecontentis a string or table. Table properties are:content: raw content string
mentions: mentionable object or table of mentionable objectstts: boolean indicating whether the message is TTSnonce: unique message identifierfile: relative or absolute path to file for attachmentfilename: custom name to use for attachment (not required)embed: table of message embed data- File attachments made possible by multipart/form-data implementation [@PurgePJ]
- Added
nonceandoldContentproperties toMessageclass - Added
attachments,embeds,attachment, andembedproperties toMessageclass. All are exposed as raw Lua tables with original Discord formatting. - Added
reactionAddUncachedandreactionRemoveUncachedevents for when reactions are added/removed to messages that are uncached. A raw data table is passed as the only argument.
- Deprecated
- Added support for larger avatars and animated Nitro avatars
User:getAvatar(size)can be used for custom sizesgiffiles are automatically returned if the avatar is animatedpngis still used for static avatars
- Other changes:
- Removed unnecessary fields from
PATCH /users/@merequest - Added
isPlaying,isPaused, andplayTimeproperties toVoiceConnectionclass
- Removed unnecessary fields from
- Added package metadata to main
discordiamodule - Reduced timeout on voice channel join from 10 to 5 seconds
- Fixed an overflow when writing the maximum least-significant byte to a buffer
- Fixed an issue that caused a crash after failing to join a voice channel
- Added a Clock utility class (not used by the library)
- Voice optimizations
- Fixed issue where PermissionOverwrite tostring value was not properly formatted
- Voice tweaks
- Moved encryption mode to constants module
- pcall'd FFmpeg handle closings to avoid rare nil error
- Some minor optimizations
- Implemented voice-send features
- Streaming of PCM data from strings, tables, generators, or an FFmpeg process is now possible
- Implemented
VoiceManager,VoiceConnection,VoiceSocket,AudioStream, andFFmpegPipeclasses - Implemented a re-written version of Luvit's
Bufferclass - Implemented
libopusandlibsodiumbindings via LuaJIT FFI VOICE_SERVER_UPDATEis now handledMember.voiceChannelis now an accessible and mutable propertyGuild.connectionandGuildVoiceChannel.connectionis now an accessible property- Added
GuildVoiceChanneljoinandleavemethods - Added
creationix/coro-spawndependency - Other
- Added optional patterns to string pad extensions
- Added
pauseandresumemethods forStopwatch - Outgoing gateway payloads are now coroutine-wrapped
- Fixed gateway reconnection bug
- Implemented emoji features
- Added Emoji and Reaction classes
- Added message reaction methods
addReaction,removeReaction,clearReactions,getReactionUsers,getReactions
- Added handling of message reaction and emoji events
reactionAdd,reactionRemove,emojisUpdate
- Emoji are formally cached per guild
- Reactions are stored per message, but are not formally cached
- Fixed issue where PermissionOverwrites for members were not named
- Added more standard library extensions:
table.slice,string.startswith,string.endswith,string.levenshtein
-
General
- All mentions of server or Server were changed to guild or Guild to maintain consistency with internal Discord nomenclature
- Methods that use the REST API and that previously returned nothing now return a boolean to indicate whether the call was successful
- Discord-compliant ratelimiting has been implemented
- User handling has been changed slightly:
Userobjects are now cached once perClientinstead of per everyPrivateChannelandGuild- The
Memberclass now wraps theUserclass instead of extending it - To get a user's
Memberobject, useUser:getMembership(guild) - A member's
Userobject is accessed viaMember.user - Message authors, channel recipients, and invite inviters are always
Userobjects - Guild owners and members are always
Memberobjects
utilswas removed from the maindiscordiamodule and has been replaced by individual utility classesWarningandErrorclasses were removed in favor of events- Gateway disconnects, nil values on events, and HTTP errors are now handled more gracefully
- All modules relevant to the
Clientclass were refactored and moved with it into aclientfolder:Clientnow extends a custom version of Luvit's built-inEmitter- Client instances are initialized using
discordia.Client()instead ofdiscordia.Client:new() - A table of options can be passed to the client initializer. Currently supported options are:
routeDelay: minimum time to wait between requests per-route (default: 300 ms)globalDelay: minimum time to wait between requests globally after a global 429 (default: 10 ms)messageLimit: limit to the number of cached messages per channel (default: 100)largeThreshold: limit to how many members are initially fetched per-guild on start-up (default: 100)fetchMembers: whether to fetch all members for all guilds (default: false)autoReconnect: whether to attempt to reconnect after an unexpected gateway disconnection (default: true)
- Client instances are initialized using
endpointswas changed toAPIeventswas changed toEventHandlerWebSocketwas changed toSocket
- Discord objects are now stored in custom
Cacheobjects instead of pure Lua tables - Many iterators were added to help with accessing cached objects or methods that used to return a table
- The entire class system was overhauled
- Internally used properties and methods are now prefixed with an underscore to indicate their protected status
- Getter and setter properties and methods have been added.
- For every public property that can be accessed/mutated, there is an associated get/set method
-- these lines examples are equivalent local name = guild.name local name = guild:getName()
-- these lines examples are equivalent guild.name = "foo" guild:setName("foo")
- Objects that have caches have a variety of get and find methods for accessing those caches. For example:
guild:getRoles()orguild.roles- returns an iterator for all roles in the guildguild:getRoleCount()orguild.roleCount- returns the number of roles cachedguild:getRole(id)- returns the role with the given Snowflake IDguild:getRole(key, value)- returns the first found role matching a key, value pairguild:getRoles(key, value)- returns an iterator for all roles matching the key, value pairguild:findRole(predicate)- returns the first found role that makes the predicate trueguild:findRoles(predicate)- returns an iterator for all roles that makes the predicate true
-- pre-1.0 code for _, role in pairs(guild.roles) do print(role) end
-- 1.0 code for role in guild.roles do print(role) end for role in guild:getRoles() do print(role) end
-
Events
- Event handling was made more reliable by using the new
Cacheobjects - Attempts to access uncached objects are now caught, and warnings are printed to the console
- Guild sync was implemented for non-bot accounts
serverCreatewas renamed/split intoguildCreate,guildAvailable, andguildCreateUnavailableserverDeletewas renamed/split intoguildDeleteandguildUnavailablemessageAcknowledgeandmembersChunkwere removedmemberBanandmemberUnbanwere renamed touserBananduserUnbanand now provide aUserobject instead of aMemberobjectvoiceJoinandVoiceLeavewere renamed/split intoVoiceChannel[Join|Leave]andvoice[Connected|Disconnect]typingStartnow has a timestamp as a third argumentmessageUpdateUncachedandmessageDeleteUncachedevents were added for uncached message eventswarninganderrorevents were addedheartbeatevent was added with event sequence and roundtrip latency arguments
- Event handling was made more reliable by using the new
-
New Classes
API- Adds a layer of abstraction between Discord's REST API and Discordia's object oriented APIContainer- Base object used to store Discord objectsCache- Data structure used to store and accessContainerobjectsEmitter- A simplified re-write of Luvit's built-in event emitterMutex- Extension ofDequethat is used by theAPIclass to throttle HTTP requestsOrderedCache- Extension ofCachethat maintains the order of objects as a doubly-linked listStopwatch- Used to measure elapsed time with nanosecond precisionPermissionOverwrite- Extension ofSnowflakethat maintains per-channel permissions
-
For other API changes, please consult the Discordia wiki.
- Fixed issue where presences were applied to offline members on guild creation
- Fixed issue where roles where not properly being applied by Member:setRoles method
- Fixed issue where mentioned object would be nil
- Fixed issue with UTC time parsing
- Updated secure-socket dependency to version 0.1.4
- Member:setRoles now accepts a table of roles instead of IDs
- Tweaked internal Member updating
- Mentions are now ignored in private/direct messages
- Fixed issue where private message author was always the channel recipient
- Fixed erroneous private message parenting for User:sendMessage
- Partial restoration of class overhaul for critical fix
- Reverted class overhaul due to complicated bugs
- Added API client class (not yet exposed)
- Updated class constructor
- Reduced memory footprint by 30 to 40%
- Added isInstanceOf utility function
- Equality operator now correctly considers type
- Fixes an issue where Server == defaultChannel or defaultRole was true
- Fixed regression due to Message.channelId removal
- Added User object fallback for member[Ban/Unban]
- Added local datetime to Error/Warning output
- Fixed critical issue where client would not recognize a resumed connection
- Added "0x" to Color:toHex() output
- Added Permissions:toHex() method
- Fixed issue where server owner was nil
- Server.joinedAt is now a Unix timestamp
- utils.dateToTime and resulting timestamps now support milliseconds
- Fixed critical issue with lit package metadata
- Added Member:kick() overload method
- table.reverse now reverses a table in place
- Reorganized directories
- Implemented basic Permissions handling
- Added abstract Channel superclass for TextChannel and ServerChannel
- Expanded Role features
- Member.roles is now parsed into a table of Role objects
- User.name is now the User's display name: Either User.username by default, or User.nickname if one exists
- Other Chanegs
- Added custom delimiter to string.split
- Overhauled WebSocket reconnection process
- Changed mentions iterator from ipairs to pairs
- Default argument for TextChannel:getMessageHistory changed from 50 to 1
- Removed redundant channelId from Message class
- Bug Fixes
- Fixed issue when trying to access nil invites or bans tables
- Fixed issue where handleWebSocketDisconnect was improperly called
- Minor refactoring of token caching
- Overhauled WebSocket keep alive process
- Fixed issue where Server.defaultRole was nil
- Fixed UTC issue with dateToTime utility
- Added utility for converting UTC datetime string to Unix timestamp
- Message timestamps and Message joinedAt is now a Unix timestamp
- messageUpdate is no longer fired for non-existing messages
- Fixed @everyone mention crash
- Critical: Removed code that accesses Server.memberCount
- TextChannel improvements
- Added adjustable limit to getMessageHistory()
- Reimplemented broadcastTyping() from an old version
- Implemented bulkDelete()
- Removed memberCount from Server class
- Added utility for converting snowflake ID to creation time and date
- Added string.totable
- Color class changes:
- RGB values are now rounded
- Added add, sub, mul, and div operators
- Added error codes to HTTP warnings and errors
- Client:setNickname now uses proper endpoint
- Fixed issue where nickname would not update
- Fixed issue where deleting private channels crashed library
- Added table.randompair and table.randomipair
- Added standard library extensions (printf, string, table, and math)
- Implemented nickname support
- Added Client:setNickname and Member:setNickname methods
- Added Member.nickname attribute
- getMemberByName now also searches nickname (may change in the future)
- Implemented role color support
- Added Color class with RGB, hex, and dec support
- Role.color and Role:setColor() now utilize Color class
- Implemented mentions support
- Parsed message mentions into objects within Message.mentions table
- Added Message:mentions[Member|Role|Channel] methods
- Added getMentionString methods for User, Role, and ServerTextChannel
- Added object array to sendMessage/createMessage method
- Other changes
- Moved classes out of /classes/utils folder into /classes
- VoiceState and Invite no longer inherit from Base, since they do not have Snowflake IDs
- Bug fixes
- Fixed issue where role would not properly update
- Fixed issue where member status was nil
- Fixed issue where server owner was nil
- Fixed issue where Member.gameName would be nil
- Removed logout POST until otherwise required
- Added timeout for WebSocket reconnections
- Improved rate limit handling
- ServerChannel:createInvite() now returns an Invite object
- Privatized update methods with leading underscore
- getMessageHistory now returns a table of objects
- Added User.bot parameter (boolean)
- Fixed issue where voiceLeave event would not fire
- Reworked logout and termination handling:
- Client:logout() now also clears the stored token
- Added Client:stop() method
- Added Client:disconnectWebsocket() and WebSocket:disconnect() helpers
- Renamed startWebsocketReceiver to startWebsocketHandler
- Added condition for an expected WS disconnection, which should be only after logout() is called.
- Added 'expected' argument to disconnect event.
- Added User.name alias for User.username
- Added HTTP 502 handling
- Caught exceptions no longer terminate the program
- Added convenient Server attributes defaultRole, defaultChannel, and me
- Added disconnect event
- Fixed missing presenceUpdate arguments
- Increased max messages to 500 per channel
- Fixed issue where offline member status was nil
- Fixed issue where nil gateways or tokens could potentially be cached as empty files
- Fixed issue where ready was not properly delayed
- Reworked login process
- loginWithEmail accepts email and password for regular accounts only
- loginWithToken accepts a token for any account
- Client:run() calls the appropriate login method
- Bot is prepended to the token according to the READY data
- Added User:sendMessage() method
- Implemented support for bot accounts
- Client:run() now accepts email and password or token
- Renamed Client:login(email, pass) to Client:userLogin(email, pass)
- Added Client:botLogin(token)
- Initially unavailable servers are now accounted for
- Implemented channel editing
- Added general edit method for ServerChannel
- Added setName method for ServerChannel
- Added setTopic method for ServerTextChannel
- Added setBitrate method for ServerVoiceChannel
- Critical: Fixed package path issue
- Overhauled class system
- Implemented exception handling
- New Error and Warning classes
- HTTP 400 is raised
- HTTP 403 is warned
- HTTP 429 is handled and warned
- Unhandled HTTP errors are raised
- Unhandled WebSocket events are warned
- Unhandled WebSocket payloads are warned
- Implemented Invite handling
- Added statusUpdate WebSocket method and corresponding client methods setStatusIdle, setStatusOnline, and setGameGame
- Implemented WebSocket reconnecting
- First 'stable' release to coincide with official API documentation release
- Code overhauled for optimizations and bug fixes
- Event callbacks no longer block the main loop
- Added Member class, which extends a now simplified User class
- Implemented gateway caching
- Added 'raw' event
- Added setOwner, setAfkTimeout, setAfkChannel Server methods
- Established project name: Discordia
- Added reply example script
- Changed luvit/secure-socket version to 1.1.2
- Request data is now camelified
- Moved websocket handlers to their own Client methods
- Added op# shortcut WebSocket methods
- Role events no longer emit Server object, use role.server instead
- General Git version control employed instead of GitHub direct editing
- Implemented custom class module with multiple inheritance
- Added base Base class for Discord classes
- Added peek methods to Deque class
- Converted lone Channel class to multiple classes:
- ServerChannel and TextChannel inherit from Base
- PrivateChannel inherits from TextChannel
- ServerTextChannel inherits from TextChannel and ServerChannel
- ServerVoiceChannel inherit from ServerChannel
- Fixed token caching, which now uses an MD5 hash
- Implemented token caching
- Conformed user agent to API standard
- Message deques and maximum scrollback implemented
- Added member chunking
- 'discord' now includes utils (in addition to Client)
- Added string split and number clamp helpers to utils
- Added event handling for guildRoleCreate, guildRoleDelete, and guildRoleUpdate
- Added channel position and general role mutators
- Message updates now account for 'embeds only'
- Added getServers and getMessages User methods
- Added event handling for guildCreate, guildDelete, guildUpdate
- Added event handling for guildBanAdd and guildBanRemove
- Added event handling for guildMemberAdd, guildMemberRemove, and guildMemberUpdate
- Added getAvatarUrl method for user class
- Pasted MIT license info into package.lua
- Created PrivateChannel class
- Moved several methods from Client class to respective Discord classes
- Added event handling for typingStart, messageDelete, messageUpdate, and MessageAck
- Added event handling for channelUpdate, channelDelete, and channelCreate
- Added methods to update class instances
- Switched from multiple User classes to one main class for all types
- Added event handling for messageCreate and voiceStateUpdate
- get[Role|Channel|Server]By[Name|Id] now use cached data
- Expanded Message class
- Finished the majority of REST methods
- Started the majority of expected class definitions
- Added websocket support
- Added event handling for the ready event