From cbc688ecfeb4cdf6eab8bccf4c7ae4fb6dd73689 Mon Sep 17 00:00:00 2001 From: TTtie Date: Tue, 30 May 2023 23:18:02 +0200 Subject: [PATCH 01/22] feat(Constants): add useExternalSounds permission (#76) --- index.d.ts | 5 +++-- lib/Constants.js | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1a657ec5..f982a286 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2333,12 +2333,13 @@ declare namespace Dysnomia { startEmbeddedActivities: 549755813888n; moderateMembers: 1099511627776n; viewCreatorMonetizationAnalytics: 2199023255552n; + useExternalSounds: 35184372088832n; useSoundboard: 4398046511104n; sendVoiceMessages: 70368744177664n; allGuild: 3309205717182n; allText: 70904273435729n; - allVoice: 4952431789841n; - all: 79164837199871n; + allVoice: 40136803878673n; + all: 114349209288703n; }; PremiumTiers: { NONE: 0; diff --git a/lib/Constants.js b/lib/Constants.js index 1747a849..5cfc9be2 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -505,6 +505,7 @@ const Permissions = { moderateMembers: 1n << 40n, viewCreatorMonetizationAnalytics: 1n << 41n, useSoundboard: 1n << 42n, + useExternalSounds: 1n << 45n, sendVoiceMessages: 1n << 46n }; Permissions.allGuild = Permissions.kickMembers @@ -557,6 +558,7 @@ Permissions.allVoice = Permissions.createInstantInvite | Permissions.manageRoles | Permissions.voiceRequestToSpeak | Permissions.startEmbeddedActivities + | Permissions.useExternalSounds | Permissions.useSoundboard; Permissions.all = Permissions.allGuild | Permissions.allText | Permissions.allVoice; module.exports.Permissions = Permissions; From 4dc7dfbda4bcd758545fca86c637a7252f218ff5 Mon Sep 17 00:00:00 2001 From: TTtie Date: Sun, 18 Jun 2023 12:47:16 +0200 Subject: [PATCH 02/22] feat: unique username system support (#70) * initial unique username system support * fix up wrong ordering * add a newline between new member getter * migrated users have 6 default avatars now ref: https://github.com/discord/discord-api-docs/pull/6218#discussion_r1221908900 * emit old globalName in userUpdate * whoops: global_name -> globalName * copy note about single "0" discrim to Member.js --- index.d.ts | 9 ++++++++- lib/gateway/Shard.js | 14 +++++++++----- lib/structures/Member.js | 7 ++++++- lib/structures/User.js | 10 +++++++++- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index f982a286..f397cc9a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -874,7 +874,7 @@ declare namespace Dysnomia { | [channel: PrivateChannel | Uncached, user: User | Uncached, member: null]; unavailableGuildCreate: [guild: UnavailableGuild]; unknown: [packet: RawPacket, id?: number]; - userUpdate: [user: User, oldUser: PartialUser | null]; + userUpdate: [user: User, oldUser: OldUser | null]; voiceChannelJoin: [member: Member, channel: AnyVoiceChannel]; voiceChannelLeave: [member: Member, channel: AnyVoiceChannel]; voiceChannelSwitch: [member: Member, newChannel: AnyVoiceChannel, oldChannel: AnyVoiceChannel]; @@ -1382,6 +1382,12 @@ declare namespace Dysnomia { interface MemberRoles extends BaseData { roles: string[]; } + interface OldUser { + avatar: string | null; + discriminator: string; + globalName: string | null; + username: string; + } interface PartialUser { avatar: string | null; avatar_decoration: string | null; @@ -3970,6 +3976,7 @@ declare namespace Dysnomia { defaultAvatar: string; defaultAvatarURL: string; discriminator: string; + globalName: string | null; id: string; mention: string; publicFlags?: number; diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 401ac6ad..c0b9db1b 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -637,11 +637,12 @@ class Shard extends EventEmitter { if(packet.d.user.username !== undefined) { let user = this.client.users.get(packet.d.user.id); let oldUser = null; - if(user && (user.username !== packet.d.user.username || user.discriminator !== packet.d.user.discriminator || user.avatar !== packet.d.user.avatar)) { + if(user && (user.username !== packet.d.user.username || user.discriminator !== packet.d.user.discriminator || user.avatar !== packet.d.user.avatar || user.globalName !== packet.d.user.global_name)) { oldUser = { username: user.username, discriminator: user.discriminator, - avatar: user.avatar + avatar: user.avatar, + globalName: user.globalName }; } if(!user || oldUser) { @@ -654,6 +655,7 @@ class Shard extends EventEmitter { * @prop {String} oldUser.username The username of the user * @prop {String} oldUser.discriminator The discriminator of the user * @prop {String?} oldUser.avatar The hash of the user's avatar, or null if no avatar + * @prop {String?} oldUser.globalName The globally visible display name of the user */ this.emit("userUpdate", user, oldUser); } @@ -1111,11 +1113,12 @@ class Shard extends EventEmitter { if(!(this.client.shards.options.intents & Constants.Intents.guildPresences) && packet.d.user.username !== undefined) { let user = this.client.users.get(packet.d.user.id); let oldUser = null; - if(user && (user.username !== packet.d.user.username || user.discriminator !== packet.d.user.discriminator || user.avatar !== packet.d.user.avatar)) { + if(user && (user.username !== packet.d.user.username || user.discriminator !== packet.d.user.discriminator || user.avatar !== packet.d.user.avatar || user.globalName !== packet.d.user.global_name)) { oldUser = { username: user.username, discriminator: user.discriminator, - avatar: user.avatar + avatar: user.avatar, + globalName: user.globalName }; } if(!user || oldUser) { @@ -1763,7 +1766,8 @@ class Shard extends EventEmitter { oldUser = { username: user.username, discriminator: user.discriminator, - avatar: user.avatar + avatar: user.avatar, + globalName: user.globalName }; } user = this.client.users.update(packet.d, this.client); diff --git a/lib/structures/Member.js b/lib/structures/Member.js index 21cfa53e..6e6612e2 100644 --- a/lib/structures/Member.js +++ b/lib/structures/Member.js @@ -22,12 +22,13 @@ const VoiceState = require("./VoiceState"); * @prop {Number} createdAt Timestamp of user creation * @prop {String} defaultAvatar The hash for the default avatar of a user if there is no avatar set * @prop {String} defaultAvatarURL The URL of the user's default avatar -* @prop {String} discriminator The discriminator of the user +* @prop {String} discriminator The discriminator of the user - if a single zero digit ("0"), the user is using the unique username system * @prop {Number} flags The guild member flag bit set * @prop {Object?} game The active game the member is playing * @prop {String} game.name The name of the active game * @prop {Number} game.type The type of the active game (0 is default, 1 is Twitch, 2 is YouTube) * @prop {String?} game.url The url of the active game +* @prop {String?} globalName The globally visible display name of the user * @prop {Guild} guild The guild the member is in * @prop {String} id The ID of the member * @prop {Number?} joinedAt Timestamp of when the member joined the guild @@ -159,6 +160,10 @@ class Member extends Base { return this.user.discriminator; } + get globalName() { + return this.user.globalName; + } + get mention() { return `<@!${this.id}>`; } diff --git a/lib/structures/User.js b/lib/structures/User.js index 3fee5570..c093b5b1 100644 --- a/lib/structures/User.js +++ b/lib/structures/User.js @@ -14,8 +14,9 @@ const Endpoints = require("../rest/Endpoints"); * @prop {Number} createdAt Timestamp of the user's creation * @prop {String} defaultAvatar The hash for the default avatar of a user if there is no avatar set * @prop {String} defaultAvatarURL The URL of the user's default avatar -* @prop {String} discriminator The discriminator of the user +* @prop {String} discriminator The discriminator of the user - if a single zero digit ("0"), the user is using the unique username system * @prop {String} id The ID of the user +* @prop {String?} globalName The globally visible display name of the user * @prop {String} mention A string that mentions the user * @prop {Number?} publicFlags Publicly visible flags for this user * @prop {String} staticAvatarURL The URL of the user's avatar (always a JPG) @@ -53,6 +54,9 @@ class User extends Base { if(data.accent_color !== undefined) { this.accentColor = data.accent_color; } + if(data.global_name !== undefined) { + this.globalName = data.global_name; + } } get avatarURL() { @@ -73,6 +77,9 @@ class User extends Base { } get defaultAvatar() { + if(this.discriminator === "0") { + return Base.getDiscordEpoch(this.id) % 6; + } return this.discriminator % 5; } @@ -138,6 +145,7 @@ class User extends Base { "banner", "bot", "discriminator", + "globalName", "publicFlags", "system", "username", From 04c640a21d70c3663b4f13471d2fd8b9b84c209d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bekir=20Nazmi=20G=C3=B6rkem?= <69164892+nazmigorkem@users.noreply.github.com> Date: Sat, 1 Jul 2023 21:37:47 +0300 Subject: [PATCH 03/22] feat: add port option to rest options (#78) * added port option to rest options * Add docs for the new option --------- Co-authored-by: TTtie --- index.d.ts | 1 + lib/Client.js | 1 + lib/rest/RequestHandler.js | 1 + 3 files changed, 3 insertions(+) diff --git a/index.d.ts b/index.d.ts index f397cc9a..a662fc82 100644 --- a/index.d.ts +++ b/index.d.ts @@ -518,6 +518,7 @@ declare namespace Dysnomia { baseURL?: string; disableLatencyCompensation?: boolean; domain?: string; + port?: string; https?: boolean; latencyThreshold?: number; ratelimiterOffset?: number; diff --git a/lib/Client.js b/lib/Client.js index 26087da0..dc6ed693 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -104,6 +104,7 @@ class Client extends EventEmitter { * @arg {String} [options.rest.domain="discord.com"] The domain to use for API requests * @arg {Boolean} [options.rest.https=true] Whether to make requests to the Discord API over HTTPS (true) or HTTP (false) * @arg {Number} [options.rest.latencyThreshold=30000] The average request latency at which Dysnomia will start emitting latency errors + * @arg {Number} [options.rest.port] The port to use for API requests. Defaults to 443 (HTTPS) or 80 (HTTP) * @arg {Number} [options.rest.ratelimiterOffset=0] A number of milliseconds to offset the ratelimit timing calculations by * @arg {Number} [options.rest.requestTimeout=15000] A number of milliseconds before REST requests are considered timed out * @arg {Boolean} [options.restMode=false] Whether to enable getting objects over REST. Even with this option enabled, it is recommended that you check the cache first before using REST diff --git a/lib/rest/RequestHandler.js b/lib/rest/RequestHandler.js index 4d118f8b..f9c4b015 100644 --- a/lib/rest/RequestHandler.js +++ b/lib/rest/RequestHandler.js @@ -153,6 +153,7 @@ class RequestHandler { req = requester.request({ method: method, host: this.options.domain, + port: this.options.port, path: this.options.baseURL + finalURL, headers: headers, agent: this.options.agent From 580a22aad2286743674e0bebd366f1abde33a186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bekir=20Nazmi=20G=C3=B6rkem?= <69164892+nazmigorkem@users.noreply.github.com> Date: Sat, 8 Jul 2023 02:25:35 +0300 Subject: [PATCH 04/22] feat: add headers to REST options (#79) * headers option is added to REST options * fixed linting * fixed typing * changed the order of header assignment --- index.d.ts | 1 + lib/Client.js | 1 + lib/rest/RequestHandler.js | 3 +++ 3 files changed, 5 insertions(+) diff --git a/index.d.ts b/index.d.ts index a662fc82..9ff4908b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -519,6 +519,7 @@ declare namespace Dysnomia { disableLatencyCompensation?: boolean; domain?: string; port?: string; + headers?: Record; https?: boolean; latencyThreshold?: number; ratelimiterOffset?: number; diff --git a/lib/Client.js b/lib/Client.js index dc6ed693..e9009799 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -105,6 +105,7 @@ class Client extends EventEmitter { * @arg {Boolean} [options.rest.https=true] Whether to make requests to the Discord API over HTTPS (true) or HTTP (false) * @arg {Number} [options.rest.latencyThreshold=30000] The average request latency at which Dysnomia will start emitting latency errors * @arg {Number} [options.rest.port] The port to use for API requests. Defaults to 443 (HTTPS) or 80 (HTTP) + * @arg {Object} [options.rest.headers] Headers to be appended in REST requests * @arg {Number} [options.rest.ratelimiterOffset=0] A number of milliseconds to offset the ratelimit timing calculations by * @arg {Number} [options.rest.requestTimeout=15000] A number of milliseconds before REST requests are considered timed out * @arg {Boolean} [options.restMode=false] Whether to enable getting objects over REST. Even with this option enabled, it is recommended that you check the cache first before using REST diff --git a/lib/rest/RequestHandler.js b/lib/rest/RequestHandler.js index f9c4b015..3a2eaa84 100644 --- a/lib/rest/RequestHandler.js +++ b/lib/rest/RequestHandler.js @@ -82,6 +82,9 @@ class RequestHandler { let finalURL = url; try { + if(this.options.headers) { + Object.assign(headers, this.options.headers); + } if(auth) { headers.Authorization = this._client._token; } From 93acefbc36bdc7f0cd93035dc48a71b330280458 Mon Sep 17 00:00:00 2001 From: TTtie Date: Sat, 8 Jul 2023 01:47:33 +0200 Subject: [PATCH 05/22] types: RequestHandlerOptions#port should be a number (#80) * types: RequestHandlerOptions#port should be a number * correct sorting p comes before r --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 9ff4908b..deabcd2d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -518,10 +518,10 @@ declare namespace Dysnomia { baseURL?: string; disableLatencyCompensation?: boolean; domain?: string; - port?: string; headers?: Record; https?: boolean; latencyThreshold?: number; + port?: number; ratelimiterOffset?: number; requestTimeout?: number; } From e37ec7dfaa74446daec4adac24723339a9079083 Mon Sep 17 00:00:00 2001 From: Randall Date: Sun, 9 Jul 2023 11:03:01 -0400 Subject: [PATCH 06/22] docs(Client): remove missing options.maxShards option (#82) --- lib/Client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Client.js b/lib/Client.js index e9009799..d24d9489 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -94,7 +94,6 @@ class Client extends EventEmitter { * @arg {Number | String} [options.gateway.maxShards=1] The total number of shards you want to run. If "auto" Dysnomia will use Discord's recommended shard count. * @arg {Function} [options.gateway.reconnectDelay] A function which returns how long the bot should wait until reconnecting to Discord. * @arg {Boolean} [options.gateway.seedVoiceConnections=false] Whether to populate bot.voiceConnections with existing connections the bot account has during startup. Note that this will disconnect connections from other bot sessions - * @arg {Number | String} [options.maxShards=1] The total number of shards you want to run. If "auto" Dysnomia will use Discord's recommended shard count. This option has been moved under `options.gateway` * @arg {Number} [options.messageLimit=100] The maximum size of a channel message cache * @arg {Boolean} [options.opusOnly=false] Whether to suppress the Opus encoder not found error or not * @arg {Object} [options.rest] Options for the REST request handler From 97bfe9e085e87ad8fc18c4378cb428e2c47ad83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bekir=20Nazmi=20G=C3=B6rkem?= <69164892+nazmigorkem@users.noreply.github.com> Date: Mon, 10 Jul 2023 19:08:32 +0300 Subject: [PATCH 07/22] types(PartialEmoji): make `id` optional (#83) --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index deabcd2d..cb574ca5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -666,7 +666,7 @@ declare namespace Dysnomia { roles?: string[]; } interface PartialEmoji { - id: string | null; + id?: string; name: string; animated?: boolean; } From bd07fd593890828cf5c525fc616fb0e54a500de8 Mon Sep 17 00:00:00 2001 From: TTtie Date: Sat, 15 Jul 2023 01:48:00 +0200 Subject: [PATCH 08/22] feat: add `defaultForumLayout` to createChannel() (#84) --- index.d.ts | 2 +- lib/Client.js | 2 ++ lib/structures/Guild.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index cb574ca5..25917a35 100644 --- a/index.d.ts +++ b/index.d.ts @@ -366,6 +366,7 @@ declare namespace Dysnomia { availableTags?: (Required> & Partial)[]; bitrate?: number; defaultAutoArchiveDuration?: AutoArchiveDuration; + defaultForumLayout?: ForumLayoutTypes; defaultReactionEmoji?: ForumDefaultReactionEmoji | null; defaultSortOrder?: ThreadSortingOrders | null; nsfw?: boolean; @@ -383,7 +384,6 @@ declare namespace Dysnomia { archived?: boolean; appliedTags?: string[]; autoArchiveDuration?: AutoArchiveDuration; - defaultForumLayout?: ForumLayoutTypes; defaultThreadRateLimitPerUser?: number | null; flags?: number; invitable?: boolean; diff --git a/lib/Client.js b/lib/Client.js index d24d9489..45327bca 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -419,6 +419,7 @@ class Client extends EventEmitter { * @arg {Array} [options.availableTags] Available tags for a forum channel * @arg {Number} [options.bitrate] The bitrate of the channel (voice channels only) * @arg {Number} [options.defaultAutoArchiveDuration] The default duration of newly created threads in minutes to automatically archive the thread after inactivity (60, 1440, 4320, 10080) + * @arg {Number} [options.defaultForumLayout] The default forum layout view used to display forum posts * @arg {Object} [options.defaultReactionEmoji] The emoji to show as the reaction button (forum channels only) * @arg {Object} [options.defaultSortOrder] The default thread sorting order * @arg {Boolean} [options.nsfw] The nsfw status of the channel @@ -446,6 +447,7 @@ class Client extends EventEmitter { })), bitrate: options.bitrate, default_auto_archive_duration: options.defaultAutoArchiveDuration, + default_forum_layout: options.defaultForumLayout, default_reaction_emoji: options.defaultReactionEmoji && { emoji_id: options.defaultReactionEmoji.emojiID, emoji_name: options.defaultReactionEmoji.emojiName diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index 7030affd..6a0aa587 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -409,6 +409,7 @@ class Guild extends Base { * @arg {Array} [options.availableTags] Available tags for a forum channel * @arg {Number} [options.bitrate] The bitrate of the channel (voice channels only) * @arg {Number} [options.defaultAutoArchiveDuration] The default duration of newly created threads in minutes to automatically archive the thread after inactivity (60, 1440, 4320, 10080) + * @arg {Number} [options.defaultForumLayout] The default forum layout view used to display forum posts * @arg {Object} [options.defaultReactionEmoji] The emoji to show as the reaction button (forum channels only) * @arg {Object} [options.defaultSortOrder] The default thread sorting order * @arg {Boolean} [options.nsfw] The nsfw status of the channel From e260ed56674b334ba48d6d6f6c4efa7b43ae5f6c Mon Sep 17 00:00:00 2001 From: TTtie Date: Sat, 15 Jul 2023 02:20:37 +0200 Subject: [PATCH 09/22] feat: support role flags (#85) * feat: support role flags Ref: https://github.com/discord/discord-api-docs/commit/1a635825d1b9da5770eaaf1b06b5078746a61fe4 * lint, correct sorting * add role flags to guildRoleUpdate --- index.d.ts | 5 +++++ lib/Constants.js | 4 ++++ lib/gateway/Shard.js | 2 ++ lib/structures/Role.js | 6 +++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 25917a35..9de494b4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -767,6 +767,7 @@ declare namespace Dysnomia { } interface OldRole { color: number; + flags: number; hoist: boolean; icon: string | null; managed: boolean; @@ -2370,6 +2371,9 @@ declare namespace Dysnomia { BOOLEAN_EQUAL: 7; BOOLEAN_NOT_EQUAL: 8; }; + RoleFlags: { + IN_PROMPT: 1; + }; StageInstancePrivacyLevel: { /** @deprecated */ PUBLIC: 1; @@ -3685,6 +3689,7 @@ declare namespace Dysnomia { export class Role extends Base { color: number; createdAt: number; + flags: number; guild: Guild; hoist: boolean; icon: string | null; diff --git a/lib/Constants.js b/lib/Constants.js index 5cfc9be2..9788dc22 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -605,6 +605,10 @@ module.exports.RoleConnectionMetadataTypes = { BOOLEAN_NOT_EQUAL: 8 }; +module.exports.RoleFlags = { + IN_PROMPT: 1 << 0 +}; + module.exports.StageInstancePrivacyLevel = { PUBLIC: 1, // [DEPRECATED] GUILD_ONLY: 2 diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index c0b9db1b..cde46b2e 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -1390,6 +1390,7 @@ class Shard extends EventEmitter { } const oldRole = { color: role.color, + flags: role.flags, hoist: role.hoist, icon: role.icon, managed: role.managed, @@ -1407,6 +1408,7 @@ class Shard extends EventEmitter { * @prop {Role} role The updated role * @prop {Object} oldRole The old role data * @prop {Number} oldRole.color The hex color of the role in base 10 + * @prop {Number} oldRole.flags Role flags. See [Discord's documentation](https://discord.com/developers/docs/topics/permissions#role-object-role-flags) for a list of them * @prop {Boolean} oldRole.hoist Whether users with this role are hoisted in the user list or not * @prop {String?} oldRole.icon The hash of the role's icon, or null if no icon * @prop {Boolean} oldRole.managed Whether a guild integration manages this role or not diff --git a/lib/structures/Role.js b/lib/structures/Role.js index 512dab91..84395e2e 100644 --- a/lib/structures/Role.js +++ b/lib/structures/Role.js @@ -8,12 +8,13 @@ const Permission = require("./Permission"); * Represents a role * @prop {Number} color The hex color of the role in base 10 * @prop {Number} createdAt Timestamp of the role's creation +* @prop {Number} flags Role flags. See [Discord's documentation](https://discord.com/developers/docs/topics/permissions#role-object-role-flags) for a list of them +* @prop {Guild} guild The guild that owns the role * @prop {Boolean} hoist Whether users with this role are hoisted in the user list or not * @prop {String?} icon The hash of the role's icon, or null if no icon * @prop {String?} iconURL The URL of the role's icon * @prop {String} id The ID of the role * @prop {Object} json Generates a JSON representation of the role permissions -* @prop {Guild} guild The guild that owns the role * @prop {Boolean} managed Whether a guild integration manages this role or not * @prop {String} mention A string that mentions the role * @prop {Boolean} mentionable Whether the role is mentionable or not @@ -73,6 +74,9 @@ class Role extends Base { if(data.unicode_emoji !== undefined) { this.unicodeEmoji = data.unicode_emoji; } + if(data.flags !== undefined) { + this.flags = data.flags; + } } get iconURL() { From f66d8e6723a0abe886a257bde6fa5496201a04b4 Mon Sep 17 00:00:00 2001 From: TTtie Date: Sat, 15 Jul 2023 02:33:04 +0200 Subject: [PATCH 10/22] feat(Client): support `withCounts` parameter in getRESTGuilds() (#88) * feat(Client): support `with_counts` parameter in getRESTGuilds() * update the default fetch limit * the upper bound is unfortunately also 200 :( --- index.d.ts | 1 + lib/Client.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 9de494b4..fb6ba991 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1056,6 +1056,7 @@ declare namespace Dysnomia { after?: string; before?: string; limit?: number; + withCounts?: boolean; } interface GuildAuditLog { autoModerationRules: AutoModerationRule[]; diff --git a/lib/Client.js b/lib/Client.js index 45327bca..1b82847c 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -2813,7 +2813,8 @@ class Client extends EventEmitter { * @arg {Object} [options] Options for the request. * @arg {String} [options.after] The highest guild ID of the previous page * @arg {String} [options.before] The lowest guild ID of the next page - * @arg {Number} [options.limit=100] The max number of guilds to get (1 to 1000) + * @arg {Number} [options.limit=200] The max number of guilds to get (1 to 200) + * @arg {Boolean} [options.withCounts] Whether the guild objects will have approximateMemberCount and approximatePresenceCount * @returns {Promise>} */ getRESTGuilds(options = {}) { @@ -2821,6 +2822,7 @@ class Client extends EventEmitter { if(!this.options.restMode) { return Promise.reject(new Error("Dysnomia REST mode is not enabled")); } + options.with_counts = options.withCounts; return this.requestHandler.request("GET", Endpoints.USER_GUILDS("@me"), true, options).then((guilds) => guilds.map((guild) => new Guild(guild, this))); } From 20fc3a476b88f943ee5477cb7bbfc7406f3c940d Mon Sep 17 00:00:00 2001 From: TTtie Date: Wed, 19 Jul 2023 00:51:04 +0200 Subject: [PATCH 11/22] feat: support onboarding updates (#69) * feat: support onboarding updates * fix linting issues --- index.d.ts | 11 +++++++++++ lib/Client.js | 11 +++++++++++ lib/Constants.js | 5 +++++ lib/structures/Guild.js | 10 ++++++++++ 4 files changed, 37 insertions(+) diff --git a/index.d.ts b/index.d.ts index fb6ba991..6b6788b0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -117,6 +117,7 @@ declare namespace Dysnomia { type GuildScheduledEventPrivacyLevel = Constants["GuildScheduledEventPrivacyLevel"][keyof Constants["GuildScheduledEventPrivacyLevel"]]; type GuildScheduledEventStatus = Constants["GuildScheduledEventStatus"][keyof Constants["GuildScheduledEventStatus"]]; type NSFWLevel = Constants["GuildNSFWLevels"][keyof Constants["GuildNSFWLevels"]]; + type OnboardingModes = Constants["OnboardingModes"][keyof Constants["OnboardingModes"]]; type OnboardingPromptTypes = Constants["OnboardingPromptTypes"][keyof Constants["OnboardingPromptTypes"]]; type PossiblyUncachedGuild = Guild | Uncached; type PossiblyUncachedGuildScheduledEvent = GuildScheduledEvent | Uncached; @@ -1023,6 +1024,9 @@ declare namespace Dysnomia { level: MFALevel; reason?: string; } + interface EditGuildOnboardingOptions extends Partial> { + reason?: string; + } interface GetGuildAuditLogOptions { actionType?: number; after?: string; @@ -1076,6 +1080,7 @@ declare namespace Dysnomia { enabled: boolean; default_channel_ids: string[]; guild_id: string; + mode: OnboardingModes; prompts: GuildOnboardingPrompt[]; } interface GuildOnboardingPrompt { @@ -2291,6 +2296,10 @@ declare namespace Dysnomia { INVITED: 1; ACCEPTED: 2; }; + OnboardingModes: { + ONBOARDING_DEFAULT: 0; + ONBOARDING_ADVANCED: 1; + }; OnboardingPromptTypes: { MULTIPLE_CHOICE: 0; DROPDOWN: 1; @@ -2783,6 +2792,7 @@ declare namespace Dysnomia { editGuildIntegration(guildID: string, integrationID: string, options: IntegrationOptions): Promise; editGuildMember(guildID: string, memberID: string, options: MemberOptions, reason?: string): Promise; editGuildMFALevel(guildID: string, options: EditGuildMFALevelOptions): Promise; + editGuildOnboarding(guildID: string, options: EditGuildOnboardingOptions): Promise; editGuildScheduledEvent(guildID: string, eventID: string, event: GuildScheduledEventEditOptions, reason?: string): Promise>; editGuildSticker(guildID: string, stickerID: string, options?: EditStickerOptions, reason?: string): Promise; editGuildTemplate(guildID: string, code: string, options: GuildTemplateOptions): Promise; @@ -3207,6 +3217,7 @@ declare namespace Dysnomia { editIntegration(integrationID: string, options: IntegrationOptions): Promise; editMember(memberID: string, options: MemberOptions, reason?: string): Promise; editMFALevel(options: EditGuildMFALevelOptions): Promise; + editOnboarding(options: EditGuildOnboardingOptions): Promise; editRole(roleID: string, options: RoleOptions): Promise; editScheduledEvent(eventID: string, event: GuildScheduledEventEditOptions, reason?: string): Promise>; editSticker(stickerID: string, options?: EditStickerOptions, reason?: string): Promise; diff --git a/lib/Client.js b/lib/Client.js index 1b82847c..3f4ae902 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -1590,6 +1590,17 @@ class Client extends EventEmitter { return this.requestHandler.request("POST", Endpoints.GUILD_MFA_LEVEL(guildID), true, options).then((data) => data.level); } + /** + * Edits the onboarding flow of a guild, shown to new members + * @param {String} guildID The ID of the guild + * @param {Object} options The [guild onboarding](https://discord.com/developers/docs/resources/guild#guild-onboarding-object) object + * @param {String} [options.reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with the [guild onboarding object](https://discord.com/developers/docs/resources/guild#guild-onboarding-object) + */ + editGuildOnboarding(guildID, options) { + return this.requestHandler.request("PUT", Endpoints.GUILD_ONBOARDING(guildID), true, options); + } + /** * Edit a guild scheduled event * @arg {String} guildID The guild ID where the event will be edited diff --git a/lib/Constants.js b/lib/Constants.js index 9788dc22..dad62e2d 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -451,6 +451,11 @@ module.exports.MembershipState = { ACCEPTED: 2 }; +module.exports.OnboardingModes = { + ONBOARDING_DEFAULT: 0, + ONBOARDING_ADVANCED: 1 +}; + module.exports.OnboardingPromptTypes = { MULTIPLE_CHOICE: 0, DROPDOWN: 1 diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index 6a0aa587..c2ed76fc 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -796,6 +796,16 @@ class Guild extends Base { return this._client.editGuildMFALevel.call(this._client, this.id, options); } + /** + * Edits the onboarding flow of this guild, shown to new members + * @param {Object} options The [guild onboarding](https://discord.com/developers/docs/resources/guild#guild-onboarding-object) object + * @param {String} [options.reason] The reason to be displayed in audit logs + * @returns {Promise} Resolves with the [guild onboarding object](https://discord.com/developers/docs/resources/guild#guild-onboarding-object) + */ + editOnboarding(options) { + return this.#client.editGuildOnboarding.call(this.#client, this.id, options); + } + /** * Edit the guild role * @arg {String} roleID The ID of the role From 816c600467e371364a96b90dc5685d864dbcfb7f Mon Sep 17 00:00:00 2001 From: TTtie Date: Wed, 19 Jul 2023 00:53:49 +0200 Subject: [PATCH 12/22] feat: support attachment flags (#86) Ref: https://github.com/discord/discord-api-docs/commit/8530715b6d51e80713734f414896b4273a491c38 --- index.d.ts | 4 ++++ lib/Constants.js | 4 ++++ lib/structures/Attachment.js | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/index.d.ts b/index.d.ts index 6b6788b0..14a2132d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1934,6 +1934,9 @@ declare namespace Dysnomia { EMBEDDED_FIRST_PARTY: 1048576; APPLICATION_COMMAND_BADGE: 8388608; }; + AttachmentFlags: { + IS_REMIX: 4; + }; AuditLogActions: { GUILD_UPDATE: 1; @@ -2567,6 +2570,7 @@ declare namespace Dysnomia { durationSecs?: number; ephemeral?: boolean; filename: string; + flags?: number; height?: number; id: string; proxyURL: string; diff --git a/lib/Constants.js b/lib/Constants.js index dad62e2d..1c820b45 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -67,6 +67,10 @@ module.exports.ApplicationFlags = { APPLICATION_COMMAND_BADGE: 1 << 23 }; +module.exports.AttachmentFlags = { + IS_REMIX: 1 << 2 +}; + module.exports.AuditLogActions = { GUILD_UPDATE: 1, diff --git a/lib/structures/Attachment.js b/lib/structures/Attachment.js index 5fda4e02..61cf633b 100644 --- a/lib/structures/Attachment.js +++ b/lib/structures/Attachment.js @@ -9,6 +9,7 @@ const Base = require("./Base"); * @prop {Number?} durationSecs The duration of the audio file (voice messages only) * @prop {Boolean?} ephemeral Whether the attachment is ephemeral * @prop {String} filename The filename of the attachment + * @prop {Number?} flags Attachment flags. See [Discord's documentation](https://discord.com/developers/docs/resources/channel#attachment-object-attachment-flags) for a list of them * @prop {Number?} height The height of the attachment * @prop {String} id The attachment ID * @prop {String} proxyURL The proxy URL of the attachment @@ -46,6 +47,9 @@ class Attachment extends Base { if(data.ephemeral !== undefined) { this.ephemeral = data.ephemeral; } + if(data.flags !== undefined) { + this.flags = data.flags; + } } toJSON(props = []) { From 1f881560363d9193acbd8e69c77f098d1e77cd25 Mon Sep 17 00:00:00 2001 From: TTtie Date: Tue, 18 Jul 2023 22:56:31 +0000 Subject: [PATCH 13/22] fix: #client -> _client --- lib/structures/Guild.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index c2ed76fc..f7e2527e 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -803,7 +803,7 @@ class Guild extends Base { * @returns {Promise} Resolves with the [guild onboarding object](https://discord.com/developers/docs/resources/guild#guild-onboarding-object) */ editOnboarding(options) { - return this.#client.editGuildOnboarding.call(this.#client, this.id, options); + return this._client.editGuildOnboarding.call(this._client, this.id, options); } /** From 604a9ef357adadffcb25146bb596020a4f4c7dee Mon Sep 17 00:00:00 2001 From: TTtie Date: Wed, 19 Jul 2023 00:58:37 +0200 Subject: [PATCH 14/22] types(Client): make `editChannelOptions()` channel position optional (#89) Ref: https://github.com/discord/discord-api-docs/commit/a50bf9ba22b5f493a242d748c0e9f51f726bfa17 --- index.d.ts | 2 +- lib/Client.js | 2 +- lib/structures/Guild.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 14a2132d..bd3f3035 100644 --- a/index.d.ts +++ b/index.d.ts @@ -359,7 +359,7 @@ declare namespace Dysnomia { } interface ChannelPosition { id: string; - position: number; + position?: number; lockPermissions?: boolean; parentID?: string; } diff --git a/lib/Client.js b/lib/Client.js index 3f4ae902..98743ff1 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -1381,7 +1381,7 @@ class Client extends EventEmitter { * @arg {String} guildID The ID of the guild * @arg {Array} channelPositions An array of [ChannelPosition](https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions) * @arg {String} channelPositions[].id The ID of the channel - * @arg {Number} channelPositions[].position The new position of the channel + * @arg {Number} [channelPositions[].position] The new position of the channel * @arg {Boolean} [channelPositions[].lockPermissions] Whether to sync the channel's permissions with the new parent, if changing parents * @arg {String} [channelPositions[].parentID] The new parent ID (category channel) for the channel that is moved. For each request, only one channel can change parents * @returns {Promise} diff --git a/lib/structures/Guild.js b/lib/structures/Guild.js index f7e2527e..a6e9a93f 100644 --- a/lib/structures/Guild.js +++ b/lib/structures/Guild.js @@ -705,7 +705,7 @@ class Guild extends Base { * Edit multiple channels' positions. Note that channel position numbers are grouped by type (category, text, voice), then sorted in ascending order (lowest number is on top). * @arg {Array} channelPositions An array of [ChannelPosition](https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions) * @arg {String} channelPositions[].id The ID of the channel - * @arg {Number} channelPositions[].position The new position of the channel + * @arg {Number} [channelPositions[].position] The new position of the channel * @arg {Boolean} [channelPositions[].lockPermissions] Whether to sync the channel's permissions with the new parent, if changing parents * @arg {String} [channelPositions[].parentID] The new parent ID (category channel) for the channel that is moved. For each request, only one channel can change parents * @returns {Promise} From 221d1cc254f899d7e5d23704ca4aaa110c0f9f99 Mon Sep 17 00:00:00 2001 From: TTtie Date: Wed, 19 Jul 2023 01:08:47 +0200 Subject: [PATCH 15/22] feat: support `message_author_id` on uncached `MESSAGE_REACTION_ADD` payloads (#87) Ref: https://github.com/discord/discord-api-docs/commit/095e858ee3838ebf343d408c8a6b31ed96e878e4 Ref: https://github.com/discord/discord-api-docs/commit/26b95485354b4d583b35f6dd5b149d1ab0ff42ae --- index.d.ts | 2 +- lib/gateway/Shard.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index bd3f3035..15d2ddb3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -164,7 +164,7 @@ declare namespace Dysnomia { type MessageContent = string | AdvancedMessageContent; type MessageContentEdit = string | AdvancedMessageContent<"isMessageEdit">; type MFALevel = Constants["MFALevels"][keyof Constants["MFALevels"]]; - type PossiblyUncachedMessage = Message | { channel: TextableChannel | { id: string; guild?: Uncached }; guildID?: string; id: string }; + type PossiblyUncachedMessage = Message | { author?: User | Uncached; channel: TextableChannel | { id: string; guild?: Uncached }; guildID?: string; id: string }; type SelectMenu = BaseSelectMenu | ChannelSelectMenu | StringSelectMenu; type SelectMenuTypes = Constants["ComponentTypes"][keyof Pick]; type SelectMenuExtendedTypes = Constants["ComponentTypes"][keyof Pick]; diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index cde46b2e..948c43e2 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -965,6 +965,10 @@ class Shard extends EventEmitter { channel: channel || {id: packet.d.channel_id} }; + if(packet.d.message_author_id) { + message.author = this.client.users.get(packet.d.message_author_id) ?? {id: packet.d.message_author_id}; + } + if(packet.d.guild_id) { message.guildID = packet.d.guild_id; if(!message.channel.guild) { @@ -975,7 +979,7 @@ class Shard extends EventEmitter { /** * Fired when someone adds a reaction to a message * @event Client#messageReactionAdd - * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id`, `channel`, and if inside a guild, `guildID` keys. If the channel is not cached, channel key will be an object with only an id. `guildID` will be present if the message was sent in a guild channel. No other property is guaranteed + * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id`, `channel`, `author` (if present in the payload), and if inside a guild, `guildID` keys. If the channel is not cached, channel key will be an object with only an id. If the author is not cached, the author key will be an object with only an ID. `guildID` will be present if the message was sent in a guild channel. No other property is guaranteed * @prop {Object} emoji The reaction emoji object * @prop {Boolean?} emoji.animated Whether the emoji is animated or not * @prop {String?} emoji.id The emoji ID (null for non-custom emojis) From 6b2c3bff66162febf6a51ce22f701e85299c3170 Mon Sep 17 00:00:00 2001 From: TTtie Date: Fri, 28 Jul 2023 00:56:27 +0200 Subject: [PATCH 16/22] refactor: don't call update() multiple times in the prototype chain (#91) The update() method is already called in the base class - according to JS class semantics, when calling a constructor via `super`, `this` still points to the object at the top of the prototype chain, resulting in the update() method being called twice or more down the prototype chain as the super-classes initialize. --- lib/structures/CategoryChannel.js | 1 - lib/structures/ExtendedUser.js | 1 - lib/structures/ForumChannel.js | 1 - lib/structures/NewsChannel.js | 1 - lib/structures/PrivateThreadChannel.js | 1 - lib/structures/PublicThreadChannel.js | 1 - lib/structures/TextChannel.js | 1 - lib/structures/TextVoiceChannel.js | 1 - lib/structures/ThreadChannel.js | 1 - lib/structures/VoiceChannel.js | 1 - 10 files changed, 10 deletions(-) diff --git a/lib/structures/CategoryChannel.js b/lib/structures/CategoryChannel.js index 928974fb..b6f6c53d 100644 --- a/lib/structures/CategoryChannel.js +++ b/lib/structures/CategoryChannel.js @@ -14,7 +14,6 @@ const PermissionOverwrite = require("./PermissionOverwrite"); class CategoryChannel extends GuildChannel { constructor(data, client) { super(data, client); - this.update(data); } update(data) { diff --git a/lib/structures/ExtendedUser.js b/lib/structures/ExtendedUser.js index c1a0769d..5f79d65f 100644 --- a/lib/structures/ExtendedUser.js +++ b/lib/structures/ExtendedUser.js @@ -13,7 +13,6 @@ const User = require("./User"); class ExtendedUser extends User { constructor(data, client) { super(data, client); - this.update(data); } update(data) { diff --git a/lib/structures/ForumChannel.js b/lib/structures/ForumChannel.js index 2cdc987b..18017d97 100644 --- a/lib/structures/ForumChannel.js +++ b/lib/structures/ForumChannel.js @@ -27,7 +27,6 @@ class ForumChannel extends GuildChannel { this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user == null ? null : data.default_thread_rate_limit_per_user; this.lastThreadID = data.last_message_id || null; this.rateLimitPerUser = data.rate_limit_per_user == null ? null : data.rate_limit_per_user; - this.update(data); } update(data) { diff --git a/lib/structures/NewsChannel.js b/lib/structures/NewsChannel.js index c9deea28..f84c6336 100644 --- a/lib/structures/NewsChannel.js +++ b/lib/structures/NewsChannel.js @@ -10,7 +10,6 @@ class NewsChannel extends TextChannel { constructor(data, guild, messageLimit) { super(data, guild, messageLimit); this.rateLimitPerUser = 0; - this.update(data); } /** diff --git a/lib/structures/PrivateThreadChannel.js b/lib/structures/PrivateThreadChannel.js index fe181f81..14c4d9a8 100644 --- a/lib/structures/PrivateThreadChannel.js +++ b/lib/structures/PrivateThreadChannel.js @@ -15,7 +15,6 @@ const ThreadChannel = require("./ThreadChannel"); class PrivateThreadChannel extends ThreadChannel { constructor(data, client, messageLimit) { super(data, client, messageLimit); - this.update(data); } update(data) { diff --git a/lib/structures/PublicThreadChannel.js b/lib/structures/PublicThreadChannel.js index 2932f7a5..dc13490d 100644 --- a/lib/structures/PublicThreadChannel.js +++ b/lib/structures/PublicThreadChannel.js @@ -10,7 +10,6 @@ const ThreadChannel = require("./ThreadChannel"); class PublicThreadChannel extends ThreadChannel { constructor(data, client, messageLimit) { super(data, client, messageLimit); - this.update(data); } update(data) { diff --git a/lib/structures/TextChannel.js b/lib/structures/TextChannel.js index f313a4fd..074e7892 100644 --- a/lib/structures/TextChannel.js +++ b/lib/structures/TextChannel.js @@ -25,7 +25,6 @@ class TextChannel extends GuildChannel { this.lastMessageID = data.last_message_id || null; this.rateLimitPerUser = data.rate_limit_per_user == null ? null : data.rate_limit_per_user; this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null; - this.update(data); } update(data) { diff --git a/lib/structures/TextVoiceChannel.js b/lib/structures/TextVoiceChannel.js index 7db496c6..545ab51d 100644 --- a/lib/structures/TextVoiceChannel.js +++ b/lib/structures/TextVoiceChannel.js @@ -20,7 +20,6 @@ class TextVoiceChannel extends VoiceChannel { this.messages = new Collection(Message, messageLimit == null ? client.options.messageLimit : messageLimit); this.nsfw = data.nsfw; this.lastMessageID = data.last_message_id || null; - this.update(data); } update(data) { diff --git a/lib/structures/ThreadChannel.js b/lib/structures/ThreadChannel.js index c500641f..bc9f32c8 100644 --- a/lib/structures/ThreadChannel.js +++ b/lib/structures/ThreadChannel.js @@ -34,7 +34,6 @@ class ThreadChannel extends GuildChannel { this.members = new Collection(ThreadMember); this.lastMessageID = data.last_message_id || null; this.ownerID = data.owner_id; - this.update(data); } update(data) { diff --git a/lib/structures/VoiceChannel.js b/lib/structures/VoiceChannel.js index e50cdf9c..5b2edca7 100644 --- a/lib/structures/VoiceChannel.js +++ b/lib/structures/VoiceChannel.js @@ -18,7 +18,6 @@ class VoiceChannel extends GuildChannel { constructor(data, client) { super(data, client); this.voiceMembers = new Collection(Member); - this.update(data); } update(data) { From 51c806493ff831ce6e0a7851a0bbaecfdb02532e Mon Sep 17 00:00:00 2001 From: TTtie Date: Sun, 30 Jul 2023 21:54:52 +0200 Subject: [PATCH 17/22] fix(types): allow attachment command options in createCommand() and co. (#92) --- index.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 15d2ddb3..ca8b4b57 100644 --- a/index.d.ts +++ b/index.d.ts @@ -29,6 +29,7 @@ declare namespace Dysnomia { type ApplicationCommandOptionMinMaxValue = (ApplicationCommandOption & ApplicationCommandOptionsMinMaxValue); type ApplicationCommandOptionMinMaxLength = (ApplicationCommandOption & ApplicationCommandOptionsMinMaxLength); + type ApplicationCommandOptionsAttachment = ApplicationCommandOption<"ATTACHMENT">; type ApplicationCommandOptionsBoolean = ApplicationCommandOption<"BOOLEAN">; type ApplicationCommandOptionsChannel = ApplicationCommandOptionChannelTypes<"CHANNEL">; type ApplicationCommandOptionsInteger = ApplicationCommandOptionAutocomplete<"INTEGER"> | ApplicationCommandOptionChoices<"INTEGER"> | ApplicationCommandOptionMinMaxValue<"INTEGER">; @@ -39,7 +40,7 @@ declare namespace Dysnomia { type ApplicationCommandOptionsUser = ApplicationCommandOption<"USER">; type ApplicationCommandOptionsWithOptions = ApplicationCommandOptionsSubCommand | ApplicationCommandOptionsSubCommandGroup; - type ApplicationCommandOptionsWithValue = ApplicationCommandOptionsString | ApplicationCommandOptionsInteger | ApplicationCommandOptionsBoolean | ApplicationCommandOptionsUser | ApplicationCommandOptionsChannel | ApplicationCommandOptionsRole | ApplicationCommandOptionsMentionable | ApplicationCommandOptionsNumber; + type ApplicationCommandOptionsWithValue = ApplicationCommandOptionsString | ApplicationCommandOptionsInteger | ApplicationCommandOptionsBoolean | ApplicationCommandOptionsUser | ApplicationCommandOptionsChannel | ApplicationCommandOptionsRole | ApplicationCommandOptionsMentionable | ApplicationCommandOptionsNumber | ApplicationCommandOptionsAttachment; type ApplicationCommandStructure = ChatInputApplicationCommandStructure | MessageApplicationCommandStructure | UserApplicationCommandStructure; type ApplicationCommandStructureConversion = T extends ChatInputApplicationCommandStructure ? ChatInputApplicationCommand : T extends MessageApplicationCommandStructure ? From 8f2fe05f8c8e506fbb4e3bd2bf4285a89361b3b6 Mon Sep 17 00:00:00 2001 From: TTtie Date: Sun, 30 Jul 2023 22:18:33 +0200 Subject: [PATCH 18/22] feat: add `Client#getApplication()` (#90) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the time being, we're preserving both methods – the /applications/@me route still doesn't have information about the team associated with the application unlike the /oauth2/applications/@me route. --- index.d.ts | 7 +++++++ lib/Client.js | 13 +++++++++++-- lib/rest/Endpoints.js | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index ca8b4b57..75bdfae9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1829,6 +1829,7 @@ declare namespace Dysnomia { [key: string]: unknown; } interface OAuthApplicationInfo { + approximate_guild_count?: number; bot_public: boolean; bot_require_code_grant: boolean; cover_image?: string; @@ -1836,6 +1837,11 @@ declare namespace Dysnomia { description: string; flags?: number; guild_id?: string; + // The docs say that there can be a partial guild object attached, + // but as of 2023-07-25, there is no guild object attached in either + // endpoints, so we cannot determine how partial the guild object really is. + // Proceed with caution. + guild?: unknown; icon: string | null; id: string; install_params?: OAuthInstallParams; @@ -2832,6 +2838,7 @@ declare namespace Dysnomia { executeWebhook(webhookID: string, token: string, options: WebhookPayload): Promise; followChannel(channelID: string, webhookChannelID: string): Promise; getActiveGuildThreads(guildID: string): Promise; + getApplication(): Promise; getArchivedThreads(channelID: string, type: "private", options?: GetArchivedThreadsOptions): Promise>; getArchivedThreads(channelID: string, type: "public", options?: GetArchivedThreadsOptions): Promise>; getAutoModerationRule(guildID: string, ruleID: string): Promise; diff --git a/lib/Client.js b/lib/Client.js index 98743ff1..7d9f4260 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -2123,6 +2123,15 @@ class Client extends EventEmitter { }); } + /** + * Get data on the application associated with this bot account. + * The returned data is similar to the `getOAuthApplication()` method with additional information. + * @returns {Promise} The bot's application data. Refer to [Discord's Documentation](https://discord.com/developers/docs/resources/application#application-object) for object structure + */ + getApplication() { + return this.requestHandler.request("GET", Endpoints.APPLICATION, true); + } + /** * Get all archived threads in a channel * @arg {String} channelID The ID of the channel @@ -2682,8 +2691,8 @@ class Client extends EventEmitter { } /** - * Get data on the bot's OAuth2 application - * @returns {Promise} The bot's application data. Refer to [Discord's Documentation](https://discord.com/developers/docs/topics/oauth2#get-current-application-information) for object structure + * Get data on the bot's OAuth2 application. See also `getApplication()` for more info. + * @returns {Promise} The bot's application data. Refer to [Discord's Documentation](https://discord.com/developers/docs/resources/application#application-object) for object structure */ getOAuthApplication() { return this.requestHandler.request("GET", Endpoints.OAUTH2_APPLICATION, true); diff --git a/lib/rest/Endpoints.js b/lib/rest/Endpoints.js index c0ffc6b8..b1af3fcb 100644 --- a/lib/rest/Endpoints.js +++ b/lib/rest/Endpoints.js @@ -6,6 +6,7 @@ module.exports.BASE_URL = "/api/v" + REST_VERSION; module.exports.CDN_URL = "https://cdn.discordapp.com"; module.exports.CLIENT_URL = "https://discord.com"; +module.exports.APPLICATION = "/applications/@me"; module.exports.AUTO_MODERATION_RULES = (guildID) => `/guilds/${guildID}/auto-moderation/rules`; module.exports.AUTO_MODERATION_RULE = (guildID, ruleID) => `/guilds/${guildID}/auto-moderation/rules/${ruleID}`; module.exports.ORIGINAL_INTERACTION_RESPONSE = (appID, interactToken) => `/webhooks/${appID}/${interactToken}`; From cce0a38a1fe066cc45d90655856502ef1e1c754c Mon Sep 17 00:00:00 2001 From: Mert <41897689+MertBhey@users.noreply.github.com> Date: Thu, 3 Aug 2023 16:34:50 +0300 Subject: [PATCH 19/22] fix(types): add ModalSubmitInteraction to AnyInteractionGateway (#97) --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 75bdfae9..81ff2cc8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -130,7 +130,7 @@ declare namespace Dysnomia { // Interaction type AnyInteraction = AnyInteractionGateway | PingInteraction; - type AnyInteractionGateway = AutocompleteInteraction | CommandInteraction | ComponentInteraction; + type AnyInteractionGateway = AutocompleteInteraction | CommandInteraction | ComponentInteraction | ModalSubmitInteraction; type InteractionContent = Pick; type InteractionContentEdit = Omit; type InteractionDataOption, V = boolean | number | string> = InteractionDataOptionsBase; From e108cc77cefe421942f037abefdf80a99748c53b Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 3 Aug 2023 13:43:56 +0000 Subject: [PATCH 20/22] types: correct gateway/REST versions in Constants interface (#98) --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 81ff2cc8..045962fd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1877,8 +1877,8 @@ declare namespace Dysnomia { permissions: string; } interface Constants { - GATEWAY_VERSION: 9; - REST_VERSION: 9; + GATEWAY_VERSION: 10; + REST_VERSION: 10; ActivityFlags: { INSTANCE: 1; JOIN: 2; From 6d19a676c44e542324558a942199d117915abd50 Mon Sep 17 00:00:00 2001 From: TTtie Date: Tue, 8 Aug 2023 17:28:27 +0000 Subject: [PATCH 21/22] fix(Attachment): include `flags` in toJSON() output (#99) --- lib/structures/Attachment.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/structures/Attachment.js b/lib/structures/Attachment.js index 61cf633b..bdf18b64 100644 --- a/lib/structures/Attachment.js +++ b/lib/structures/Attachment.js @@ -65,6 +65,7 @@ class Attachment extends Base { "ephemeral", "durationSecs", "waveform", + "flags", ...props ]); } From 1a1384c893876aab7a525f544f6f880d1b9d3047 Mon Sep 17 00:00:00 2001 From: TTtie Date: Tue, 8 Aug 2023 18:36:27 +0000 Subject: [PATCH 22/22] feat: support GUILD_MEDIA channels (#96) * feat: support GUILD_MEDIA channels Ref: https://github.com/discord/discord-api-docs/commit/107de2df26c3030e2b3f06c547a56ac96934f4e7 * correct the word order * add MediaChannel to package exports * consistency - extract ForumChannel type into a type alias * add missing intellisense hints to createChannel --- esm.mjs | 1 + index.d.ts | 31 ++++++++++++++++++++++----- index.js | 1 + lib/Client.js | 6 +++--- lib/Constants.js | 8 ++++--- lib/gateway/Shard.js | 5 +++-- lib/structures/Channel.js | 4 ++++ lib/structures/ForumChannel.js | 2 +- lib/structures/GuildChannel.js | 2 +- lib/structures/MediaChannel.js | 11 ++++++++++ lib/structures/PublicThreadChannel.js | 2 +- 11 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 lib/structures/MediaChannel.js diff --git a/esm.mjs b/esm.mjs index cf34a4be..697669a6 100644 --- a/esm.mjs +++ b/esm.mjs @@ -35,6 +35,7 @@ export const { GuildTemplate, Interaction, Invite, + MediaChannel, Member, Message, ModalSubmitInteraction, diff --git a/index.d.ts b/index.d.ts index 045962fd..9dc0db4c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -84,6 +84,7 @@ declare namespace Dysnomia { type TextChannelTypes = GuildTextChannelTypes | PrivateChannelTypes; type GuildTextChannelTypes = Constants["ChannelTypes"][keyof Pick]; type GuildThreadChannelTypes = Constants["ChannelTypes"][keyof Pick]; + type GuildThreadOnlyChannelTypes = Constants["ChannelTypes"][keyof Pick]; type GuildPublicThreadChannelTypes = Exclude; type GuildVoiceChannelTypes = Constants["ChannelTypes"][keyof Pick]; type PrivateChannelTypes = Constants["ChannelTypes"][keyof Pick]; @@ -2073,10 +2074,12 @@ declare namespace Dysnomia { GUILD_STAGE_VOICE: 13; GUILD_DIRECTORY: 14; GUILD_FORUM: 15; + GUILD_MEDIA: 16; }; ChannelFlags: { - PINNED: 2; - REQUIRE_TAG: 16; + PINNED: 2; + REQUIRE_TAG: 16; + HIDE_MEDIA_DOWNLOAD_OPTIONS: 32768; }; ComponentTypes: { ACTION_ROW: 1; @@ -2714,6 +2717,18 @@ declare namespace Dysnomia { type: Constants["ChannelTypes"]["GUILD_STAGE_VOICE"], options?: CreateChannelOptions ): Promise; + createChannel( + guildID: string, + name: string, + type: Constants["ChannelTypes"]["GUILD_FORUM"], + options?: CreateChannelOptions + ): Promise; + createChannel( + guildID: string, + name: string, + type: Constants["ChannelTypes"]["GUILD_MEDIA"], + options?: CreateChannelOptions + ): Promise; createChannel( guildID: string, name: string, @@ -3116,7 +3131,7 @@ declare namespace Dysnomia { permissionOverwrites: Collection; rateLimitPerUser: number; topic?: string | null; - type: Constants["ChannelTypes"]["GUILD_FORUM"]; + type: GuildThreadOnlyChannelTypes; createInvite(options?: CreateInviteOptions, reason?: string): Promise>; createThread(options: CreateThreadWithoutMessageOptions): Promise; createWebhook(options: Omit, reason?: string): Promise; @@ -3193,8 +3208,10 @@ declare namespace Dysnomia { createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_TEXT"], options?: CreateChannelOptions): Promise; createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_VOICE"], options?: CreateChannelOptions): Promise; createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_CATEGORY"], options?: CreateChannelOptions): Promise; - createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_ANNOUNCEMENT"], options?: CreateChannelOptions | string): Promise; - createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_STAGE_VOICE"], options?: CreateChannelOptions | string): Promise; + createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_ANNOUNCEMENT"], options?: CreateChannelOptions): Promise; + createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_STAGE_VOICE"], options?: CreateChannelOptions): Promise; + createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_FORUM"], options: CreateChannelOptions): Promise; + createChannel(name: string, type: Constants["ChannelTypes"]["GUILD_MEDIA"], options: CreateChannelOptions): Promise; createChannel(name: string, type?: number, options?: CreateChannelOptions): Promise; createCommand(command: T): Promise>; createEmoji(options: { image: string; name: string; roles?: string[] }, reason?: string): Promise; @@ -3515,6 +3532,10 @@ declare namespace Dysnomia { unban(reason?: string): Promise; } + export class MediaChannel extends ForumChannel { + type: Constants["ChannelTypes"]["GUILD_MEDIA"]; + } + export class Message extends Base { activity?: MessageActivity; application?: MessageApplication; diff --git a/index.js b/index.js index 75b00bbd..a19e8c82 100644 --- a/index.js +++ b/index.js @@ -36,6 +36,7 @@ Dysnomia.GuildScheduledEvent = require("./lib/structures/GuildScheduledEvent"); Dysnomia.GuildTemplate = require("./lib/structures/GuildTemplate"); Dysnomia.Interaction = require("./lib/structures/Interaction"); Dysnomia.Invite = require("./lib/structures/Invite"); +Dysnomia.MediaChannel = require("./lib/structures/MediaChannel"); Dysnomia.Member = require("./lib/structures/Member"); Dysnomia.Message = require("./lib/structures/Message"); Dysnomia.ModalSubmitInteraction = require("./lib/structures/ModalSubmitInteraction.js"); diff --git a/lib/Client.js b/lib/Client.js index 7d9f4260..6f6c2dab 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -865,9 +865,9 @@ class Client extends EventEmitter { * @arg {String} channelID The ID of the channel * @arg {Object} options The thread options * @arg {Number} [options.autoArchiveDuration] Duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080 - * @arg {Array} [options.appliedTags] The tags to apply to the thread (available only for threads created in a `GUILD_FORUM` channel) + * @arg {Array} [options.appliedTags] The tags to apply to the thread (available only in threads in thread-only channels) * @arg {Boolean} [options.invitable] Whether non-moderators can add other non-moderators to the thread (private threads only) - * @arg {Object} [options.message] The message to attach to the thread (set only if creating a thread in a `GUILD_FORUM` channel) + * @arg {Object} [options.message] The message to attach to the thread (set only if creating a thread in a thread-only channel) * @arg {Object} [options.message.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [options.message.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [options.message.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. @@ -1250,7 +1250,7 @@ class Client extends EventEmitter { * @arg {String} channelID The ID of the channel * @arg {Object} options The properties to edit * @arg {Boolean} [options.archived] The archive status of the channel (thread channels only) - * @arg {Array} [options.appliedTags] An array of applied tag IDs for the thread (available in `GUILD_FORUM` threads only) + * @arg {Array} [options.appliedTags] An array of applied tag IDs for the thread (available only in threads in thread-only channels) * @arg {Number} [options.autoArchiveDuration] The duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080 (thread channels only) * @arg {Array} [options.availableTags] Available tags for a forum channel * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) diff --git a/lib/Constants.js b/lib/Constants.js index 1c820b45..1f25d1d2 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -185,8 +185,9 @@ module.exports.ButtonStyles = { }; module.exports.ChannelFlags = { - PINNED: 1 << 1, - REQUIRE_TAG: 1 << 4 + PINNED: 1 << 1, + REQUIRE_TAG: 1 << 4, + HIDE_MEDIA_DOWNLOAD_OPTIONS: 1 << 15 }; module.exports.ChannelTypes = { @@ -202,7 +203,8 @@ module.exports.ChannelTypes = { PRIVATE_THREAD: 12, GUILD_PRIVATE_THREAD: 12, // [DEPRECATED] GUILD_STAGE_VOICE: 13, GUILD_DIRECTORY: 14, - GUILD_FORUM: 15 + GUILD_FORUM: 15, + GUILD_MEDIA: 16 }; module.exports.ComponentTypes = { diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 948c43e2..0766f6f4 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -19,6 +19,7 @@ const GuildScheduledEvent = require("../structures/GuildScheduledEvent"); const GuildAuditLogEntry = require("../structures/GuildAuditLogEntry"); const AutoModerationRule = require("../structures/AutoModerationRule"); const GuildIntegration = require("../structures/GuildIntegration"); +const ForumChannel = require("../structures/ForumChannel"); const WebSocket = typeof window !== "undefined" ? require("../util/BrowserWebSocket") : require("ws"); @@ -1860,7 +1861,7 @@ class Shard extends EventEmitter { } } const parent = this.client.getChannel(packet.d.parent_id); - if(parent && parent.type === ChannelTypes.GUILD_FORUM) { + if(parent instanceof ForumChannel) { parent.lastThreadID = packet.d.id; } @@ -1900,7 +1901,7 @@ class Shard extends EventEmitter { * @event Client#threadUpdate * @prop {NewsThreadChannel | PrivateThreadChannel | PublicThreadChannel} channel The updated channel * @prop {Object?} oldChannel The old thread channel. This will be null if the channel was uncached - * @prop {Array?} oldChannel.appliedTags An array of applied tag IDs for the thread (available in `GUILD_FORUM` threads only) + * @prop {Array?} oldChannel.appliedTags An array of applied tag IDs for the thread (available only in threads in thread-only channels) * @prop {Number?} oldChannel.flags The flags of the channel * @prop {String} oldChannel.name The name of the channel * @prop {Number} oldChannel.rateLimitPerUser The ratelimit of the channel, in seconds. 0 means no ratelimit is enabled diff --git a/lib/structures/Channel.js b/lib/structures/Channel.js index cccd73de..276ba54c 100644 --- a/lib/structures/Channel.js +++ b/lib/structures/Channel.js @@ -54,6 +54,9 @@ class Channel extends Base { case ChannelTypes.GUILD_FORUM: { return new ForumChannel(data, client); } + case ChannelTypes.GUILD_MEDIA: { + return new MediaChannel(data, client); + } } if(data.guild_id) { if(data.last_message_id !== undefined) { @@ -81,6 +84,7 @@ module.exports = Channel; const CategoryChannel = require("./CategoryChannel"); const ForumChannel = require("./ForumChannel"); const GuildChannel = require("./GuildChannel"); +const MediaChannel = require("./MediaChannel"); const NewsChannel = require("./NewsChannel"); const NewsThreadChannel = require("./NewsThreadChannel"); const PrivateChannel = require("./PrivateChannel"); diff --git a/lib/structures/ForumChannel.js b/lib/structures/ForumChannel.js index 18017d97..b0152e51 100644 --- a/lib/structures/ForumChannel.js +++ b/lib/structures/ForumChannel.js @@ -98,7 +98,7 @@ class ForumChannel extends GuildChannel { * @arg {Number} [options.autoArchiveDuration] Duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080 * @arg {Array} [options.appliedTags] The tags to apply to the thread * @arg {String} options.name The thread channel name - * @arg {Object} options.message The message to attach to the thread (set only if creating a thread in a `GUILD_FORUM` channel) + * @arg {Object} options.message The message to attach to the thread (set only if creating a thread in a thread-only channel) * @arg {Object} [options.message.allowedMentions] A list of mentions to allow (overrides default) * @arg {Boolean} [options.message.allowedMentions.everyone] Whether or not to allow @everyone/@here. * @arg {Boolean | Array} [options.message.allowedMentions.roles] Whether or not to allow all role mentions, or an array of specific role mentions to allow. diff --git a/lib/structures/GuildChannel.js b/lib/structures/GuildChannel.js index f02570eb..31f562ef 100644 --- a/lib/structures/GuildChannel.js +++ b/lib/structures/GuildChannel.js @@ -66,7 +66,7 @@ class GuildChannel extends Channel { * Edit the channel's properties * @arg {Object} options The properties to edit * @arg {Boolean} [options.archived] The archive status of the channel (thread channels only) - * @arg {Array} [options.appliedTags] An array of applied tag IDs for the thread (available in `GUILD_FORUM` threads only) + * @arg {Array} [options.appliedTags] An array of applied tag IDs for the thread (available only in threads in thread-only channels) * @arg {Number} [options.autoArchiveDuration] The duration in minutes to automatically archive the thread after recent activity, either 60, 1440, 4320 or 10080 (thread channels only) * @arg {Array} [options.availableTags] Available tags for a forum channel * @arg {Number} [options.bitrate] The bitrate of the channel (guild voice channels only) diff --git a/lib/structures/MediaChannel.js b/lib/structures/MediaChannel.js new file mode 100644 index 00000000..c792e832 --- /dev/null +++ b/lib/structures/MediaChannel.js @@ -0,0 +1,11 @@ +"use strict"; + +const ForumChannel = require("./ForumChannel"); + +/** + * Represents a media channel. See ForumChannel for available properties and methods. + * @extends ForumChannel + */ +class MediaChannel extends ForumChannel {} + +module.exports = MediaChannel; diff --git a/lib/structures/PublicThreadChannel.js b/lib/structures/PublicThreadChannel.js index dc13490d..16388100 100644 --- a/lib/structures/PublicThreadChannel.js +++ b/lib/structures/PublicThreadChannel.js @@ -5,7 +5,7 @@ const ThreadChannel = require("./ThreadChannel"); /** * Represents a public thread channel. See ThreadChannel for extra properties. * @extends ThreadChannel -* @prop {Array} appliedTags An array of applied tag IDs for the thread (available in `GUILD_FORUM` threads only) +* @prop {Array} appliedTags An array of applied tag IDs for the thread (available only in threads in thread-only channels) */ class PublicThreadChannel extends ThreadChannel { constructor(data, client, messageLimit) {