From a3aa3ef10df48be0642328794feeeb45b26ea83e Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sun, 8 Jan 2023 16:36:22 -0500 Subject: [PATCH 01/22] Fixes language server warnings --- examples/helpCommandExample.lua | 2 +- libs/client/API.lua | 12 ++++++------ libs/client/Client.lua | 6 +++--- libs/client/EventHandler.lua | 2 +- libs/client/Resolver.lua | 6 +++--- libs/client/Shard.lua | 7 ++++++- libs/containers/AuditLogEntry.lua | 2 +- libs/containers/Guild.lua | 2 +- libs/containers/GuildCategoryChannel.lua | 2 +- libs/containers/Member.lua | 2 +- libs/containers/Message.lua | 2 +- libs/containers/Webhook.lua | 2 +- libs/containers/abstract/Channel.lua | 2 +- libs/containers/abstract/GuildChannel.lua | 2 +- libs/iterables/Cache.lua | 2 +- libs/iterables/Iterable.lua | 3 ++- libs/iterables/SecondaryCache.lua | 2 +- libs/utils/Clock.lua | 2 +- libs/utils/Date.lua | 2 +- libs/utils/Logger.lua | 6 +++--- libs/utils/Mutex.lua | 2 +- libs/utils/Permissions.lua | 2 +- libs/voice/VoiceConnection.lua | 4 ++-- libs/voice/VoiceManager.lua | 4 ++-- libs/voice/VoiceSocket.lua | 2 +- 25 files changed, 44 insertions(+), 38 deletions(-) diff --git a/examples/helpCommandExample.lua b/examples/helpCommandExample.lua index e22a3e6d..308eee92 100644 --- a/examples/helpCommandExample.lua +++ b/examples/helpCommandExample.lua @@ -19,7 +19,7 @@ local commands = { } client:on('ready', function() - p(string.format('Logged in as %s', client.user.username)) + print(string.format('Logged in as %s', client.user.username)) end) client:on("messageCreate", function(message) diff --git a/libs/client/API.lua b/libs/client/API.lua index 10e099b8..4a1ea6b3 100644 --- a/libs/client/API.lua +++ b/libs/client/API.lua @@ -132,14 +132,14 @@ function API:request(method, endpoint, payload, query, files) local url = BASE_URL .. endpoint if query and next(query) then - url = {url} + local buf = {url} for k, v in pairs(query) do - insert(url, #url == 1 and '?' or '&') - insert(url, urlencode(k)) - insert(url, '=') - insert(url, urlencode(v)) + insert(buf, #buf == 1 and '?' or '&') + insert(buf, urlencode(k)) + insert(buf, '=') + insert(buf, urlencode(v)) end - url = concat(url) + url = concat(buf) end local req = { diff --git a/libs/client/Client.lua b/libs/client/Client.lua index 1bb70e6c..4b59c462 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -40,8 +40,8 @@ local VoiceManager = require('voice/VoiceManager') local encode, decode, null = json.encode, json.decode, json.null local readFileSync, writeFileSync = fs.readFileSync, fs.writeFileSync -local logLevel = enums.logLevel -local gameType = enums.gameType +local logLevel = assert(enums.logLevel) +local gameType = assert(enums.gameType) local wrap = coroutine.wrap local time, difftime = os.time, os.difftime @@ -101,7 +101,7 @@ local Client, get = require('class')('Client', Emitter) function Client:__init(options) Emitter.__init(self) - options = parseOptions(options) + options = assert(parseOptions(options)) self._options = options self._shards = {} self._api = API(self) diff --git a/libs/client/EventHandler.lua b/libs/client/EventHandler.lua index 84577134..72ec09aa 100644 --- a/libs/client/EventHandler.lua +++ b/libs/client/EventHandler.lua @@ -1,7 +1,7 @@ local enums = require('enums') local json = require('json') -local channelType = enums.channelType +local channelType = assert(enums.channelType) local insert = table.insert local null = json.null diff --git a/libs/client/Resolver.lua b/libs/client/Resolver.lua index 0ee26481..f1186920 100644 --- a/libs/client/Resolver.lua +++ b/libs/client/Resolver.lua @@ -4,9 +4,9 @@ local ssl = require('openssl') local class = require('class') local enums = require('enums') -local permission = enums.permission -local actionType = enums.actionType -local messageFlag = enums.messageFlag +local permission = assert(enums.permission) +local actionType = assert(enums.actionType) +local messageFlag = assert(enums.messageFlag) local base64 = ssl.base64 local readFileSync = fs.readFileSync local classes = class.classes diff --git a/libs/client/Shard.lua b/libs/client/Shard.lua index 9c826731..31d5e250 100644 --- a/libs/client/Shard.lua +++ b/libs/client/Shard.lua @@ -7,7 +7,7 @@ local WebSocket = require('client/WebSocket') local constants = require('constants') local enums = require('enums') -local logLevel = enums.logLevel +local logLevel = assert(enums.logLevel) local min, max, random = math.min, math.max, math.random local null = json.null local format = string.format @@ -45,6 +45,11 @@ local ignore = { ['INTEGRATION_CREATE'] = true, ['INTEGRATION_UPDATE'] = true, ['INTEGRATION_DELETE'] = true, + ['EMBEDDED_ACTIVITY_UPDATE'] = true, + ['GIFT_CODE_UPDATE'] = true, + ['GUILD_JOIN_REQUEST_UPDATE'] = true, + ['GUILD_JOIN_REQUEST_DELETE'] = true, + ['APPLICATION_COMMAND_PERMISSIONS_UPDATE'] = true, } local Shard = require('class')('Shard', WebSocket) diff --git a/libs/containers/AuditLogEntry.lua b/libs/containers/AuditLogEntry.lua index c82fe90a..0e28ff16 100644 --- a/libs/containers/AuditLogEntry.lua +++ b/libs/containers/AuditLogEntry.lua @@ -6,7 +6,7 @@ local Snowflake = require('containers/abstract/Snowflake') local enums = require('enums') -local actionType = enums.actionType +local actionType = assert(enums.actionType) local AuditLogEntry, get = require('class')('AuditLogEntry', Snowflake) diff --git a/libs/containers/Guild.lua b/libs/containers/Guild.lua index 10d9d524..f3d68c8e 100644 --- a/libs/containers/Guild.lua +++ b/libs/containers/Guild.lua @@ -21,7 +21,7 @@ local Snowflake = require('containers/abstract/Snowflake') local json = require('json') local enums = require('enums') -local channelType = enums.channelType +local channelType = assert(enums.channelType) local floor = math.floor local format = string.format diff --git a/libs/containers/GuildCategoryChannel.lua b/libs/containers/GuildCategoryChannel.lua index 8dedd106..fede1ce2 100644 --- a/libs/containers/GuildCategoryChannel.lua +++ b/libs/containers/GuildCategoryChannel.lua @@ -8,7 +8,7 @@ local GuildChannel = require('containers/abstract/GuildChannel') local FilteredIterable = require('iterables/FilteredIterable') local enums = require('enums') -local channelType = enums.channelType +local channelType = assert(enums.channelType) local GuildCategoryChannel, get = require('class')('GuildCategoryChannel', GuildChannel) diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index fdda8737..996d9551 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -21,7 +21,7 @@ local Time = require('utils/Time') local insert, remove, sort = table.insert, table.remove, table.sort local band, bor, bnot = bit.band, bit.bor, bit.bnot local isInstance = class.isInstance -local permission = enums.permission +local permission = assert(enums.permission) local Member, get = class('Member', UserPresence) diff --git a/libs/containers/Message.lua b/libs/containers/Message.lua index 989e8af5..61434771 100644 --- a/libs/containers/Message.lua +++ b/libs/containers/Message.lua @@ -16,7 +16,7 @@ local Resolver = require('client/Resolver') local insert = table.insert local null = json.null local format = string.format -local messageFlag = enums.messageFlag +local messageFlag = assert(enums.messageFlag) local band, bor, bnot = bit.band, bit.bor, bit.bnot local Message, get = require('class')('Message', Snowflake) diff --git a/libs/containers/Webhook.lua b/libs/containers/Webhook.lua index 610af95c..cd91f6dc 100644 --- a/libs/containers/Webhook.lua +++ b/libs/containers/Webhook.lua @@ -11,7 +11,7 @@ local Snowflake = require('containers/abstract/Snowflake') local User = require('containers/User') local Resolver = require('client/Resolver') -local defaultAvatar = enums.defaultAvatar +local defaultAvatar = assert(enums.defaultAvatar) local Webhook, get = require('class')('Webhook', Snowflake) diff --git a/libs/containers/abstract/Channel.lua b/libs/containers/abstract/Channel.lua index d8f4d1a2..6c766d38 100644 --- a/libs/containers/abstract/Channel.lua +++ b/libs/containers/abstract/Channel.lua @@ -8,7 +8,7 @@ local Snowflake = require('containers/abstract/Snowflake') local enums = require('enums') local format = string.format -local channelType = enums.channelType +local channelType = assert(enums.channelType) local Channel, get = require('class')('Channel', Snowflake) diff --git a/libs/containers/abstract/GuildChannel.lua b/libs/containers/abstract/GuildChannel.lua index 3fa4b5f4..ffec2087 100644 --- a/libs/containers/abstract/GuildChannel.lua +++ b/libs/containers/abstract/GuildChannel.lua @@ -15,7 +15,7 @@ local Resolver = require('client/Resolver') local isInstance = class.isInstance local classes = class.classes -local channelType = enums.channelType +local channelType = assert(enums.channelType) local insert, sort = table.insert, table.sort local min, max, floor = math.min, math.max, math.floor diff --git a/libs/iterables/Cache.lua b/libs/iterables/Cache.lua index a9c757b6..32b8ecfe 100644 --- a/libs/iterables/Cache.lua +++ b/libs/iterables/Cache.lua @@ -140,7 +140,7 @@ end is not guaranteed. ]=] function Cache:iter() - local objects, k, obj = self._objects + local objects, k, obj = self._objects, nil, nil return function() k, obj = next(objects, k) return obj diff --git a/libs/iterables/Iterable.lua b/libs/iterables/Iterable.lua index ebfb7b4b..86c5758b 100644 --- a/libs/iterables/Iterable.lua +++ b/libs/iterables/Iterable.lua @@ -10,7 +10,7 @@ all stored objects should have a `__hash` method. ]=] local random = math.random -local insert, sort, pack = table.insert, table.sort, table.pack +local insert, sort, pack, unpack = table.insert, table.sort, table.pack, table.unpack local Iterable = require('class')('Iterable') @@ -240,6 +240,7 @@ function Iterable:select(...) return sorter(a[i], b[i]) end end + return false end) return rows end diff --git a/libs/iterables/SecondaryCache.lua b/libs/iterables/SecondaryCache.lua index 660fd2c2..443a834d 100644 --- a/libs/iterables/SecondaryCache.lua +++ b/libs/iterables/SecondaryCache.lua @@ -68,7 +68,7 @@ end is not guaranteed. ]=] function SecondaryCache:iter() - local objects, k, obj = self._objects + local objects, k, obj = self._objects, nil, nil return function() k, obj = next(objects, k) return obj diff --git a/libs/utils/Clock.lua b/libs/utils/Clock.lua index 892abc28..b0c3835d 100644 --- a/libs/utils/Clock.lua +++ b/libs/utils/Clock.lua @@ -32,7 +32,7 @@ function Clock:start(utc) local prev = date(fmt) self._interval = setInterval(1000, function() local now = date(fmt) - for k, v in pairs(now) do + for k, v in pairs(now) do ---@diagnostic disable-line: param-type-mismatch if v ~= prev[k] then self:emit(k, now) end diff --git a/libs/utils/Date.lua b/libs/utils/Date.lua index 73d694a0..dc5a521f 100644 --- a/libs/utils/Date.lua +++ b/libs/utils/Date.lua @@ -30,7 +30,7 @@ local months = { } local function offset() -- difference between *t and !*t - return difftime(time(), time(date('!*t'))) + return difftime(time(), time(date('!*t'))) ---@diagnostic disable-line: param-type-mismatch end local Date = class('Date') diff --git a/libs/utils/Logger.lua b/libs/utils/Logger.lua index cc582ecb..2d72b7d3 100644 --- a/libs/utils/Logger.lua +++ b/libs/utils/Logger.lua @@ -15,7 +15,7 @@ local fs = require('fs') local date = os.date local format = string.format -local stdout = _G.process.stdout.handle +local stdout = _G.process.stdout.handle ---@diagnostic disable-line: undefined-field local openSync, writeSync = fs.openSync, fs.writeSync -- local BLACK = 30 @@ -37,7 +37,7 @@ local config = { do -- parse config local bold = 1 for _, v in ipairs(config) do - v[2] = format('\27[%i;%im%s\27[0m', bold, v[2], v[1]) + v[3] = format('\27[%i;%im%s\27[0m', bold, v[2], v[1]) end end @@ -73,7 +73,7 @@ function Logger:log(level, msg, ...) if self._file then writeSync(self._file, -1, format('%s | %s | %s\n', d, tag[1], msg)) end - stdout:write(format('%s | %s | %s\n', d, tag[2], msg)) + stdout:write(format('%s | %s | %s\n', d, tag[3], msg)) return msg diff --git a/libs/utils/Mutex.lua b/libs/utils/Mutex.lua index fd575805..a5a6c7c1 100644 --- a/libs/utils/Mutex.lua +++ b/libs/utils/Mutex.lua @@ -5,7 +5,7 @@ @d Mutual exclusion class used to control Lua coroutine execution order. ]=] -local Deque = require('./Deque') +local Deque = require('utils/Deque') local timer = require('timer') local yield = coroutine.yield diff --git a/libs/utils/Permissions.lua b/libs/utils/Permissions.lua index e2a4be67..c41d47f5 100644 --- a/libs/utils/Permissions.lua +++ b/libs/utils/Permissions.lua @@ -10,7 +10,7 @@ permissions. See the `permission` enumeration for acceptable permission values. local enums = require('enums') local Resolver = require('client/Resolver') -local permission = enums.permission +local permission = assert(enums.permission) local format = string.format local band, bor, bnot, bxor = bit.band, bit.bor, bit.bnot, bit.bxor diff --git a/libs/voice/VoiceConnection.lua b/libs/voice/VoiceConnection.lua index d1fd744b..5eb20272 100644 --- a/libs/voice/VoiceConnection.lua +++ b/libs/voice/VoiceConnection.lua @@ -11,8 +11,8 @@ local FFmpegProcess = require('voice/streams/FFmpegProcess') local uv = require('uv') local ffi = require('ffi') local constants = require('constants') -local opus = require('voice/opus') -local sodium = require('voice/sodium') +local opus = require('voice/opus') or {} +local sodium = require('voice/sodium') or {} local CHANNELS = 2 local SAMPLE_RATE = 48000 -- Hz diff --git a/libs/voice/VoiceManager.lua b/libs/voice/VoiceManager.lua index 84ab0a71..9ea97645 100644 --- a/libs/voice/VoiceManager.lua +++ b/libs/voice/VoiceManager.lua @@ -1,8 +1,8 @@ local VoiceSocket = require('voice/VoiceSocket') local Emitter = require('utils/Emitter') -local opus = require('voice/opus') -local sodium = require('voice/sodium') +local opus = require('voice/opus') or {} +local sodium = require('voice/sodium') or {} local constants = require('constants') local wrap = coroutine.wrap diff --git a/libs/voice/VoiceSocket.lua b/libs/voice/VoiceSocket.lua index 867de259..1bfbc599 100644 --- a/libs/voice/VoiceSocket.lua +++ b/libs/voice/VoiceSocket.lua @@ -5,7 +5,7 @@ local enums = require('enums') local WebSocket = require('client/WebSocket') -local logLevel = enums.logLevel +local logLevel = assert(enums.logLevel) local format = string.format local setInterval, clearInterval = timer.setInterval, timer.clearInterval local wrap = coroutine.wrap From ee7b2f80ee012dc8908218b926f072b2b3d1fe96 Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sun, 8 Jan 2023 19:07:32 -0500 Subject: [PATCH 02/22] Adds a bunch of missing enumerations --- libs/enums.lua | 152 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 108 insertions(+), 44 deletions(-) diff --git a/libs/enums.lua b/libs/enums.lua index f3b4327c..fae80022 100644 --- a/libs/enums.lua +++ b/libs/enums.lua @@ -46,17 +46,28 @@ enums.notificationSetting = enum { } enums.channelType = enum { - text = 0, - private = 1, - voice = 2, - group = 3, - category = 4, - news = 5, + text = 0, + private = 1, + voice = 2, + group = 3, + category = 4, + news = 5, + store = 6, + -- unused = 7, + -- unused = 8, + -- unused = 9, + newsThread = 10, + publicThread = 11, + privateThread = 12, + stageVoice = 13, + directory = 14, + forum = 15, } enums.webhookType = enum { incoming = 1, channelFollower = 2, + application = 3, } enums.messageType = enum { @@ -72,6 +83,20 @@ enums.messageType = enum { premiumGuildSubscriptionTier1 = 9, premiumGuildSubscriptionTier2 = 10, premiumGuildSubscriptionTier3 = 11, + channelFollowAdd = 12, + -- unused (guildStream) = 13, + guildDiscoveryDisqualified = 14, + guildDiscoveryRequalified = 15, + guildDiscoveryInitialWarning = 16, + guildDiscoveryFinalWarning = 17, + threadCreated = 18, + reply = 19, + chatInputCommand = 20, + threadStarterMessage = 21, + guildInviteReminder = 22, + contextMenuCommand = 23, + autoModerationAction = 24, + roleSubscriptionPurchase = 25, } enums.relationshipType = enum { @@ -86,21 +111,26 @@ enums.activityType = enum { default = 0, streaming = 1, listening = 2, + watching = 3, custom = 4, + competing = 5, } enums.status = enum { - online = 'online', - idle = 'idle', + online = 'online', + idle = 'idle', doNotDisturb = 'dnd', - invisible = 'invisible', + invisible = 'invisible', -- only sent? + offline = 'offline', -- only received? } enums.gameType = enum { -- NOTE: deprecated; use activityType default = 0, streaming = 1, listening = 2, + watching = 3, custom = 4, + competing = 5, } enums.verificationLevel = enum { @@ -124,45 +154,61 @@ enums.premiumTier = enum { tier3 = 3, } +local function flag(n) + return 2^n +end + enums.permission = enum { - createInstantInvite = 0x00000001, - kickMembers = 0x00000002, - banMembers = 0x00000004, - administrator = 0x00000008, - manageChannels = 0x00000010, - manageGuild = 0x00000020, - addReactions = 0x00000040, - viewAuditLog = 0x00000080, - prioritySpeaker = 0x00000100, - stream = 0x00000200, - readMessages = 0x00000400, - sendMessages = 0x00000800, - sendTextToSpeech = 0x00001000, - manageMessages = 0x00002000, - embedLinks = 0x00004000, - attachFiles = 0x00008000, - readMessageHistory = 0x00010000, - mentionEveryone = 0x00020000, - useExternalEmojis = 0x00040000, - connect = 0x00100000, - speak = 0x00200000, - muteMembers = 0x00400000, - deafenMembers = 0x00800000, - moveMembers = 0x01000000, - useVoiceActivity = 0x02000000, - changeNickname = 0x04000000, - manageNicknames = 0x08000000, - manageRoles = 0x10000000, - manageWebhooks = 0x20000000, - manageEmojis = 0x40000000, + createInstantInvite = flag(0), + kickMembers = flag(1), + banMembers = flag(2), + administrator = flag(3), + manageChannels = flag(4), + manageGuild = flag(5), + addReactions = flag(6), + viewAuditLog = flag(7), + prioritySpeaker = flag(8), + stream = flag(9), + readMessages = flag(10), + sendMessages = flag(11), + sendTextToSpeech = flag(12), + manageMessages = flag(13), + embedLinks = flag(14), + attachFiles = flag(15), + readMessageHistory = flag(16), + mentionEveryone = flag(17), + useExternalEmojis = flag(18), + viewGuildInsights = flag(19), + connect = flag(20), + speak = flag(21), + muteMembers = flag(22), + deafenMembers = flag(23), + moveMembers = flag(24), + useVoiceActivity = flag(25), + changeNickname = flag(26), + manageNicknames = flag(27), + manageRoles = flag(28), + manageWebhooks = flag(29), + manageEmojis = flag(30), + useSlashCommands = flag(31), + requestToSpeak = flag(32), + manageEvents = flag(33), + manageThreads = flag(34), + usePublicThreads = flag(35), + usePrivateThreads = flag(36), } enums.messageFlag = enum { - crossposted = 0x00000001, - isCrosspost = 0x00000002, - suppressEmbeds = 0x00000004, - sourceMessageDeleted = 0x00000008, - urgent = 0x00000010, + crossposted = flag(0), + isCrosspost = flag(1), + suppressEmbeds = flag(2), + sourceMessageDeleted = flag(3), + urgent = flag(4), + hasThread = flag(5), + ephemeral = flag(6), + loading = flag(7), +} + } enums.actionType = enum { @@ -201,6 +247,24 @@ enums.actionType = enum { integrationCreate = 80, integrationUpdate = 81, integrationDelete = 82, + stageInstanceCreate = 83, + stageInstanceUpdate = 84, + stageInstanceDelete = 85, + stickerCreate = 90, + stickerUpdate = 91, + stickerDelete = 92, + eventCreate = 100, + eventUpdate = 101, + eventDelete = 102, + threadCreate = 110, + threadUpdate = 111, + threadDelete = 112, + autoModRuleCreate = 140, + autoModRuleUpdate = 141, + autoModRuleDelete = 142, + autoModMessageBlock = 144, + autoModMessageFlag = 144, + autoModUserTimeout = 145, } enums.logLevel = enum { From dfaf4b07eb9567f5841c81e5f783354339f1a87f Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 9 Jan 2023 11:52:11 -0500 Subject: [PATCH 03/22] Adds support for gateway intents --- libs/client/Client.lua | 45 ++++++++++++++++++++++++++++++++++++++++ libs/client/Resolver.lua | 12 +++++++++++ libs/client/Shard.lua | 1 + libs/enums.lua | 25 +++++++++++++++++++++- 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/libs/client/Client.lua b/libs/client/Client.lua index 4b59c462..2326fd59 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -39,9 +39,11 @@ local VoiceManager = require('voice/VoiceManager') local encode, decode, null = json.encode, json.decode, json.null local readFileSync, writeFileSync = fs.readFileSync, fs.writeFileSync +local band, bor, bnot = bit.band, bit.bor, bit.bnot local logLevel = assert(enums.logLevel) local gameType = assert(enums.gameType) +local gatewayIntent = assert(enums.gatewayIntent) local wrap = coroutine.wrap local time, difftime = os.time, os.difftime @@ -68,6 +70,7 @@ local defaultOptions = { gatewayFile = 'gateway.json', dateTime = '%F %T', syncGuilds = false, + gatewayIntents = 3243773, -- all non-privileged intents } local function parseOptions(customOptions) @@ -118,6 +121,7 @@ function Client:__init(options) self._emoji_map = {} self._channel_map = {} self._events = require('client/EventHandler') + self._intents = options.gatewayIntents end for name, level in pairs(logLevel) do @@ -297,6 +301,47 @@ function Client:stop() end end +local function getIntent(i, ...) + local v = select(i, ...) + local n = Resolver.gatewayIntent(v) + if not n then + return error('Invalid gateway intent: ' .. tostring(v), 2) + end + return n +end + +function Client:getIntents() + return self._intents +end + +function Client:setIntents(intents) + self._intents = tonumber(intents) or 0 +end + +function Client:enableIntents(...) + for i = 1, select('#', ...) do + local intent = getIntent(i, ...) + self._intents = bor(self._intents, intent) + end +end + +function Client:disableIntents(...) + for i = 1, select('#', ...) do + local intent = getIntent(i, ...) + self._intents = band(self._intents, bnot(intent)) + end +end + +function Client:enableAllIntents() + for _, value in pairs(gatewayIntent) do + self._intents = bor(self._intents, value) + end +end + +function Client:disableAllIntents() + self._intents = 0 +end + function Client:_modify(payload) local data, err = self._api:modifyCurrentUser(payload) if data then diff --git a/libs/client/Resolver.lua b/libs/client/Resolver.lua index f1186920..c4d85e37 100644 --- a/libs/client/Resolver.lua +++ b/libs/client/Resolver.lua @@ -5,6 +5,7 @@ local class = require('class') local enums = require('enums') local permission = assert(enums.permission) +local gatewayIntent = assert(enums.gatewayIntent) local actionType = assert(enums.actionType) local messageFlag = assert(enums.messageFlag) local base64 = ssl.base64 @@ -163,6 +164,17 @@ function Resolver.permission(obj) return n end +function Resolver.gatewayIntent(obj) + local t = type(obj) + local n = nil + if t == 'string' then + n = gatewayIntent[obj] + elseif t == 'number' then + n = gatewayIntent(obj) and obj + end + return n +end + function Resolver.actionType(obj) local t = type(obj) local n = nil diff --git a/libs/client/Shard.lua b/libs/client/Shard.lua index 31d5e250..6ab809e9 100644 --- a/libs/client/Shard.lua +++ b/libs/client/Shard.lua @@ -222,6 +222,7 @@ function Shard:identify() large_threshold = options.largeThreshold, shard = {self._id, client._total_shard_count}, presence = next(client._presence) and client._presence, + intents = client._intents, }, true) end diff --git a/libs/enums.lua b/libs/enums.lua index fae80022..4fd25846 100644 --- a/libs/enums.lua +++ b/libs/enums.lua @@ -209,6 +209,29 @@ enums.messageFlag = enum { loading = flag(7), } +enums.gatewayIntent = enum { + guilds = flag(0), + guildMembers = flag(1), -- privileged + guildBans = flag(2), + guildEmojis = flag(3), + guildIntegrations = flag(4), + guildWebhooks = flag(5), + guildInvites = flag(6), + guildVoiceStates = flag(7), + guildPresences = flag(8), -- privileged + guildMessages = flag(9), + guildMessageReactions = flag(10), + guildMessageTyping = flag(11), + directMessage = flag(12), + directMessageRections = flag(13), + directMessageTyping = flag(14), + messageContent = flag(15), -- privileged + guildScheduledEvents = flag(16), + -- unused = flag(17), + -- unused = flag(18), + -- unused = flag(19), + autoModConfiguration = flag(20), + autoModExecution = flag(21), } enums.actionType = enum { @@ -262,7 +285,7 @@ enums.actionType = enum { autoModRuleCreate = 140, autoModRuleUpdate = 141, autoModRuleDelete = 142, - autoModMessageBlock = 144, + autoModMessageBlock = 143, autoModMessageFlag = 144, autoModUserTimeout = 145, } From 6493e89d787199b592c6b1fbb8f562487030053f Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 9 Jan 2023 13:18:38 -0500 Subject: [PATCH 04/22] Adds support for permission precision greater than 32 bits --- libs/containers/Member.lua | 53 +++++++++++-------------- libs/containers/PermissionOverwrite.lua | 44 ++++++++++---------- libs/containers/Role.lua | 4 +- libs/utils/Permissions.lua | 12 +++--- 4 files changed, 56 insertions(+), 57 deletions(-) diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index 996d9551..d4eadd88 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -19,7 +19,6 @@ local Date = require('utils/Date') local Time = require('utils/Time') local insert, remove, sort = table.insert, table.remove, table.sort -local band, bor, bnot = bit.band, bit.bor, bit.bnot local isInstance = class.isInstance local permission = assert(enums.permission) @@ -75,10 +74,6 @@ function Member:getColor() return roles[1] and roles[1]:getColor() or Color() end -local function has(a, b) - return band(a, b) > 0 -end - --[=[ @m hasPermission @t mem @@ -113,15 +108,15 @@ function Member:hasPermission(channel, perm) return true end - local rolePermissions = guild.defaultRole.permissions + local rolePermissions = guild.defaultRole:getPermissions() for role in self.roles:iter() do if role.id ~= guild.id then -- just in case - rolePermissions = bor(rolePermissions, role.permissions) + rolePermissions = rolePermissions:union(role:getPermissions()) end end - if has(rolePermissions, permission.administrator) then + if rolePermissions:has(permission.administrator) then return true end @@ -131,10 +126,10 @@ function Member:hasPermission(channel, perm) local overwrite = overwrites:get(self.id) if overwrite then - if has(overwrite.allowedPermissions, n) then + if overwrite:getAllowedPermissions():has(n) then return true end - if has(overwrite.deniedPermissions, n) then + if overwrite:getDeniedPermissions():has(n) then return false end end @@ -144,32 +139,32 @@ function Member:hasPermission(channel, perm) if role.id ~= guild.id then -- just in case overwrite = overwrites:get(role.id) if overwrite then - allow = bor(allow, overwrite.allowedPermissions) - deny = bor(deny, overwrite.deniedPermissions) + allow = allow:union(overwrite:getAllowedPermissions()) + deny = deny:union(overwrite:getDeniedPermissions()) end end end - if has(allow, n) then + if allow:has(n) then return true end - if has(deny, n) then + if deny:has(n) then return false end local everyone = overwrites:get(guild.id) if everyone then - if has(everyone.allowedPermissions, n) then + if everyone:getAllowedPermissions():has(n) then return true end - if has(everyone.deniedPermissions, n) then + if everyone:getDeniedPermissions():has(n) then return false end end end - return has(rolePermissions, n) + return rolePermissions:has(n) end @@ -195,15 +190,15 @@ function Member:getPermissions(channel) return Permissions.all() end - local ret = guild.defaultRole.permissions + local ret = guild.defaultRole:getPermissions() for role in self.roles:iter() do if role.id ~= guild.id then -- just in case - ret = bor(ret, role.permissions) + ret = ret:union(role:getPermissions()) end end - if band(ret, permission.administrator) > 0 then + if ret:has(permission.administrator) then return Permissions.all() end @@ -213,8 +208,8 @@ function Member:getPermissions(channel) local everyone = overwrites:get(guild.id) if everyone then - ret = band(ret, bnot(everyone.deniedPermissions)) - ret = bor(ret, everyone.allowedPermissions) + ret = ret:complement(everyone:getDeniedPermissions()) + ret = ret:union(everyone:getAllowedPermissions()) end local allow, deny = 0, 0 @@ -222,23 +217,23 @@ function Member:getPermissions(channel) if role.id ~= guild.id then -- just in case local overwrite = overwrites:get(role.id) if overwrite then - deny = bor(deny, overwrite.deniedPermissions) - allow = bor(allow, overwrite.allowedPermissions) + deny = deny:union(overwrite:getDeniedPermissions()) + allow = allow:union(overwrite:getAllowedPermissions()) end end end - ret = band(ret, bnot(deny)) - ret = bor(ret, allow) + ret = ret:complement(deny) + ret = ret:union(allow) local overwrite = overwrites:get(self.id) if overwrite then - ret = band(ret, bnot(overwrite.deniedPermissions)) - ret = bor(ret, overwrite.allowedPermissions) + ret = ret:complement(overwrite:getDeniedPermissions()) + ret = ret:union(overwrite:getAllowedPermissions()) end end - return Permissions(ret) + return ret end diff --git a/libs/containers/PermissionOverwrite.lua b/libs/containers/PermissionOverwrite.lua index 294ab97c..d2c0a8ff 100644 --- a/libs/containers/PermissionOverwrite.lua +++ b/libs/containers/PermissionOverwrite.lua @@ -8,8 +8,6 @@ local Snowflake = require('containers/abstract/Snowflake') local Permissions = require('utils/Permissions') local Resolver = require('client/Resolver') -local band, bnot = bit.band, bit.bnot - local PermissionOverwrite, get = require('class')('PermissionOverwrite', Snowflake) function PermissionOverwrite:__init(data, parent) @@ -53,7 +51,7 @@ function PermissionOverwrite:getObject() end local function getPermissions(self) - return Permissions(self._allow), Permissions(self._deny) + return Permissions(self._allow_new or self._allow), Permissions(self._deny_new or self._deny) end local function setPermissions(self, allow, deny) @@ -76,7 +74,7 @@ end explicitly allows. ]=] function PermissionOverwrite:getAllowedPermissions() - return Permissions(self._allow) + return Permissions(self._allow_new or self._allow) end --[=[ @@ -87,7 +85,7 @@ end explicitly denies. ]=] function PermissionOverwrite:getDeniedPermissions() - return Permissions(self._deny) + return Permissions(self._deny_new or self._deny) end --[=[ @@ -113,9 +111,9 @@ end @d Sets the permissions that this overwrite explicitly allows. ]=] function PermissionOverwrite:setAllowedPermissions(allowed) - local allow = Resolver.permissions(allowed) - local deny = band(bnot(allow), self._deny) -- un-deny the allowed permissions - return setPermissions(self, allow, deny) + local allow = Permissions(Resolver.permissions(allowed)) + local deny = allow:complement(self:getDeniedPermissions()) -- un-deny the allowed permissions + return setPermissions(self, allow.value, deny.value) end --[=[ @@ -126,9 +124,9 @@ end @d Sets the permissions that this overwrite explicitly denies. ]=] function PermissionOverwrite:setDeniedPermissions(denied) - local deny = Resolver.permissions(denied) - local allow = band(bnot(deny), self._allow) -- un-allow the denied permissions - return setPermissions(self, allow, deny) + local deny = Permissions(Resolver.permissions(denied)) + local allow = deny:complement(self:getAllowedPermissions()) -- un-allow the denied permissions + return setPermissions(self, allow.value, deny.value) end --[=[ @@ -141,7 +139,7 @@ end function PermissionOverwrite:allowPermissions(...) local allowed, denied = getPermissions(self) allowed:enable(...); denied:disable(...) - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[ @@ -154,7 +152,7 @@ end function PermissionOverwrite:denyPermissions(...) local allowed, denied = getPermissions(self) allowed:disable(...); denied:enable(...) - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[ @@ -167,7 +165,7 @@ end function PermissionOverwrite:clearPermissions(...) local allowed, denied = getPermissions(self) allowed:disable(...); denied:disable(...) - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[ @@ -179,7 +177,7 @@ end function PermissionOverwrite:allowAllPermissions() local allowed, denied = getPermissions(self) allowed:enableAll(); denied:disableAll() - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[ @@ -191,7 +189,7 @@ end function PermissionOverwrite:denyAllPermissions() local allowed, denied = getPermissions(self) allowed:disableAll(); denied:enableAll() - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[ @@ -203,12 +201,18 @@ end function PermissionOverwrite:clearAllPermissions() local allowed, denied = getPermissions(self) allowed:disableAll(); denied:disableAll() - return setPermissions(self, allowed._value, denied._value) + return setPermissions(self, allowed.value, denied.value) end --[=[@p type string The overwrite type; either "role" or "member".]=] function get.type(self) - return self._type + if type(self._type) == 'string' then + return self._type + elseif self._type == 1 then + return 'member' + else -- 0 + return 'role' + end end --[=[@p channel GuildChannel The channel in which this overwrite exists.]=] @@ -223,12 +227,12 @@ end --[=[@p allowedPermissions number The number representing the total permissions allowed by this overwrite.]=] function get.allowedPermissions(self) - return self._allow + return tonumber(self._allow_new) or tonumber(self._allow) end --[=[@p deniedPermissions number The number representing the total permissions denied by this overwrite.]=] function get.deniedPermissions(self) - return self._deny + return tonumber(self._deny_new) or tonumber(self._deny) end return PermissionOverwrite diff --git a/libs/containers/Role.lua b/libs/containers/Role.lua index 4d35dcb8..dea7c072 100644 --- a/libs/containers/Role.lua +++ b/libs/containers/Role.lua @@ -304,7 +304,7 @@ end has enabled. ]=] function Role:getPermissions() - return Permissions(self._permissions) + return Permissions(self._permissions_new or self._permissions) end --[=[@p hoisted boolean Whether members with this role should be shown separated from other members @@ -340,7 +340,7 @@ end --[=[@p permissions number Represents the total permissions of the role as a decimal value.]=] function get.permissions(self) - return self._permissions + return tonumber(self._permissions_new) or tonumber(self._permissions) end --[=[@p mentionString string A string that, when included in a message content, may resolve as a role diff --git a/libs/utils/Permissions.lua b/libs/utils/Permissions.lua index c41d47f5..7c069a76 100644 --- a/libs/utils/Permissions.lua +++ b/libs/utils/Permissions.lua @@ -16,7 +16,7 @@ local format = string.format local band, bor, bnot, bxor = bit.band, bit.bor, bit.bnot, bit.bxor local sort, insert, concat = table.sort, table.insert, table.concat -local ALL = 0 +local ALL = 0ULL for _, value in pairs(permission) do ALL = bor(ALL, value) end @@ -24,7 +24,7 @@ end local Permissions, get = require('class')('Permissions') function Permissions:__init(value) - self._value = tonumber(value) or 0 + self._value = (tonumber(value) or 0) + 0ULL end --[=[ @@ -39,7 +39,7 @@ function Permissions:__tostring() else local a = self:toArray() sort(a) - return format('Permissions: %i (%s)', self._value, concat(a, ', ')) + return format('Permissions: %i (%s)', self.value, concat(a, ', ')) end end @@ -82,7 +82,7 @@ local function getPerm(i, ...) if not n then return error('Invalid permission: ' .. tostring(v), 2) end - return n + return n + 0ULL end --[=[ @@ -150,7 +150,7 @@ end @d Disables all permissions values. ]=] function Permissions:disableAll() - self._value = 0 + self._value = 0ULL end --[=[ @@ -249,7 +249,7 @@ end --[=[@p value number The raw decimal value that represents the permissions value.]=] function get.value(self) - return self._value + return tonumber(self._value) end return Permissions From dc84182641ea7190906a802137350fbe761e450a Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 9 Jan 2023 18:38:38 -0500 Subject: [PATCH 05/22] Removes gaming. --- libs/client/Client.lua | 45 +++++++++++++---------- libs/containers/Activity.lua | 10 ++--- libs/containers/abstract/UserPresence.lua | 22 +++++------ 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/libs/client/Client.lua b/libs/client/Client.lua index 2326fd59..6ac81cb9 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -42,7 +42,7 @@ local readFileSync, writeFileSync = fs.readFileSync, fs.writeFileSync local band, bor, bnot = bit.band, bit.bor, bit.bnot local logLevel = assert(enums.logLevel) -local gameType = assert(enums.gameType) +local activityType = assert(enums.activityType) local gatewayIntent = assert(enums.gatewayIntent) local wrap = coroutine.wrap @@ -281,7 +281,7 @@ managed by Luvit libraries and a libuv event loop, multiple clients per process and multiple shards per client can operate concurrently. This should be the last method called after all other code and event handlers have been initialized. If a presence table is provided, it will act as if the user called `setStatus` -and `setGame` after `run`. +and `setActivity` after `run`. ]=] function Client:run(token, presence) self._presence = presence or {} @@ -573,7 +573,7 @@ end local function updateStatus(self) local presence = self._presence presence.afk = presence.afk or null - presence.game = presence.game or null + presence.activities = presence.activity and {presence.activity} or null presence.since = presence.since or null presence.status = presence.status or null for _, shard in pairs(self._shards) do @@ -604,35 +604,40 @@ function Client:setStatus(status) return updateStatus(self) end +function Client:setGame(game) + self:_deprecated(self.__name, 'setGame', 'setActivity') + return self:setActivity(game) +end + --[=[ -@m setGame +@m setActivity @t ws -@p game string/table +@p activity string/table @r nil -@d Sets the current user's game on all shards that are managed by this client. -If a string is passed, it is treated as the game name. If a table is passed, it +@d Sets the current user's activity on all shards that are managed by this client. +If a string is passed, it is treated as the activity name. If a table is passed, it must have a `name` field and may optionally have a `url` or `type` field. Pass `nil` to -remove the game status. +remove the activity status. ]=] -function Client:setGame(game) - if type(game) == 'string' then - game = {name = game, type = gameType.default} - elseif type(game) == 'table' then - if type(game.name) == 'string' then - if type(game.type) ~= 'number' then - if type(game.url) == 'string' then - game.type = gameType.streaming +function Client:setActivity(activity) + if type(activity) == 'string' then + activity = {name = activity, type = activityType.default} + elseif type(activity) == 'table' then + if type(activity.name) == 'string' then + if type(activity.type) ~= 'number' then + if type(activity.url) == 'string' then + activity.type = activityType.streaming else - game.type = gameType.default + activity.type = activityType.default end end else - game = null + activity = null end else - game = null + activity = null end - self._presence.game = game + self._presence.activity = activity return updateStatus(self) end diff --git a/libs/containers/Activity.lua b/libs/containers/Activity.lua index 0ed95247..b8dd9a22 100644 --- a/libs/containers/Activity.lua +++ b/libs/containers/Activity.lua @@ -1,7 +1,7 @@ --[=[ @c Activity -@d Represents a Discord user's presence data, either plain game or streaming presence or a rich presence. -Most if not all properties may be nil. +@d Represents a Discord user's presence data, either an application or streaming +presence or a rich presence. Most if not all properties may be nil. ]=] local Container = require('containers/abstract/Container') @@ -58,18 +58,18 @@ function get.stop(self) return self._stop end ---[=[@p name string/nil The game that the user is currently playing.]=] +--[=[@p name string/nil The name of the activity in which the user is currently engaged.]=] function get.name(self) return self._name end ---[=[@p type number/nil The type of user's game status. See the `activityType` +--[=[@p type number/nil The user's activity type. See the `activityType` enumeration for a human-readable representation.]=] function get.type(self) return self._type end ---[=[@p url string/nil The URL that is set for a user's streaming game status.]=] +--[=[@p url string/nil The URL for a user's streaming activity.]=] function get.url(self) return self._url end diff --git a/libs/containers/abstract/UserPresence.lua b/libs/containers/abstract/UserPresence.lua index 022e6157..229a69f1 100644 --- a/libs/containers/abstract/UserPresence.lua +++ b/libs/containers/abstract/UserPresence.lua @@ -38,29 +38,29 @@ function UserPresence:_loadPresence(presence) self._mobile_status = status.mobile self._desktop_status = status.desktop end - local game = presence.game - if game == null then + local activity = presence.activities[1] + if activity == null then self._activity = nil - elseif game then + elseif activity then local arr = presence.activities if arr and arr[2] then for i = 2, #arr do for k, v in pairs(arr[i]) do - game[k] = v + activity[k] = v end end end if self._activity then - self._activity:_load(game) + self._activity:_load(activity) else - local activity = activities[self:__hash()] - if activity then - activity:_load(game) + local cached = activities[self:__hash()] + if cached then + cached:_load(activity) else - activity = Activity(game, self) - activities[self:__hash()] = activity + cached = Activity(activity, self) + activities[self:__hash()] = cached end - self._activity = activity + self._activity = cached end end end From eb055792cebf0efd30e03ea8c15c17c134047aae Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 16 Jan 2023 10:35:27 -0500 Subject: [PATCH 06/22] Preparation for Discord API version bump --- libs/client/API.lua | 9 +++-- libs/client/EventHandler.lua | 64 ++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/libs/client/API.lua b/libs/client/API.lua index 4a1ea6b3..0319c8f3 100644 --- a/libs/client/API.lua +++ b/libs/client/API.lua @@ -13,8 +13,8 @@ local insert, concat = table.insert, table.concat local sleep = timer.sleep local running = coroutine.running -local BASE_URL = "https://discord.com/api/v7" - +local VERSION = 7 +local BASE_URL = "https://discord.com/api/" .. 'v' .. VERSION local JSON = 'application/json' local PRECISION = 'millisecond' local MULTIPART = 'multipart/form-data;boundary=' @@ -144,10 +144,13 @@ function API:request(method, endpoint, payload, query, files) local req = { {'User-Agent', USER_AGENT}, - {'X-RateLimit-Precision', PRECISION}, {'Authorization', self._token}, } + if VERSION < 8 then + insert(req, {'X-RateLimit-Precision', PRECISION}) + end + if payloadRequired[method] then payload = payload and encode(payload) or '{}' if files and next(files) then diff --git a/libs/client/EventHandler.lua b/libs/client/EventHandler.lua index 72ec09aa..8ca25c47 100644 --- a/libs/client/EventHandler.lua +++ b/libs/client/EventHandler.lua @@ -427,13 +427,6 @@ function EventHandler.PRESENCE_UPDATE(d, client) -- may have incomplete data else if d.status == 'offline' then -- uncache offline members member = guild._members:_delete(d.user.id) - else - if d.user.username then -- member was offline - member = guild._members:_insert(d) - elseif user then -- member was invisible, user is still cached - member = guild._members:_insert(d) - member._user = user - end end end if member then @@ -537,4 +530,61 @@ function EventHandler.WEBHOOKS_UPDATE(d, client) -- webhook object is not provid return client:emit('webhooksUpdate', channel) end +function EventHandler.AUTO_MODERATION_RULE_CREATE(d, client) +end + +function EventHandler.AUTO_MODERATION_RULE_UPDATE(d, client) +end + +function EventHandler.AUTO_MODERATION_RULE_DELETE(d, client) +end + +function EventHandler.AUTO_MODERATION_ACTION_EXECUTION(d, client) +end + +function EventHandler.THREAD_CREATE(d, client) +end + +function EventHandler.THREAD_UPDATE(d, client) +end + +function EventHandler.THREAD_DELETE(d, client) +end + +function EventHandler.THREAD_LIST_SYNC(d, client) +end + +function EventHandler.THREAD_MEMBER_UPDATE(d, client) +end + +function EventHandler.THREAD_MEMBERS_UPDATE(d, client) +end + +function EventHandler.GUILD_STICKERS_UPDATE(d, client) +end + +function EventHandler.GUILD_SCHEDULED_EVENT_CREATE(d, client) +end + +function EventHandler.GUILD_SCHEDULED_EVENT_UPDATE(d, client) +end + +function EventHandler.GUILD_SCHEDULED_EVENT_DELETE(d, client) +end + +function EventHandler.GUILD_SCHEDULED_EVENT_USER_ADD(d, client) +end + +function EventHandler.GUILD_SCHEDULED_EVENT_USER_REMOVE(d, client) +end + +function EventHandler.STAGE_INSTANCE_CREATE(d, client) +end + +function EventHandler.STAGE_INSTANCE_UPDATE(d, client) +end + +function EventHandler.STAGE_INSTANCE_DELETE(d, client) +end + return EventHandler From 141c777d9dc017dfd368f3a6e7aedf76141fb81b Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 16 Jan 2023 13:33:46 -0500 Subject: [PATCH 07/22] Some more v8 preparation --- libs/client/API.lua | 7 ++++--- libs/client/Client.lua | 9 +++++++-- libs/client/EventHandler.lua | 3 +++ libs/constants.lua | 2 +- libs/containers/Member.lua | 2 +- libs/enums.lua | 2 +- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/libs/client/API.lua b/libs/client/API.lua index 0319c8f3..ebc6d3ca 100644 --- a/libs/client/API.lua +++ b/libs/client/API.lua @@ -4,6 +4,7 @@ local http = require('coro-http') local package = require('../../package.lua') local Mutex = require('utils/Mutex') local endpoints = require('endpoints') +local constants = require('constants') local request = http.request local f, gsub, byte = string.format, string.gsub, string.byte @@ -13,8 +14,8 @@ local insert, concat = table.insert, table.concat local sleep = timer.sleep local running = coroutine.running -local VERSION = 7 -local BASE_URL = "https://discord.com/api/" .. 'v' .. VERSION +local API_VERSION = constants.API_VERSION +local BASE_URL = "https://discord.com/api/" .. 'v' .. API_VERSION local JSON = 'application/json' local PRECISION = 'millisecond' local MULTIPART = 'multipart/form-data;boundary=' @@ -147,7 +148,7 @@ function API:request(method, endpoint, payload, query, files) {'Authorization', self._token}, } - if VERSION < 8 then + if API_VERSION < 8 then insert(req, {'X-RateLimit-Precision', PRECISION}) end diff --git a/libs/client/Client.lua b/libs/client/Client.lua index 6ac81cb9..a240b2f9 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -50,7 +50,7 @@ local time, difftime = os.time, os.difftime local format = string.format local CACHE_AGE = constants.CACHE_AGE -local GATEWAY_VERSION = constants.GATEWAY_VERSION +local API_VERSION = constants.API_VERSION -- do not change these options here -- pass a custom table on client initialization instead @@ -153,6 +153,11 @@ local function run(self, token) local users = self._users local options = self._options + if options.cacheAllMembers and bit.band(self._intents, gatewayIntent.guildMembers) == 0 then + self:warning('Cannot cache all members while guildMembers intent is disabled') + options.cacheAllMembers = false + end + local user, err1 = api:authenticate(token) if not user then return self:error('Could not authenticate, check token: ' .. err1) @@ -262,7 +267,7 @@ local function run(self, token) self._shards[id] = Shard(id, self) end - local path = format('/?v=%i&encoding=json', GATEWAY_VERSION) + local path = format('/?v=%i&encoding=json', API_VERSION) for _, shard in pairs(self._shards) do wrap(shard.connect)(shard, url, path) shard:identifyWait() diff --git a/libs/client/EventHandler.lua b/libs/client/EventHandler.lua index 8ca25c47..f9e9b42c 100644 --- a/libs/client/EventHandler.lua +++ b/libs/client/EventHandler.lua @@ -587,4 +587,7 @@ end function EventHandler.STAGE_INSTANCE_DELETE(d, client) end +function EventHandler.GUILD_AUDIT_LOG_ENTRY_CREATE(d, client) +end + return EventHandler diff --git a/libs/constants.lua b/libs/constants.lua index 5836d943..48728c08 100644 --- a/libs/constants.lua +++ b/libs/constants.lua @@ -3,7 +3,7 @@ return { ID_DELAY = 5000, -- milliseconds GATEWAY_DELAY = 500, -- milliseconds, DISCORD_EPOCH = 1420070400000, -- milliseconds - GATEWAY_VERSION = 6, + API_VERSION = 7, DEFAULT_AVATARS = 5, ZWSP = '\226\128\139', NS_PER_US = 1000, diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index d4eadd88..0208a5a3 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -134,7 +134,7 @@ function Member:hasPermission(channel, perm) end end - local allow, deny = 0, 0 + local allow, deny = Permissions(), Permissions() for role in self.roles:iter() do if role.id ~= guild.id then -- just in case overwrite = overwrites:get(role.id) diff --git a/libs/enums.lua b/libs/enums.lua index 4fd25846..1bce1f14 100644 --- a/libs/enums.lua +++ b/libs/enums.lua @@ -212,7 +212,7 @@ enums.messageFlag = enum { enums.gatewayIntent = enum { guilds = flag(0), guildMembers = flag(1), -- privileged - guildBans = flag(2), + guildModeration = flag(2), guildEmojis = flag(3), guildIntegrations = flag(4), guildWebhooks = flag(5), From 5154509a7bdd50e8865284dd709d48c5ce8bd9bc Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Mon, 16 Jan 2023 14:07:44 -0500 Subject: [PATCH 08/22] Update to 2.11.0 --- CHANGELOG.md | 87 +++++++++++++++++++++++++++++++++++++++--- LICENSE | 2 +- libs/client/Client.lua | 44 +++++++++++++++++++++ libs/constants.lua | 2 +- package.lua | 4 +- 5 files changed, 129 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d19742e2..53c64b50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,87 @@ # Changelog +## 2.11.0 +- Bumped the internal Discord API version to 8. +- Added support for gateway intents: + - Added `gatewayIntent` enumeration + - Added `gatewayIntents` client option + - Added `Client:getIntents` method + - Added `Client:setIntents` method + - Added `Client:enableIntents` method + - Added `Client:disableIntents` method + - Added `Client:enableAllIntents` method + - Added `Client:disableAllIntents` method +- Added support for permission precision greater than 31 bits +- Deprecated `Client:setGame`, use `Client:setActivity` +- Added support for `embeds` field in `TextChannel:send` +- Added `channelType` enumerations: + - `store` + - `newsThread` + - `publicThread` + - `privateThread` + - `stageVoice` + - `directory` + - `forum` +- Added `webhookType` enumeration: + - `application` +- Added `messageType` enumerations: + - `channelFollowAdd` + - `guildDiscoveryDisqualified` + - `guildDiscoveryRequalified` + - `guildDiscoveryInitialWarning` + - `guildDiscoveryFinalWarning` + - `threadCreated` + - `reply` + - `chatInputCommand` + - `threadStarterMessage` + - `guildInviteReminder` + - `contextMenuCommand` + - `autoModerationAction` + - `roleSubscriptionPurchase` +- Added `activityType` enumerations: + - `watching` + - `competing` +- Added `status` enumeration: + - `offline` +- Added `permission` enumerations: + - `viewGuildInsights` + - `useSlashCommands` + - `requestToSpeak` + - `manageEvents` + - `manageThreads` + - `usePublicThreads` + - `usePrivateThreads` +- Added `messageFlag` enumerations: + - `hasThread` + - `ephemeral` + - `loading` +- Added `actionType` enumerations: + - `stageInstanceCreate` + - `stageInstanceUpdate` + - `stageInstanceDelete` + - `stickerCreate` + - `stickerUpdate` + - `stickerDelete` + - `eventCreate` + - `eventUpdate` + - `eventDelete` + - `threadCreate` + - `threadUpdate` + - `threadDelete` + - `autoModRuleCreate` + - `autoModRuleUpdate` + - `autoModRuleDelete` + - `autoModMessageBlock` + - `autoModMessageFlag` + - `autoModUserTimeout` + ## 2.10.0 -- Adds support for member timeouts - - Adds `Member:timeoutFor` - - Adds `Member:timeoutUntil` - - Adds `Member:removeTimeout` - - Adds `Member.timedOut` - - Adds `Member.timedOutUntil` +- Added support for member timeouts + - Added `Member:timeoutFor` + - Added `Member:timeoutUntil` + - Added `Member:removeTimeout` + - Added `Member.timedOut` + - Added `Member.timedOutUntil` - Fixes a bug in trying to sleep where `retry_after` is `nil` on 429. - Fixes mention consistency in for edited reply messages diff --git a/LICENSE b/LICENSE index 31618900..a8862f7f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2022 SinisterRectus +Copyright (c) 2016-2023 SinisterRectus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/libs/client/Client.lua b/libs/client/Client.lua index a240b2f9..7fb7605d 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -315,14 +315,36 @@ local function getIntent(i, ...) return n end +--[=[ +@m getIntents +@t mem +@r number +@d Returns a number that represents the gateway intents enabled for this client. +]=] function Client:getIntents() return self._intents end +--[=[ +@m setIntents +@t mem +@p intents Intents-Resolvable +@r nothing +@d Sets the gateway intents that this client will use. The new value will not be +used internally until the client (re-)identifies. +]=] function Client:setIntents(intents) self._intents = tonumber(intents) or 0 end +--[=[ +@m enableIntents +@t mem +@p ... Intents-Resolvables +@r nothing +@d Enables individual gateway intents for this client. The new value will not be +used internally until the client (re-)identifies. +]=] function Client:enableIntents(...) for i = 1, select('#', ...) do local intent = getIntent(i, ...) @@ -330,6 +352,14 @@ function Client:enableIntents(...) end end +--[=[ +@m disableIntents +@t mem +@p ... Intents-Resolvables +@r nothing +@d Disables individual gateway intents for this client. The new value will not be +used internally until the client (re-)identifies. +]=] function Client:disableIntents(...) for i = 1, select('#', ...) do local intent = getIntent(i, ...) @@ -337,12 +367,26 @@ function Client:disableIntents(...) end end +--[=[ +@m enableAllIntents +@t mem +@r nothing +@d Enables all known gateway intents for this client. The new value will not be +used internally until the client (re-)identifies. +]=] function Client:enableAllIntents() for _, value in pairs(gatewayIntent) do self._intents = bor(self._intents, value) end end +--[=[ +@m disableAllIntents +@t mem +@r nothing +@d Disables all gateway intents for this client. The new value will not be +used internally until the client (re-)identifies. +]=] function Client:disableAllIntents() self._intents = 0 end diff --git a/libs/constants.lua b/libs/constants.lua index 48728c08..5cd69e85 100644 --- a/libs/constants.lua +++ b/libs/constants.lua @@ -3,7 +3,7 @@ return { ID_DELAY = 5000, -- milliseconds GATEWAY_DELAY = 500, -- milliseconds, DISCORD_EPOCH = 1420070400000, -- milliseconds - API_VERSION = 7, + API_VERSION = 8, DEFAULT_AVATARS = 5, ZWSP = '\226\128\139', NS_PER_US = 1000, diff --git a/package.lua b/package.lua index da390cdd..e451d710 100644 --- a/package.lua +++ b/package.lua @@ -1,6 +1,6 @@ --[[The MIT License (MIT) -Copyright (c) 2016-2022 SinisterRectus +Copyright (c) 2016-2023 SinisterRectus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ SOFTWARE.]] return { name = 'SinisterRectus/discordia', - version = '2.10.0-1', + version = '2.11.0', homepage = 'https://github.com/SinisterRectus/Discordia', dependencies = { 'creationix/coro-http@3.1.0', From 940339639a1593d3815b1fd43dd65a87ec5f475b Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sat, 21 Jan 2023 12:43:23 -0500 Subject: [PATCH 09/22] Fixes missing direct message channels on message events --- libs/client/EventHandler.lua | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/libs/client/EventHandler.lua b/libs/client/EventHandler.lua index f9e9b42c..d70e2999 100644 --- a/libs/client/EventHandler.lua +++ b/libs/client/EventHandler.lua @@ -24,13 +24,19 @@ local function checkReady(shard) return client:emit('ready') end -local function getChannel(client, id) - local guild = client._channel_map[id] - if guild then - return guild._text_channels:get(id) - else - return client._private_channels:get(id) or client._group_channels:get(id) +local function getChannel(client, d) + local channel = client:getChannel(d.channel_id) + if not channel and not d.guild_id then + channel = client._api:getChannel(d.channel_id) + if channel then + if channel.type == channelType.private then + channel = client._private_channels:_insert(channel) + elseif channel.type == channelType.group then + channel = client._group_channels:_insert(channel) + end + end end + return channel end local EventHandler = setmetatable({}, {__index = function(self, k) @@ -315,14 +321,14 @@ function EventHandler.GUILD_ROLE_DELETE(d, client) -- role object not provided end function EventHandler.MESSAGE_CREATE(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_CREATE') end local message = channel._messages:_insert(d) return client:emit('messageCreate', message) end function EventHandler.MESSAGE_UPDATE(d, client) -- may not contain the whole message - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_UPDATE') end local message = channel._messages:get(d.id) if message then @@ -335,7 +341,7 @@ function EventHandler.MESSAGE_UPDATE(d, client) -- may not contain the whole mes end function EventHandler.MESSAGE_DELETE(d, client) -- message object not provided - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_DELETE') end local message = channel._messages:_delete(d.id) if message then @@ -346,7 +352,7 @@ function EventHandler.MESSAGE_DELETE(d, client) -- message object not provided end function EventHandler.MESSAGE_DELETE_BULK(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_DELETE_BULK') end for _, id in ipairs(d.ids) do local message = channel._messages:_delete(id) @@ -359,7 +365,7 @@ function EventHandler.MESSAGE_DELETE_BULK(d, client) end function EventHandler.MESSAGE_REACTION_ADD(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_REACTION_ADD') end local message = channel._messages:get(d.message_id) if message then @@ -372,7 +378,7 @@ function EventHandler.MESSAGE_REACTION_ADD(d, client) end function EventHandler.MESSAGE_REACTION_REMOVE(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_REACTION_REMOVE') end local message = channel._messages:get(d.message_id) if message then @@ -389,7 +395,7 @@ function EventHandler.MESSAGE_REACTION_REMOVE(d, client) end function EventHandler.MESSAGE_REACTION_REMOVE_ALL(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'MESSAGE_REACTION_REMOVE_ALL') end local message = channel._messages:get(d.message_id) if message then @@ -407,7 +413,7 @@ function EventHandler.MESSAGE_REACTION_REMOVE_ALL(d, client) end function EventHandler.CHANNEL_PINS_UPDATE(d, client) - local channel = getChannel(client, d.channel_id) + local channel = getChannel(client, d) if not channel then return warning(client, 'TextChannel', d.channel_id, 'CHANNEL_PINS_UPDATE') end return client:emit('pinsUpdate', channel) end From 397dce095d30e00887f89158ac467091eb0221b2 Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sun, 22 Jan 2023 11:31:43 -0500 Subject: [PATCH 10/22] Bump to version 2.11.1 --- CHANGELOG.md | 3 +++ package.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c64b50..8f17367c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 2.11.1 +- Fixes missing direct message channels on message events + ## 2.11.0 - Bumped the internal Discord API version to 8. - Added support for gateway intents: diff --git a/package.lua b/package.lua index e451d710..a300cf90 100644 --- a/package.lua +++ b/package.lua @@ -22,7 +22,7 @@ SOFTWARE.]] return { name = 'SinisterRectus/discordia', - version = '2.11.0', + version = '2.11.1', homepage = 'https://github.com/SinisterRectus/Discordia', dependencies = { 'creationix/coro-http@3.1.0', From 8183e21685539899909272b544d4d229df9f4b25 Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sat, 28 Jan 2023 21:05:40 -0500 Subject: [PATCH 11/22] Fixes missing message cache bug --- libs/client/EventHandler.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/client/EventHandler.lua b/libs/client/EventHandler.lua index d70e2999..677cf170 100644 --- a/libs/client/EventHandler.lua +++ b/libs/client/EventHandler.lua @@ -36,7 +36,7 @@ local function getChannel(client, d) end end end - return channel + return channel and channel._messages and channel end local EventHandler = setmetatable({}, {__index = function(self, k) From 899a8d45bb8cdeed73656c786a7bd79179def79e Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Fri, 3 Feb 2023 11:48:27 -0500 Subject: [PATCH 12/22] Bump to version 2.11.2 --- CHANGELOG.md | 3 +++ package.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f17367c..d0af6984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 2.11.2 +- Fixes a crash when messages are received in voice channels + ## 2.11.1 - Fixes missing direct message channels on message events diff --git a/package.lua b/package.lua index a300cf90..6c2899cb 100644 --- a/package.lua +++ b/package.lua @@ -22,7 +22,7 @@ SOFTWARE.]] return { name = 'SinisterRectus/discordia', - version = '2.11.1', + version = '2.11.2', homepage = 'https://github.com/SinisterRectus/Discordia', dependencies = { 'creationix/coro-http@3.1.0', From e3552057158e2c578f30b669394eb26294ea8daf Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sat, 10 Jun 2023 08:05:43 -0400 Subject: [PATCH 13/22] Adds support for unique and global usernames --- libs/containers/Member.lua | 4 ++-- libs/containers/User.lua | 29 ++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index 0208a5a3..80c71faf 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -531,9 +531,9 @@ function get.roles(self) end --[=[@p name string If the member has a nickname, then this will be equivalent to that nickname. -Otherwise, this is equivalent to `Member.user.username`.]=] +Otherwise, this is equivalent to `Member.user.name`.]=] function get.name(self) - return self._nick or self._user._username + return self._nick or self._user.name end --[=[@p nickname string/nil The member's nickname, if one is set.]=] diff --git a/libs/containers/User.lua b/libs/containers/User.lua index 81d55097..f4da0ea8 100644 --- a/libs/containers/User.lua +++ b/libs/containers/User.lua @@ -117,9 +117,9 @@ function get.bot(self) return self._bot or false end ---[=[@p name string Equivalent to `User.username`.]=] +--[=[@p name string Equivalent to `Used.globalName or User.username`.]=] function get.name(self) - return self._username + return self._global_name or self._username end --[=[@p username string The name of the user. This should be between 2 and 32 characters in length.]=] @@ -127,20 +127,35 @@ function get.username(self) return self._username end ---[=[@p discriminator number The discriminator of the user. This is a 4-digit string that is used to -discriminate the user from other users with the same username.]=] +--[=[@p globalName string/nil The global display name of the user. +If set, this has priority over the a username in displays, but not over a guild nickname.]=] +function get.globalName(self) + return self._global_name +end + +--[=[@p discriminator number The discriminator of the user. This is a string that is used to +discriminate the user from other users with the same username. Note that this will be "0" +for users with unique usernames.]=] function get.discriminator(self) return self._discriminator end ---[=[@p tag string The user's username and discriminator concatenated by an `#`.]=] +--[=[@p tag string The user's username if unique or username and discriminator concatenated by an `#`.]=] function get.tag(self) - return self._username .. '#' .. self._discriminator + if self._discriminator == "0" then + return self._username + else + return self._username .. '#' .. self._discriminator + end end function get.fullname(self) self.client:_deprecated(self.__name, 'fullname', 'tag') - return self._username .. '#' .. self._discriminator + if self._discriminator == "0" then + return self._username + else + return self._username .. '#' .. self._discriminator + end end --[=[@p avatar string/nil The hash for the user's custom avatar, if one is set.]=] From 3637e93e5f5c0499dceebca4f999fd38a9d1309a Mon Sep 17 00:00:00 2001 From: Tanoshii <79271690+Ta-noshii@users.noreply.github.com> Date: Mon, 12 Jun 2023 01:58:49 +0200 Subject: [PATCH 14/22] Fix typo in new username support update (#391) --- libs/containers/User.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/containers/User.lua b/libs/containers/User.lua index f4da0ea8..d1675746 100644 --- a/libs/containers/User.lua +++ b/libs/containers/User.lua @@ -117,7 +117,7 @@ function get.bot(self) return self._bot or false end ---[=[@p name string Equivalent to `Used.globalName or User.username`.]=] +--[=[@p name string Equivalent to `User.globalName or User.username`.]=] function get.name(self) return self._global_name or self._username end From 1d66402c35b2ad847f17029332a98d2607966b3c Mon Sep 17 00:00:00 2001 From: Bilal Bassam <38175840+Bilal2453@users.noreply.github.com> Date: Mon, 12 Jun 2023 03:00:17 +0300 Subject: [PATCH 15/22] PermissionOverwrite: use .type instead of ._type (#388) --- libs/containers/PermissionOverwrite.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/containers/PermissionOverwrite.lua b/libs/containers/PermissionOverwrite.lua index d2c0a8ff..238ee6ef 100644 --- a/libs/containers/PermissionOverwrite.lua +++ b/libs/containers/PermissionOverwrite.lua @@ -43,9 +43,9 @@ This may make an HTTP request if the object is not cached. ]=] function PermissionOverwrite:getObject() local guild = self._parent._parent - if self._type == 'role' then + if self.type == 'role' then return guild:getRole(self._id) - elseif self._type == 'member' then + elseif self.type == 'member' then return guild:getMember(self._id) end end From 85ea92db5c70adfa90aa0e997f1fd11b59cc0f7f Mon Sep 17 00:00:00 2001 From: Lort533 <76491869+Lort533@users.noreply.github.com> Date: Mon, 12 Jun 2023 02:02:50 +0200 Subject: [PATCH 16/22] IP Discovery update (#377) * IP Discovery update It seems to be working, prepared for change that will happen within a day from now. * Fix for likely port being added wrong It should be fine now. * Forgot one argument in string.pack It seems to make sense now * unpack fix for client_ip Thanks for pointing this out, @Bilal2453. * Code consistency changes Thanks again, @Bilal2453. --- libs/voice/VoiceSocket.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/voice/VoiceSocket.lua b/libs/voice/VoiceSocket.lua index 1bfbc599..257fa4cf 100644 --- a/libs/voice/VoiceSocket.lua +++ b/libs/voice/VoiceSocket.lua @@ -10,10 +10,9 @@ local format = string.format local setInterval, clearInterval = timer.setInterval, timer.clearInterval local wrap = coroutine.wrap local time = os.time -local unpack = string.unpack -- luacheck: ignore +local unpack, pack = string.unpack, string.pack -- luacheck: ignore local ENCRYPTION_MODE = 'xsalsa20_poly1305' -local PADDING = string.rep('\0', 70) local IDENTIFY = 0 local SELECT_PROTOCOL = 1 @@ -168,11 +167,12 @@ function VoiceSocket:handshake(server_ip, server_port) udp:recv_start(function(err, data) assert(not err, err) udp:recv_stop() - local client_ip = unpack('xxxxz', data) + local client_ip = unpack('xxxxxxxxz', data) local client_port = unpack('I2I2I4c64H', 0x1, 70, self._ssrc, self._ip, self._port) + return udp:send(packet, server_ip, server_port) end function VoiceSocket:selectProtocol(address, port) From fc135e521c5b75c697e8f6de71a3624d3d96e4d5 Mon Sep 17 00:00:00 2001 From: Tanoshii <79271690+Ta-noshii@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:26:44 +0200 Subject: [PATCH 17/22] Update Member.lua (#399) --- libs/containers/Member.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index 80c71faf..607770a5 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -352,6 +352,7 @@ end voice connection in the current guild. Due to complexities in voice state handling, the member's `voiceChannel` property will update asynchronously via WebSocket; not as a result of the HTTP request. +Not supplying an ID will result in the member being disconnected from the channel. ]=] function Member:setVoiceChannel(id) id = id and Resolver.channelId(id) From 036cb8cc0e5a3a5c564aefe59620960e4b2d358f Mon Sep 17 00:00:00 2001 From: RiskoZoSlovenska Date: Mon, 2 Oct 2023 14:28:00 -0400 Subject: [PATCH 18/22] Fix error in Member:getPermissions() (#397) --- libs/containers/Member.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/containers/Member.lua b/libs/containers/Member.lua index 607770a5..7d13024b 100644 --- a/libs/containers/Member.lua +++ b/libs/containers/Member.lua @@ -212,7 +212,7 @@ function Member:getPermissions(channel) ret = ret:union(everyone:getAllowedPermissions()) end - local allow, deny = 0, 0 + local allow, deny = Permissions(), Permissions() for role in self.roles:iter() do if role.id ~= guild.id then -- just in case local overwrite = overwrites:get(role.id) From 507c23c4d53a105adf950c4ed56bcdc57ac4cfe6 Mon Sep 17 00:00:00 2001 From: Tanoshii <79271690+Ta-noshii@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:29:03 +0200 Subject: [PATCH 19/22] Add new enums (#392) * Add new permissions * Add all new enums Note: #389 also has the new messageFlags, sorry for bundling pulls --- libs/enums.lua | 165 ++++++++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/libs/enums.lua b/libs/enums.lua index 1bce1f14..56600a00 100644 --- a/libs/enums.lua +++ b/libs/enums.lua @@ -71,32 +71,38 @@ enums.webhookType = enum { } enums.messageType = enum { - default = 0, - recipientAdd = 1, - recipientRemove = 2, - call = 3, - channelNameChange = 4, - channelIconchange = 5, - pinnedMessage = 6, - memberJoin = 7, - premiumGuildSubscription = 8, - premiumGuildSubscriptionTier1 = 9, - premiumGuildSubscriptionTier2 = 10, - premiumGuildSubscriptionTier3 = 11, - channelFollowAdd = 12, - -- unused (guildStream) = 13, - guildDiscoveryDisqualified = 14, - guildDiscoveryRequalified = 15, - guildDiscoveryInitialWarning = 16, - guildDiscoveryFinalWarning = 17, - threadCreated = 18, - reply = 19, - chatInputCommand = 20, - threadStarterMessage = 21, - guildInviteReminder = 22, - contextMenuCommand = 23, - autoModerationAction = 24, - roleSubscriptionPurchase = 25, + default = 0, + recipientAdd = 1, + recipientRemove = 2, + call = 3, + channelNameChange = 4, + channelIconchange = 5, + pinnedMessage = 6, + memberJoin = 7, + premiumGuildSubscription = 8, + premiumGuildSubscriptionTier1 = 9, + premiumGuildSubscriptionTier2 = 10, + premiumGuildSubscriptionTier3 = 11, + channelFollowAdd = 12, + -- unused (guildStream) = 13, + guildDiscoveryDisqualified = 14, + guildDiscoveryRequalified = 15, + guildDiscoveryInitialWarning = 16, + guildDiscoveryFinalWarning = 17, + threadCreated = 18, + reply = 19, + chatInputCommand = 20, + threadStarterMessage = 21, + guildInviteReminder = 22, + contextMenuCommand = 23, + autoModerationAction = 24, + roleSubscriptionPurchase = 25, + interactionPremiumUpsell = 26, + stageStart = 27, + stageEnd = 28, + stageSpeaker = 29, + stageTopic = 30, + applicationPremiumSubscription = 31, } enums.relationshipType = enum { @@ -105,6 +111,7 @@ enums.relationshipType = enum { blocked = 2, pendingIncoming = 3, pendingOutgoing = 4, + implicit = 5, } enums.activityType = enum { @@ -159,54 +166,70 @@ local function flag(n) end enums.permission = enum { - createInstantInvite = flag(0), - kickMembers = flag(1), - banMembers = flag(2), - administrator = flag(3), - manageChannels = flag(4), - manageGuild = flag(5), - addReactions = flag(6), - viewAuditLog = flag(7), - prioritySpeaker = flag(8), - stream = flag(9), - readMessages = flag(10), - sendMessages = flag(11), - sendTextToSpeech = flag(12), - manageMessages = flag(13), - embedLinks = flag(14), - attachFiles = flag(15), - readMessageHistory = flag(16), - mentionEveryone = flag(17), - useExternalEmojis = flag(18), - viewGuildInsights = flag(19), - connect = flag(20), - speak = flag(21), - muteMembers = flag(22), - deafenMembers = flag(23), - moveMembers = flag(24), - useVoiceActivity = flag(25), - changeNickname = flag(26), - manageNicknames = flag(27), - manageRoles = flag(28), - manageWebhooks = flag(29), - manageEmojis = flag(30), - useSlashCommands = flag(31), - requestToSpeak = flag(32), - manageEvents = flag(33), - manageThreads = flag(34), - usePublicThreads = flag(35), - usePrivateThreads = flag(36), + createInstantInvite = flag(0), + kickMembers = flag(1), + banMembers = flag(2), + administrator = flag(3), + manageChannels = flag(4), + manageGuild = flag(5), + addReactions = flag(6), + viewAuditLog = flag(7), + prioritySpeaker = flag(8), + stream = flag(9), + readMessages = flag(10), + sendMessages = flag(11), + sendTextToSpeech = flag(12), + manageMessages = flag(13), + embedLinks = flag(14), + attachFiles = flag(15), + readMessageHistory = flag(16), + mentionEveryone = flag(17), + useExternalEmojis = flag(18), + viewGuildInsights = flag(19), + connect = flag(20), + speak = flag(21), + muteMembers = flag(22), + deafenMembers = flag(23), + moveMembers = flag(24), + useVoiceActivity = flag(25), + changeNickname = flag(26), + manageNicknames = flag(27), + manageRoles = flag(28), + manageWebhooks = flag(29), + manageEmojis = flag(30), + useSlashCommands = flag(31), + requestToSpeak = flag(32), + manageEvents = flag(33), + manageThreads = flag(34), + usePublicThreads = flag(35), + usePrivateThreads = flag(36), + useExternalStickers = flag(37), + sendMessagesInThreads = flag(38), + useEmbeddedActivities = flag(39), + moderateMembers = flag(40), + monetizationAnalytics = flag(41), + useSoundboard = flag(42), + -- unused = flag(43), + -- unused = flag(44), + useExternalSounds = flag(45), + sendVoiceMessages = flag(46), } enums.messageFlag = enum { - crossposted = flag(0), - isCrosspost = flag(1), - suppressEmbeds = flag(2), - sourceMessageDeleted = flag(3), - urgent = flag(4), - hasThread = flag(5), - ephemeral = flag(6), - loading = flag(7), + crossposted = flag(0), + isCrosspost = flag(1), + suppressEmbeds = flag(2), + sourceMessageDeleted = flag(3), + urgent = flag(4), + hasThread = flag(5), + ephemeral = flag(6), + loading = flag(7), + threadFailedToMentionRoles = flag(8), + -- unused = flag(9), + -- unused = flag(10), + -- unused = flag(11), + suppressNotification = flag(12), + isVoiceMessage = flag(13), } enums.gatewayIntent = enum { From 85ce0cf9cdf174638295053f0673fa5aba167b6b Mon Sep 17 00:00:00 2001 From: Zan <69921455+InZan123@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:30:14 +0200 Subject: [PATCH 20/22] Made "embeds" a valid field for Message:update (#378) * "embeds" as valid field for Message:update allows for editing multiple embeds on a message * dirty fix for custom allowed_mentions * Revert "dirty fix for custom allowed_mentions" This reverts commit 6881a961c18920ac7488570e486b4363199cef01. --- libs/containers/Message.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/containers/Message.lua b/libs/containers/Message.lua index 61434771..b0b228db 100644 --- a/libs/containers/Message.lua +++ b/libs/containers/Message.lua @@ -248,7 +248,7 @@ end @p data table @r boolean @d Sets multiple properties of the message at the same time using a table similar -to the one supported by `TextChannel.send`, except only `content` and `embed` +to the one supported by `TextChannel.send`, except only `content` and `embed(s)` are valid fields; `mention(s)`, `file(s)`, etc are not supported. The message must be authored by the current user. (ie: you cannot change the embed of messages sent by other users). @@ -257,6 +257,7 @@ function Message:update(data) return self:_modify({ content = data.content or null, embed = data.embed or null, + embeds = data.embeds or null, allowed_mentions = { parse = {'users', 'roles', 'everyone'}, replied_user = not not self._reply_target, From 9465cb7df8c77fc60c846233c57126c80c98ba90 Mon Sep 17 00:00:00 2001 From: Tanoshii <79271690+Ta-noshii@users.noreply.github.com> Date: Sun, 19 Nov 2023 18:30:05 +0100 Subject: [PATCH 21/22] Add support for stickers (#389) * Update Message.lua * Stickers feature * (enums.lua) Update messageflags * Add files via upload * feat(API.lua, Client.lua, Guild.lua, Message.lua, Sticker.lua, TextChannel.lua, endpoints.lua): add support for Discord stickers This commit adds support for Discord stickers to the Discord API. The following changes were made: - Added new functions to the API.lua file to create, get, modify, and delete stickers in a guild. - Added a new _sticker_map field to the Client.lua file to store a cache of all stickers in a guild. - Added a new _stickers field to the Guild.lua file to store an iterable cache of all stickers in a guild. - Added a new sticker_items field to the Message.lua file to store an iterable array of all stickers sent in a message. - Added new functions to the Message.lua file to get the first sticker sent in a message and an iterable array of all stickers sent in a message. - Added a new Sticker.lua file to represent a sticker object. - Added new fields and functions feat(enums.lua): add new messageFlag values to improve message handling and notifications * Committing local changes before merging * Undo the allowed_mentions support and fix accident in enums * Undo the allowed_mentions support * Undo the allowed_mentions support * Im sorry for that, i have untreated brain damage * Change sticker_items to stickers --------- Co-authored-by: SinisterRectus --- libs/client/API.lua | 25 +++++ libs/client/Client.lua | 16 +++ libs/client/Resolver.lua | 14 +++ libs/containers/Guild.lua | 42 ++++++++ libs/containers/Message.lua | 30 +++++- libs/containers/Sticker.lua | 119 +++++++++++++++++++++++ libs/containers/abstract/TextChannel.lua | 7 ++ libs/endpoints.lua | 2 + 8 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 libs/containers/Sticker.lua diff --git a/libs/client/API.lua b/libs/client/API.lua index ebc6d3ca..fab83f12 100644 --- a/libs/client/API.lua +++ b/libs/client/API.lua @@ -395,6 +395,31 @@ function API:deleteGuildEmoji(guild_id, emoji_id) -- Emoji:delete return self:request("DELETE", endpoint) end +function API:createGuildSticker(guild_id, payload) -- Guild:createSticker + local endpoint = f(endpoints.GUILD_STICKERS, guild_id) + return self:request("POST", endpoint, payload, nil, {{ "sticker.png", payload.image}}) +end + +function API:getGuildStickers(guild_id) -- not exposed, use cache + local endpoint = f(endpoints.GUILD_STICKERS, guild_id) + return self:request("GET", endpoint) +end + +function API:getGuildSticker(guild_id, sticker_id) -- Guild:getSticker + local endpoint = f(endpoints.GUILD_STICKER, guild_id, sticker_id) + return self:request("GET", endpoint) +end + +function API:modifyGuildSticker(guild_id, sticker_id, payload) -- Sticker:_modify + local endpoint = f(endpoints.GUILD_STICKER, guild_id, sticker_id) + return self:request("PATCH", endpoint, payload) +end + +function API:deleteGuildSticker(guild_id, sticker_id) -- Sticker:delete + local endpoint = f(endpoints.GUILD_STICKER, guild_id, sticker_id) + return self:request("DELETE", endpoint) +end + function API:createGuild(payload) -- Client:createGuild local endpoint = endpoints.GUILDS return self:request("POST", endpoint, payload) diff --git a/libs/client/Client.lua b/libs/client/Client.lua index 7fb7605d..77f3a8d1 100644 --- a/libs/client/Client.lua +++ b/libs/client/Client.lua @@ -119,6 +119,7 @@ function Client:__init(options) self._voice = VoiceManager(self) self._role_map = {} self._emoji_map = {} + self._sticker_map = {} self._channel_map = {} self._events = require('client/EventHandler') self._intents = options.gatewayIntents @@ -378,6 +379,7 @@ function Client:enableAllIntents() for _, value in pairs(gatewayIntent) do self._intents = bor(self._intents, value) end + return self end --[=[ @@ -585,6 +587,20 @@ function Client:getEmoji(id) return guild and guild._emojis:get(id) end +--[=[ +@m getSticker +@t mem +@p id Sticker-ID-Resolvable +@r Sticker +@d Gets a sticker object by ID. The current user must be in the sticker's guild +and the client must be running the appropriate shard that serves the sticker's guild. +]=] +function Client:getSticker(id) + id = Resolver.stickerId(id) + local guild = self._sticker_map[id] + return guild and guild._stickers:get(id) +end + --[=[ @m listVoiceRegions @t http diff --git a/libs/client/Resolver.lua b/libs/client/Resolver.lua index c4d85e37..efe9544e 100644 --- a/libs/client/Resolver.lua +++ b/libs/client/Resolver.lua @@ -86,6 +86,13 @@ function Resolver.emojiId(obj) return int(obj) end +function Resolver.stickerId(obj) + if isInstance(obj, classes.Sticker) then + return obj.id + end + return int(obj) +end + function Resolver.guildId(obj) if isInstance(obj, classes.Guild) then return obj.id @@ -139,6 +146,13 @@ function Resolver.emoji(obj) return tostring(obj) end +function Resolver.sticker(obj) + if isInstance(obj, classes.Sticker) then + return obj.hash + end + return tostring(obj) +end + function Resolver.color(obj) if isInstance(obj, classes.Color) then return obj.value diff --git a/libs/containers/Guild.lua b/libs/containers/Guild.lua index f3d68c8e..a719c37b 100644 --- a/libs/containers/Guild.lua +++ b/libs/containers/Guild.lua @@ -7,6 +7,7 @@ channels, and roles that represents one community. local Cache = require('iterables/Cache') local Role = require('containers/Role') local Emoji = require('containers/Emoji') +local Sticker = require('containers/Sticker') local Invite = require('containers/Invite') local Webhook = require('containers/Webhook') local Ban = require('containers/Ban') @@ -31,6 +32,7 @@ function Guild:__init(data, parent) Snowflake.__init(self, data, parent) self._roles = Cache({}, Role, self) self._emojis = Cache({}, Emoji, self) + self._stickers = Cache({}, Sticker, self) self._members = Cache({}, Member, self) self._text_channels = Cache({}, GuildTextChannel, self) self._voice_channels = Cache({}, GuildVoiceChannel, self) @@ -56,6 +58,7 @@ function Guild:_makeAvailable(data) self._roles:_load(data.roles) self._emojis:_load(data.emojis) + self._stickers:_load(data.stickers) self:_loadMore(data) if not data.channels then return end -- incomplete guild @@ -195,6 +198,18 @@ function Guild:getEmoji(id) return self._emojis:get(id) end +--[=[ +@m getSticker +@t mem +@p id Sticker-ID-Resolvable +@r Sticker +@d Gets a sticker object by ID. +]=] +function Guild:getSticker(id) + id = Resolver.stickerId(id) + return self._stickers:get(id) +end + --[=[ @m getChannel @t mem @@ -294,6 +309,28 @@ function Guild:createEmoji(name, image) end end +--[=[ +@m createSticker +@t http +@p name string +@p description string +@p tags string +@p file Base64-Resolvable +@r Sticker +@d Creates a new sticker in this guild. The name must be between 2 and 30 characters. The description +must be between 2 and 100 characters, and the tags must be between 2 and 200 characters. The file must +be a PNG, APNG, or LOTTIE file, and must be under 500kb and 320x320 pixels. +]=] +function Guild:createSticker(name, description, tags, file) + file = Resolver.base64(file) + local data, err = self.client._api:createGuildSticker(self._id, {name = name, description = description, tags = tags, file = file}) + if data then + return self._stickers:_insert(data) + else + return nil, err + end +end + --[=[ @m setName @t http @@ -892,6 +929,11 @@ function get.emojis(self) return self._emojis end +--[=[@p stickers Cache An iterable cache of all stickers that exist in this guild.]=] +function get.stickers(self) + return self._stickers +end + --[=[@p members Cache An iterable cache of all members that exist in this guild and have been already loaded. If the `cacheAllMembers` client option (and the `syncGuilds` option for user-accounts) is enabled on start-up, then all members will be diff --git a/libs/containers/Message.lua b/libs/containers/Message.lua index b0b228db..c85e5298 100644 --- a/libs/containers/Message.lua +++ b/libs/containers/Message.lua @@ -102,6 +102,13 @@ function Message:_loadMore(data) self._attachments = #data.attachments > 0 and data.attachments or nil end + if data.sticker_items then + self._sticker_items = #data.sticker_items > 0 and data.sticker_items or nil + end + if data.sticker_items then + self._sticker_items = #data.sticker_items > 0 and data.sticker_items or nil + end + end function Message:_addReaction(d) @@ -432,7 +439,7 @@ function get.mentionedEmojis(self) local mentions = parseMentions(self._content, '') self._mentioned_emojis = ArrayIterable(mentions, function(id) local guild = client._emoji_map[id] - return guild and guild._emojis:get(id) + return guild and guild._emojis:get(id) or nil end) end return self._mentioned_emojis @@ -456,6 +463,27 @@ function get.mentionedChannels(self) return self._mentioned_channels end +--[=[@p Sticker ArrayIterable An iterable array of all stickers that are sent in this message.]=] +function get.stickers(self) + if not self._stickers then + local client = self.client + self._stickers = ArrayIterable(self._sticker_items, function(sticker) + if sticker.format_type == 1 then + local guild = client._sticker_map[sticker.id] + return guild and guild._stickers:get(sticker.id) or nil + else + -- return client:getSticker(sticker.id) ?? + end + end) + end + return self._stickers +end + +--[=[@p Sticker The first sticker that is sent in this message.]=] +function get.sticker(self) + return self.stickers and self.stickers.first or nil +end + local usersMeta = {__index = function(_, k) return '@' .. k end} local rolesMeta = {__index = function(_, k) return '@' .. k end} local channelsMeta = {__index = function(_, k) return '#' .. k end} diff --git a/libs/containers/Sticker.lua b/libs/containers/Sticker.lua new file mode 100644 index 00000000..bd869a2c --- /dev/null +++ b/libs/containers/Sticker.lua @@ -0,0 +1,119 @@ +--[=[ +@c Sticker x Snowflake +@d Represents a sticker object. +]=] + +local Snowflake = require('containers/abstract/Snowflake') +local json = require('json') + +local format = string.format + +local Sticker, get = require('class')('Sticker', Snowflake) + +function Sticker:__init(data, parent) + Snowflake.__init(self, data, parent) + self.client._sticker_map[self._id] = parent + return self:_loadMore(data) +end + +function Sticker:_load(data) + Snowflake._load(self, data) + return self:_loadMore(data) +end + +function Sticker:_loadMore(data) + +end + +function Sticker:_modify(payload) + local data, err = self.client._api:modifyGuildSticker(self._parent._id, self._id, payload) + if data then + self:_load(data) + return true + else + return false, err + end +end + +--[=[ +@m setName +@t http +@p name string +@r boolean +@d Sets the stickers's name. The name must be between 2 and 30 characters in length. +]=] +function Sticker:setName(name) + return self:_modify({name = name or json.null}) +end + +--[=[ +@m setDescription +@t http +@p description string +@r boolean +@d Sets the stickers's description. The description must be between 2 and 30 characters in length. +]=] +function Sticker:setDescription(description) + return self:_modify({description = description or json.null}) +end + +--[=[ +@m setTags +@t http +@p tags string +@r boolean +@d Sets the stickers's tags. The tags can only be up to 200 characters long. +]=] +function Sticker:setTags(tags) + return self:_modify({tags = tags or json.null}) +end + +--[=[ +@m delete +@t http +@r boolean +@d Permanently deletes the sticker. This cannot be undone! +]=] +function Sticker:delete() + local data, err = self.client._api:deleteGuildSticker(self._parent._id, self._id) + if data then + local cache = self._parent._stickers + if cache then + cache:_delete(self._id) + end + return true + else + return false, err + end +end + +--[=[@p name string The name of the sticker.]=] +function get.name(self) + return self._name +end + +--[=[@p description string The description of the sticker.]=] +function get.description(self) + return self._description +end + +--[=[@p tags string The tags of the sticker.]=] +function get.tags(self) + return self._tags +end + +function get.type(self) + return self._format_type +end + +--[=[@p guild Guild The guild in which the sticker exists.]=] +function get.guild(self) + return self._parent +end + +--[=[@p url string The URL that can be used to view a full version of the sticker.]=] +function get.url(self) + return format('https://cdn.discordapp.com/stickers/%s.png', self._id) +end + +return Sticker \ No newline at end of file diff --git a/libs/containers/abstract/TextChannel.lua b/libs/containers/abstract/TextChannel.lua index 709e978c..6fab045e 100644 --- a/libs/containers/abstract/TextChannel.lua +++ b/libs/containers/abstract/TextChannel.lua @@ -312,6 +312,11 @@ function TextChannel:send(content) } end + local sticker + if tbl.sticker then + sticker = {Resolver.stickerId(tbl.sticker)} + end + data, err = self.client._api:createMessage(self._id, { content = content, tts = tbl.tts, @@ -319,6 +324,8 @@ function TextChannel:send(content) embeds = embeds, message_reference = refMessage, allowed_mentions = refMention, + sticker_ids = sticker, + flags = tbl.silent and 2^12 or nil, }, files) else diff --git a/libs/endpoints.lua b/libs/endpoints.lua index e8939804..cbcab641 100644 --- a/libs/endpoints.lua +++ b/libs/endpoints.lua @@ -25,6 +25,8 @@ return { GUILD_EMBED = "/guilds/%s/embed", GUILD_EMOJI = "/guilds/%s/emojis/%s", GUILD_EMOJIS = "/guilds/%s/emojis", + GUILD_STICKER = "/guilds/%s/stickers/%s", + GUILD_STICKERS = "/guilds/%s/stickers", GUILD_INTEGRATION = "/guilds/%s/integrations/%s", GUILD_INTEGRATIONS = "/guilds/%s/integrations", GUILD_INTEGRATION_SYNC = "/guilds/%s/integrations/%s/sync", From 82cd6b5f33842894848516cae174cabb578dff63 Mon Sep 17 00:00:00 2001 From: SinisterRectus Date: Sun, 19 Nov 2023 12:31:51 -0500 Subject: [PATCH 22/22] Bump to version 2.12.0 --- CHANGELOG.md | 15 +++++++++++++++ package.lua | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0af6984..0b524042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 2.12.0 +- Added support for stickers (@Ta-noshii) + - Added `Sticker` class + - Added `Client:getSticker` + - Added `Guild:getSticker` + - Added `Guild:createSticker` + - Added `Guild.stickers` + - Added `Message.sticker` + - Added `Message.stickers` +- Added support for unique and global usernames +- Added support for the raw `embeds` field in `Message:update` +- Fixed a bug in `Member:getPermissions` +- Fixed a bug in `PermissionOverwrite:getObject` +- Fixed a bug in voice connection server discovery + ## 2.11.2 - Fixes a crash when messages are received in voice channels diff --git a/package.lua b/package.lua index 6c2899cb..d382a5c9 100644 --- a/package.lua +++ b/package.lua @@ -22,7 +22,7 @@ SOFTWARE.]] return { name = 'SinisterRectus/discordia', - version = '2.11.2', + version = '2.12.0', homepage = 'https://github.com/SinisterRectus/Discordia', dependencies = { 'creationix/coro-http@3.1.0',